From cc04e594c9152eb971dc7ee3f02a1d09e84a542f Mon Sep 17 00:00:00 2001 From: Hasit Mistry Date: Wed, 16 Jul 2025 01:03:21 -0700 Subject: [PATCH 1/2] Enhance gitlab-webhook.sh: add verbose option and improve error handling --- static/code/gitlab-webhook.sh | 143 ++++++++++++++++++++++++++++++---- 1 file changed, 126 insertions(+), 17 deletions(-) mode change 100644 => 100755 static/code/gitlab-webhook.sh diff --git a/static/code/gitlab-webhook.sh b/static/code/gitlab-webhook.sh old mode 100644 new mode 100755 index 1458ba0d..ab90c2fb --- a/static/code/gitlab-webhook.sh +++ b/static/code/gitlab-webhook.sh @@ -34,7 +34,7 @@ usage() { cat < -u -s \\ - [-t ] [-A ] [-p | -g ] + [-t ] [-A ] [-p | -g ] [-v] Required: -h GitLab host (e.g. gitlab.example.com) @@ -50,15 +50,18 @@ Authentication (one of): Scope (choose one): -p Project ID or full path (e.g. 42 or group/app) -g Group ID or full path, recurse through all subgroups & projects + +Options: + -v Verbose output (show individual project IDs in final summary) EOF exit 1 } HOST="" HOOK_URL="" HOOK_SECRET="" TOKEN="${GITLAB_TOKEN:-}" AUTH_HEADER="" -PROJECT="" GROUP="" +PROJECT="" GROUP="" VERBOSE=false -while getopts "h:u:s:t:A:p:g:" opt; do +while getopts "h:u:s:t:A:p:g:v" opt; do case "$opt" in h) HOST=$OPTARG ;; u) HOOK_URL=$OPTARG ;; @@ -67,6 +70,7 @@ while getopts "h:u:s:t:A:p:g:" opt; do A) AUTH_HEADER=$OPTARG ;; p) PROJECT=$OPTARG ;; g) GROUP=$OPTARG ;; + v) VERBOSE=true ;; *) usage ;; esac done @@ -78,7 +82,7 @@ done # Token handling if [[ -z $TOKEN ]]; then - echo "❌ No access token provided. Use -t or set \$GITLAB_TOKEN" >&2 + echo "[ERROR] No access token provided. Use -t or set \$GITLAB_TOKEN" >&2 exit 1 fi @@ -98,6 +102,11 @@ CURL_BASE=(curl -sSf --header "${AUTH_HEADER}: ${TOKEN}") declare -A PROCESSED_PROJECTS # Track projects where webhooks were successfully added WEBHOOK_PROJECTS=() +# Track projects where webhooks already existed +EXISTING_WEBHOOK_PROJECTS=() +# Progress counters +TOTAL_PROJECTS_FOUND=0 +PROJECTS_PROCESSED=0 ############################################################################## # Helpers @@ -108,6 +117,63 @@ url_encode() { printf '%s' "$string" | sed 's/\//%2F/g; s/ /%20/g; s/@/%40/g; s/:/%3A/g; s/#/%23/g; s/?/%3F/g; s/&/%26/g; s/=/%3D/g; s/+/%2B/g' } +# Function to handle paginated API calls +fetch_paginated() { + local url=$1 + local page=1 + local per_page=100 + + while true; do + local paginated_url="${url}?per_page=${per_page}&page=${page}" + + # Add existing query params if they exist + if [[ "$url" == *"?"* ]]; then + paginated_url="${url}&per_page=${per_page}&page=${page}" + fi + + local response + response=$("${CURL_BASE[@]}" "$paginated_url" 2>/dev/null) || { + echo "[ERROR] Failed to fetch page $page from $url" >&2 + return 1 + } + + # Check if response is empty array or null + if [[ "$response" == "[]" || "$response" == "null" ]]; then + break + fi + + # Extract results from current page + local page_results + page_results=$(echo "$response" | jq -r '.[].id' 2>/dev/null) || { + echo "[ERROR] Failed to parse JSON response from page $page" >&2 + return 1 + } + + # If no results on this page, we're done + if [[ -z "$page_results" ]]; then + break + fi + + # Count projects found and show progress + local page_count + page_count=$(echo "$page_results" | wc -l) + TOTAL_PROJECTS_FOUND=$((TOTAL_PROJECTS_FOUND + page_count)) + echo "[PROGRESS] Found $page_count projects on page $page (total: $TOTAL_PROJECTS_FOUND)" >&2 + + # Output page results + echo "$page_results" + + # If we got less than per_page results, we're on the last page + local item_count + item_count=$(echo "$response" | jq '. | length' 2>/dev/null) || 0 + if [[ "$item_count" -lt "$per_page" ]]; then + break + fi + + ((page++)) + done +} + create_hook() { local pid=$1 @@ -118,6 +184,7 @@ create_hook() { # Mark as processed PROCESSED_PROJECTS[$pid]=1 + PROJECTS_PROCESSED=$((PROJECTS_PROCESSED + 1)) local encoded_pid # URL encode if pid is not purely numeric @@ -127,6 +194,22 @@ create_hook() { encoded_pid=$(url_encode "$pid") fi + # Check if webhook already exists + local existing_webhooks + existing_webhooks=$("${CURL_BASE[@]}" "${API}/projects/${encoded_pid}/hooks" 2>/dev/null) || { + echo "[ERROR] Failed to fetch existing webhooks for project $pid" >&2 + return 1 + } + + # Check if our webhook URL already exists + if echo "$existing_webhooks" | jq -e --arg url "$HOOK_URL" '.[] | select(.url == $url)' >/dev/null 2>&1; then + [[ "$VERBOSE" == "true" ]] && echo "[INFO] Webhook already exists for project: $pid" >&2 + EXISTING_WEBHOOK_PROJECTS+=("$pid") + return 0 + fi + + [[ "$VERBOSE" == "true" ]] && echo "[INFO] Adding webhook to project: $pid" >&2 + "${CURL_BASE[@]}" --request POST \ --data-urlencode "url=${HOOK_URL}" \ --data "token=${HOOK_SECRET}" \ @@ -151,38 +234,64 @@ traverse_group() { else encoded_gid=$(url_encode "$gid") fi - # projects (includes nested sub-groups) + + # projects (includes nested sub-groups) - with pagination while IFS= read -r pid; do [[ -n "$pid" ]] && create_hook "$pid" done < <( - "${CURL_BASE[@]}" \ - "${API}/groups/${encoded_gid}/projects?include_subgroups=true&per_page=100" | - jq -r '.[].id' + fetch_paginated "${API}/groups/${encoded_gid}/projects?include_subgroups=true" ) - # recurse explicit subgroups (older GitLab) + + # recurse explicit subgroups (older GitLab) - with pagination while IFS= read -r sg; do [[ -n "$sg" ]] && traverse_group "$sg" done < <( - "${CURL_BASE[@]}" "${API}/groups/${encoded_gid}/subgroups?per_page=100" | - jq -r '.[].id' + fetch_paginated "${API}/groups/${encoded_gid}/subgroups" ) } ############################################################################## # Main ############################################################################## +echo "[INFO] Starting webhook processing..." >&2 + if [[ -n $PROJECT ]]; then + echo "[INFO] Processing single project: $PROJECT" >&2 create_hook "$PROJECT" else + echo "[INFO] Processing group and subgroups: $GROUP" >&2 traverse_group "$GROUP" fi +echo "[INFO] Finished processing all projects" >&2 + # Print final summary -if [[ ${#WEBHOOK_PROJECTS[@]} -eq 0 ]]; then - echo "❌ No webhooks were installed." +total_projects=$((${#WEBHOOK_PROJECTS[@]} + ${#EXISTING_WEBHOOK_PROJECTS[@]})) + +if [[ $total_projects -eq 0 ]]; then + echo "[INFO] No projects were processed." else - echo "✅ Webhooks installed successfully on ${#WEBHOOK_PROJECTS[@]} project(s):" - for pid in "${WEBHOOK_PROJECTS[@]}"; do - echo " - Project ID: $pid" - done + if [[ ${#WEBHOOK_PROJECTS[@]} -gt 0 ]]; then + if [[ "$VERBOSE" == "true" ]]; then + echo "[INFO] Webhooks installed successfully on ${#WEBHOOK_PROJECTS[@]} project(s):" + for pid in "${WEBHOOK_PROJECTS[@]}"; do + echo " - Project ID: $pid" + done + else + echo "[INFO] Webhooks installed successfully on ${#WEBHOOK_PROJECTS[@]} project(s)" + fi + fi + + if [[ ${#EXISTING_WEBHOOK_PROJECTS[@]} -gt 0 ]]; then + if [[ "$VERBOSE" == "true" ]]; then + echo "[INFO] Webhooks already existed on ${#EXISTING_WEBHOOK_PROJECTS[@]} project(s):" + for pid in "${EXISTING_WEBHOOK_PROJECTS[@]}"; do + echo " - Project ID: $pid" + done + else + echo "[INFO] Webhooks already existed on ${#EXISTING_WEBHOOK_PROJECTS[@]} project(s)" + fi + fi + + echo "[INFO] Total projects processed: $total_projects" fi From ffee2df1c3a26b2ba7ab62b543e540ddcb437f5f Mon Sep 17 00:00:00 2001 From: Hasit Mistry Date: Wed, 16 Jul 2025 01:10:11 -0700 Subject: [PATCH 2/2] Fix log message formatting for no processed projects in gitlab-webhook.sh --- static/code/gitlab-webhook.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/code/gitlab-webhook.sh b/static/code/gitlab-webhook.sh index ab90c2fb..87c3be7d 100755 --- a/static/code/gitlab-webhook.sh +++ b/static/code/gitlab-webhook.sh @@ -269,7 +269,7 @@ echo "[INFO] Finished processing all projects" >&2 total_projects=$((${#WEBHOOK_PROJECTS[@]} + ${#EXISTING_WEBHOOK_PROJECTS[@]})) if [[ $total_projects -eq 0 ]]; then - echo "[INFO] No projects were processed." + echo "[INFO] No projects were processed" else if [[ ${#WEBHOOK_PROJECTS[@]} -gt 0 ]]; then if [[ "$VERBOSE" == "true" ]]; then pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy