From 9fbfdcee6d298c6b7e6543a437a2983f57a44c50 Mon Sep 17 00:00:00 2001 From: Jason Woltje Date: Thu, 26 Feb 2026 12:05:30 -0600 Subject: [PATCH] fix(woodpecker): add step-level details and fix timestamps in pipeline-status - Show individual step names with OK/FAIL/RUN/SKIP/WAIT status - Show error messages and exit codes for failed steps - Convert epoch timestamps to ISO 8601 - Always fetch full pipeline detail (list endpoint lacks workflows) - Fix started_at/finished_at field names (API uses started/finished) Co-Authored-By: Claude Opus 4.6 --- tools/woodpecker/pipeline-status.sh | 71 ++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 22 deletions(-) diff --git a/tools/woodpecker/pipeline-status.sh b/tools/woodpecker/pipeline-status.sh index 08fe636..eb98f68 100755 --- a/tools/woodpecker/pipeline-status.sh +++ b/tools/woodpecker/pipeline-status.sh @@ -47,29 +47,33 @@ fi # Resolve owner/repo to numeric ID (Woodpecker v3 API) REPO_ID=$(wp_resolve_repo_id "$REPO") || exit 1 +_wp_fetch() { + local ep="$1" + local resp http_code body + resp=$(curl -sk -w "\n%{http_code}" \ + -H "Authorization: Bearer $WOODPECKER_TOKEN" \ + "$ep") + http_code=$(echo "$resp" | tail -n1) + body=$(echo "$resp" | sed '$d') + if [[ "$http_code" != "200" ]]; then + echo "Error: HTTP $http_code from $ep" >&2 + return 1 + fi + echo "$body" +} + if [[ -z "$NUMBER" ]]; then - # Get latest pipeline - endpoint="${WOODPECKER_URL}/api/repos/${REPO_ID}/pipelines?per_page=1" -else - endpoint="${WOODPECKER_URL}/api/repos/${REPO_ID}/pipelines/${NUMBER}" + # Get latest pipeline number from list, then fetch full detail + list_body=$(_wp_fetch "${WOODPECKER_URL}/api/repos/${REPO_ID}/pipelines?per_page=1") || exit 1 + NUMBER=$(echo "$list_body" | jq -r '.[0].number // empty') + if [[ -z "$NUMBER" ]]; then + echo "Error: No pipelines found" >&2 + exit 1 + fi fi -response=$(curl -sk -w "\n%{http_code}" \ - -H "Authorization: Bearer $WOODPECKER_TOKEN" \ - "$endpoint") - -http_code=$(echo "$response" | tail -n1) -body=$(echo "$response" | sed '$d') - -if [[ "$http_code" != "200" ]]; then - echo "Error: Failed to get pipeline status (HTTP $http_code)" >&2 - exit 1 -fi - -# If we got a list, extract the first one -if [[ -z "$NUMBER" ]]; then - body=$(echo "$body" | jq '.[0]') -fi +# Always fetch the single-pipeline endpoint (includes workflows/steps) +body=$(_wp_fetch "${WOODPECKER_URL}/api/repos/${REPO_ID}/pipelines/${NUMBER}") || exit 1 if [[ "$FORMAT" == "json" ]]; then echo "$body" | jq '.' @@ -79,6 +83,7 @@ fi echo "Pipeline Status" echo "===============" echo "$body" | jq -r ' + def ts: if . and . > 0 then todate else "—" end; " Number: \(.number)\n" + " Status: \(.status)\n" + " Branch: \(.branch)\n" + @@ -86,6 +91,28 @@ echo "$body" | jq -r ' " Commit: \(.commit[:12])\n" + " Message: \(.message | split("\n")[0])\n" + " Author: \(.author)\n" + - " Started: \(.started_at // "pending")\n" + - " Finished: \(.finished_at // "running")" + " Started: \(.started | ts)\n" + + " Finished: \(.finished | ts)" ' + +# Show step-level details if workflows exist +has_workflows=$(echo "$body" | jq 'has("workflows") and (.workflows | length > 0)') +if [[ "$has_workflows" == "true" ]]; then + echo "" + echo "Steps" + echo "-----" + echo "$body" | jq -r ' + .workflows[] | .children[]? | + select(.type != "clone") | + " " + + (if .state == "success" then "OK" + elif .state == "failure" then "FAIL" + elif .state == "running" then "RUN" + elif .state == "skipped" then "SKIP" + elif .state == "pending" then "WAIT" + else .state end) + + " " + .name + + (if .error and .error != "" then " (" + .error + ")" else "" end) + + (if .exit_code and .exit_code != 0 then " [exit " + (.exit_code | tostring) + "]" else "" end) + ' +fi