Skip to content

Commit 8c835f9

Browse files
authored
Enhance gitlab-webhook.sh: add verbose option and improve error handling (#456)
* Enhance gitlab-webhook.sh: add verbose option and improve error handling * Fix log message formatting for no processed projects in gitlab-webhook.sh
1 parent 9423a79 commit 8c835f9

File tree

1 file changed

+126
-17
lines changed

1 file changed

+126
-17
lines changed

static/code/gitlab-webhook.sh

100644100755
Lines changed: 126 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ usage() {
3434
cat <<EOF
3535
Usage:
3636
$0 -h <gitlab-host> -u <webhook-url> -s <webhook-secret> \\
37-
[-t <access-token>] [-A <auth-header>] [-p <project> | -g <group>]
37+
[-t <access-token>] [-A <auth-header>] [-p <project> | -g <group>] [-v]
3838
3939
Required:
4040
-h GitLab host (e.g. gitlab.example.com)
@@ -50,15 +50,18 @@ Authentication (one of):
5050
Scope (choose one):
5151
-p Project ID or full path (e.g. 42 or group/app)
5252
-g Group ID or full path, recurse through all subgroups & projects
53+
54+
Options:
55+
-v Verbose output (show individual project IDs in final summary)
5356
EOF
5457
exit 1
5558
}
5659

5760
HOST="" HOOK_URL="" HOOK_SECRET=""
5861
TOKEN="${GITLAB_TOKEN:-}" AUTH_HEADER=""
59-
PROJECT="" GROUP=""
62+
PROJECT="" GROUP="" VERBOSE=false
6063

61-
while getopts "h:u:s:t:A:p:g:" opt; do
64+
while getopts "h:u:s:t:A:p:g:v" opt; do
6265
case "$opt" in
6366
h) HOST=$OPTARG ;;
6467
u) HOOK_URL=$OPTARG ;;
@@ -67,6 +70,7 @@ while getopts "h:u:s:t:A:p:g:" opt; do
6770
A) AUTH_HEADER=$OPTARG ;;
6871
p) PROJECT=$OPTARG ;;
6972
g) GROUP=$OPTARG ;;
73+
v) VERBOSE=true ;;
7074
*) usage ;;
7175
esac
7276
done
@@ -78,7 +82,7 @@ done
7882

7983
# Token handling
8084
if [[ -z $TOKEN ]]; then
81-
echo " No access token provided. Use -t or set \$GITLAB_TOKEN" >&2
85+
echo "[ERROR] No access token provided. Use -t or set \$GITLAB_TOKEN" >&2
8286
exit 1
8387
fi
8488

@@ -98,6 +102,11 @@ CURL_BASE=(curl -sSf --header "${AUTH_HEADER}: ${TOKEN}")
98102
declare -A PROCESSED_PROJECTS
99103
# Track projects where webhooks were successfully added
100104
WEBHOOK_PROJECTS=()
105+
# Track projects where webhooks already existed
106+
EXISTING_WEBHOOK_PROJECTS=()
107+
# Progress counters
108+
TOTAL_PROJECTS_FOUND=0
109+
PROJECTS_PROCESSED=0
101110

102111
##############################################################################
103112
# Helpers
@@ -108,6 +117,63 @@ url_encode() {
108117
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'
109118
}
110119

120+
# Function to handle paginated API calls
121+
fetch_paginated() {
122+
local url=$1
123+
local page=1
124+
local per_page=100
125+
126+
while true; do
127+
local paginated_url="${url}?per_page=${per_page}&page=${page}"
128+
129+
# Add existing query params if they exist
130+
if [[ "$url" == *"?"* ]]; then
131+
paginated_url="${url}&per_page=${per_page}&page=${page}"
132+
fi
133+
134+
local response
135+
response=$("${CURL_BASE[@]}" "$paginated_url" 2>/dev/null) || {
136+
echo "[ERROR] Failed to fetch page $page from $url" >&2
137+
return 1
138+
}
139+
140+
# Check if response is empty array or null
141+
if [[ "$response" == "[]" || "$response" == "null" ]]; then
142+
break
143+
fi
144+
145+
# Extract results from current page
146+
local page_results
147+
page_results=$(echo "$response" | jq -r '.[].id' 2>/dev/null) || {
148+
echo "[ERROR] Failed to parse JSON response from page $page" >&2
149+
return 1
150+
}
151+
152+
# If no results on this page, we're done
153+
if [[ -z "$page_results" ]]; then
154+
break
155+
fi
156+
157+
# Count projects found and show progress
158+
local page_count
159+
page_count=$(echo "$page_results" | wc -l)
160+
TOTAL_PROJECTS_FOUND=$((TOTAL_PROJECTS_FOUND + page_count))
161+
echo "[PROGRESS] Found $page_count projects on page $page (total: $TOTAL_PROJECTS_FOUND)" >&2
162+
163+
# Output page results
164+
echo "$page_results"
165+
166+
# If we got less than per_page results, we're on the last page
167+
local item_count
168+
item_count=$(echo "$response" | jq '. | length' 2>/dev/null) || 0
169+
if [[ "$item_count" -lt "$per_page" ]]; then
170+
break
171+
fi
172+
173+
((page++))
174+
done
175+
}
176+
111177
create_hook() {
112178
local pid=$1
113179

@@ -118,6 +184,7 @@ create_hook() {
118184

119185
# Mark as processed
120186
PROCESSED_PROJECTS[$pid]=1
187+
PROJECTS_PROCESSED=$((PROJECTS_PROCESSED + 1))
121188

122189
local encoded_pid
123190
# URL encode if pid is not purely numeric
@@ -127,6 +194,22 @@ create_hook() {
127194
encoded_pid=$(url_encode "$pid")
128195
fi
129196

197+
# Check if webhook already exists
198+
local existing_webhooks
199+
existing_webhooks=$("${CURL_BASE[@]}" "${API}/projects/${encoded_pid}/hooks" 2>/dev/null) || {
200+
echo "[ERROR] Failed to fetch existing webhooks for project $pid" >&2
201+
return 1
202+
}
203+
204+
# Check if our webhook URL already exists
205+
if echo "$existing_webhooks" | jq -e --arg url "$HOOK_URL" '.[] | select(.url == $url)' >/dev/null 2>&1; then
206+
[[ "$VERBOSE" == "true" ]] && echo "[INFO] Webhook already exists for project: $pid" >&2
207+
EXISTING_WEBHOOK_PROJECTS+=("$pid")
208+
return 0
209+
fi
210+
211+
[[ "$VERBOSE" == "true" ]] && echo "[INFO] Adding webhook to project: $pid" >&2
212+
130213
"${CURL_BASE[@]}" --request POST \
131214
--data-urlencode "url=${HOOK_URL}" \
132215
--data "token=${HOOK_SECRET}" \
@@ -151,38 +234,64 @@ traverse_group() {
151234
else
152235
encoded_gid=$(url_encode "$gid")
153236
fi
154-
# projects (includes nested sub-groups)
237+
238+
# projects (includes nested sub-groups) - with pagination
155239
while IFS= read -r pid; do
156240
[[ -n "$pid" ]] && create_hook "$pid"
157241
done < <(
158-
"${CURL_BASE[@]}" \
159-
"${API}/groups/${encoded_gid}/projects?include_subgroups=true&per_page=100" |
160-
jq -r '.[].id'
242+
fetch_paginated "${API}/groups/${encoded_gid}/projects?include_subgroups=true"
161243
)
162-
# recurse explicit subgroups (older GitLab)
244+
245+
# recurse explicit subgroups (older GitLab) - with pagination
163246
while IFS= read -r sg; do
164247
[[ -n "$sg" ]] && traverse_group "$sg"
165248
done < <(
166-
"${CURL_BASE[@]}" "${API}/groups/${encoded_gid}/subgroups?per_page=100" |
167-
jq -r '.[].id'
249+
fetch_paginated "${API}/groups/${encoded_gid}/subgroups"
168250
)
169251
}
170252

171253
##############################################################################
172254
# Main
173255
##############################################################################
256+
echo "[INFO] Starting webhook processing..." >&2
257+
174258
if [[ -n $PROJECT ]]; then
259+
echo "[INFO] Processing single project: $PROJECT" >&2
175260
create_hook "$PROJECT"
176261
else
262+
echo "[INFO] Processing group and subgroups: $GROUP" >&2
177263
traverse_group "$GROUP"
178264
fi
179265

266+
echo "[INFO] Finished processing all projects" >&2
267+
180268
# Print final summary
181-
if [[ ${#WEBHOOK_PROJECTS[@]} -eq 0 ]]; then
182-
echo "❌ No webhooks were installed."
269+
total_projects=$((${#WEBHOOK_PROJECTS[@]} + ${#EXISTING_WEBHOOK_PROJECTS[@]}))
270+
271+
if [[ $total_projects -eq 0 ]]; then
272+
echo "[INFO] No projects were processed"
183273
else
184-
echo "✅ Webhooks installed successfully on ${#WEBHOOK_PROJECTS[@]} project(s):"
185-
for pid in "${WEBHOOK_PROJECTS[@]}"; do
186-
echo " - Project ID: $pid"
187-
done
274+
if [[ ${#WEBHOOK_PROJECTS[@]} -gt 0 ]]; then
275+
if [[ "$VERBOSE" == "true" ]]; then
276+
echo "[INFO] Webhooks installed successfully on ${#WEBHOOK_PROJECTS[@]} project(s):"
277+
for pid in "${WEBHOOK_PROJECTS[@]}"; do
278+
echo " - Project ID: $pid"
279+
done
280+
else
281+
echo "[INFO] Webhooks installed successfully on ${#WEBHOOK_PROJECTS[@]} project(s)"
282+
fi
283+
fi
284+
285+
if [[ ${#EXISTING_WEBHOOK_PROJECTS[@]} -gt 0 ]]; then
286+
if [[ "$VERBOSE" == "true" ]]; then
287+
echo "[INFO] Webhooks already existed on ${#EXISTING_WEBHOOK_PROJECTS[@]} project(s):"
288+
for pid in "${EXISTING_WEBHOOK_PROJECTS[@]}"; do
289+
echo " - Project ID: $pid"
290+
done
291+
else
292+
echo "[INFO] Webhooks already existed on ${#EXISTING_WEBHOOK_PROJECTS[@]} project(s)"
293+
fi
294+
fi
295+
296+
echo "[INFO] Total projects processed: $total_projects"
188297
fi

0 commit comments

Comments
 (0)