@@ -44,37 +44,83 @@ jobs:
4444 continue-on-error : true
4545 if : steps.check.outputs.has_ready == 'true'
4646 env :
47+ BK_ORG : ${{ vars.BUILDKITE_ORG_SLUG }}
48+ BK_PIPELINE : ${{ vars.BUILDKITE_PIPELINE_SLUG }}
4749 BUILDKITE_API_TOKEN : ${{ secrets.BUILDKITE_API_TOKEN }}
4850 PR_BRANCH : ${{ github.event.pull_request.head.ref }}
4951 PR_NUMBER : ${{ github.event.pull_request.number }}
5052 run : |
51- # `curl` without --fail-with-body treats an HTTP error as success and
52- # pipes the error body onward. Buildkite answers a rate limit or an
53- # unauthorized read with an object such as {"message": "Not Found"},
54- # and `.[]` over an object yields its values, so `.env` then runs
55- # against a string and jq exits non-zero.
56- if ! response=$(curl -sS --get --fail-with-body \
53+ set -euo pipefail
54+ response_file=$(mktemp)
55+ builds_file=$(mktemp)
56+ trap 'rm -f "$response_file" "$builds_file"' EXIT
57+
58+ if [[ ! "$PR_NUMBER" =~ ^[1-9][0-9]*$ ]]; then
59+ echo "::warning::Invalid pull request number; stale Buildkite builds may continue."
60+ exit 1
61+ fi
62+
63+ if ! curl -sS --fail-with-body --get \
5764 -H "Authorization: Bearer $BUILDKITE_API_TOKEN" \
5865 --data-urlencode "branch=$PR_BRANCH" \
59- --data-urlencode "state=running,scheduled" \
60- "https://api.buildkite.com/v2/organizations/${{ vars.BUILDKITE_ORG_SLUG }}/pipelines/${{ vars.BUILDKITE_PIPELINE_SLUG }}/builds" 2>&1); then
61- echo "::warning::Could not list Buildkite builds, skipping cancellation: $response"
62- exit 0
66+ --data-urlencode "state[]=running" \
67+ --data-urlencode "state[]=scheduled" \
68+ --data-urlencode "exclude_jobs=true" \
69+ --data-urlencode "exclude_pipeline=true" \
70+ --output "$response_file" \
71+ "https://api.buildkite.com/v2/organizations/${BK_ORG}/pipelines/${BK_PIPELINE}/builds"; then
72+ echo "::warning::Could not list Buildkite builds; stale merge-gate builds may continue."
73+ exit 1
74+ fi
75+
76+ if ! jq -e '
77+ if type != "array" then false
78+ else all(.[];
79+ if type != "object" then false
80+ else
81+ (.number | if type == "number" then . > 0 and floor == . else false end)
82+ and (
83+ (.env? | if . == null then {} else . end) as $env
84+ | if ($env | type) != "object" then false
85+ else
86+ ($env.TEST_SCOPE? | . == null or type == "string")
87+ and ($env.PR_NUMBER? | . == null or type == "string")
88+ end
89+ )
90+ end
91+ )
92+ end
93+ ' "$response_file" >/dev/null 2>&1; then
94+ # Do not print the response body: it is remote data and may contain
95+ # multiline values that would be interpreted as workflow commands.
96+ echo "::warning::Buildkite returned an invalid build list; stale merge-gate builds may continue."
97+ exit 1
6398 fi
6499
65100 # Match both branch and PR number: forks can reuse the same branch name.
66- if ! builds=$(printf '%s' "$response" | jq -r --arg pr_number "$PR_NUMBER" \
67- 'if type == "array" then .[] else empty end
68- | select((.env.TEST_SCOPE? == "merge") and (.env.PR_NUMBER? == $pr_number))
69- | .number' 2>&1); then
70- echo "::warning::Could not parse the Buildkite build list, skipping cancellation: $builds"
71- exit 0
101+ if ! jq -r --arg pr_number "$PR_NUMBER" '
102+ .[]
103+ | select((.env.TEST_SCOPE? == "merge") and (.env.PR_NUMBER? == $pr_number))
104+ | .number
105+ ' "$response_file" > "$builds_file"; then
106+ echo "::warning::Could not select stale Buildkite builds; stale merge-gate builds may continue."
107+ exit 1
72108 fi
73- for build_num in $builds; do
109+
110+ cancellation_failed=0
111+ while IFS= read -r build_num; do
74112 echo "Cancelling Buildkite build #$build_num"
75- curl -sS -X PUT -H "Authorization: Bearer $BUILDKITE_API_TOKEN" \
76- "https://api.buildkite.com/v2/organizations/${{ vars.BUILDKITE_ORG_SLUG }}/pipelines/${{ vars.BUILDKITE_PIPELINE_SLUG }}/builds/${build_num}/cancel"
77- done
113+ if ! curl -sS --fail-with-body -o /dev/null -X PUT \
114+ -H "Authorization: Bearer $BUILDKITE_API_TOKEN" \
115+ "https://api.buildkite.com/v2/organizations/${BK_ORG}/pipelines/${BK_PIPELINE}/builds/${build_num}/cancel"; then
116+ echo "::warning::Could not cancel Buildkite build #$build_num; trying remaining builds."
117+ cancellation_failed=1
118+ fi
119+ done < "$builds_file"
120+
121+ if (( cancellation_failed != 0 )); then
122+ exit 1
123+ fi
78124
79125 # Check out the immutable BASE SHA: pull_request_target must never run a
80126 # planner or gate script from the untrusted PR head.
0 commit comments