ci: retry merge-ref checkout to fix transient "not our ref" failures (#5732)

* ci: check out PR head SHA to avoid missing merge-ref checkout failures

* ci: skip coverage comment on cancelled runs to free concurrency slot

post_coverage_comment used if: always(), so on a cancelled run it still ran
on the hosted pool. During rapid pushes the cancelled run's coverage job sat
queued for a hosted runner, keeping the run non-terminal and holding the
branch concurrency slot — so the next push's required Test (ubuntu-latest)
check waited behind it (observed ~9 min, with thrash). Switch to !cancelled():
coverage still posts on test failure, but a cancelled run releases the slot
immediately. Its coverage would be stale anyway.

* ci(triage): route /triage comment runs to the ECS pool

`/triage` comments trigger the authorize+triage jobs on hosted runners,
which queue behind CI during peak hours (~2 min vs 4 s off-peak observed).
Route the comment-triggered triage job to the ECS self-hosted pool, which
is not bound by the GitHub-hosted concurrency limit.

Safe scope: only `issue_comment` events; the job is read-only and checks
out the base ref (never PR-head code). Gated on the same
MAINTAINER_ECS_RUNNER_DISABLED kill-switch as `authorize`, so a disabled
ECS pool falls back to hosted. PR/issues/dispatch triggers stay hosted.

* ci: fetch PR head by ref name to fix 'not our ref' checkout failure

* ci: align Test checkout ref with Lint (add branch_ref fallback)

On workflow_dispatch the Test job runs (its if: !cancelled() overrides the
implicit success() gate when classify_pr is skipped), so its checkout must
honor the branch_ref input like Lint does. Without it, dispatch runs validated
github.ref in Test while Lint validated the user-supplied branch_ref.

* ci: retry merge-ref checkout instead of pinning PR head; drop /triage ECS routing

Per review feedback: checking out refs/pull/N/head dropped merge-result
validation, and merge queue isn't enabled on main to backstop it. Keep merge-ref
semantics (github.ref) for the required Lint/Test checkouts and retry once to
absorb the transient merge-ref lag the PR-head change was working around.

Also revert /triage routing to ECS: that job runs an agent (sandbox:false,
shell/write tools, repo tokens) over untrusted PR/issue text, so it stays on
ephemeral hosted runners, not the persistent self-hosted pool.

* ci: back off before the merge-ref checkout retry

The merge ref (refs/pull/N/merge) is built asynchronously, so a back-to-back
retry can hit the still-unbuilt ref again. Sleep 10s before retrying so the
retry absorbs the multi-second build lag, not just instantaneous blips.
This commit is contained in:
易良 2026-06-23 16:40:36 +08:00 committed by GitHub
parent 663967e10c
commit ac1e473777
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -107,7 +107,22 @@ jobs:
if: "${{ !cancelled() && needs.classify_pr.outputs.skip_ci != 'true' }}"
runs-on: "${{ fromJSON(needs.classify_pr.outputs.ubuntu_runner || '[\"ubuntu-latest\"]') }}"
steps:
# On PRs github.ref is the merge ref (refs/pull/N/merge), so the required
# checks validate the merge result, not just the PR tip. GitHub builds that
# ref asynchronously and it can briefly 404 right after a push, so on
# failure we back off and retry the same ref once.
- name: 'Checkout'
id: 'checkout'
uses: 'actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd' # v6.0.2
continue-on-error: true
with:
ref: '${{ github.event.inputs.branch_ref || github.ref }}'
fetch-depth: 0
- name: 'Back off for the merge ref to build'
if: "${{ steps.checkout.outcome == 'failure' }}"
run: 'sleep 10'
- name: 'Checkout (retry on transient ref lag)'
if: "${{ steps.checkout.outcome == 'failure' }}"
uses: 'actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd' # v6.0.2
with:
ref: '${{ github.event.inputs.branch_ref || github.ref }}'
@ -211,9 +226,22 @@ jobs:
node-version: '22.x'
upload-coverage: 'false'
steps:
# See the Lint job's checkout: merge ref on PRs, back off and retry once on transient lag.
- name: 'Checkout'
id: 'checkout'
if: "${{ needs.classify_pr.outputs.skip_ci != 'true' }}"
uses: 'actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd' # v6.0.2
continue-on-error: true
with:
ref: '${{ github.event.inputs.branch_ref || github.ref }}'
- name: 'Back off for the merge ref to build'
if: "${{ needs.classify_pr.outputs.skip_ci != 'true' && steps.checkout.outcome == 'failure' }}"
run: 'sleep 10'
- name: 'Checkout (retry on transient ref lag)'
if: "${{ needs.classify_pr.outputs.skip_ci != 'true' && steps.checkout.outcome == 'failure' }}"
uses: 'actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd' # v6.0.2
with:
ref: '${{ github.event.inputs.branch_ref || github.ref }}'
# Self-hosted can't reach nodejs.org reliably; reuse the machine's Node.
- name: 'Set up Node.js ${{ matrix.node-version }} (hosted)'
@ -288,9 +316,10 @@ jobs:
needs:
- 'classify_pr'
- 'test'
# !cancelled() not always(): don't let a cancelled run hold the concurrency slot here.
if: |-
${{
always() &&
!cancelled() &&
needs.classify_pr.outputs.skip_ci != 'true' &&
github.event_name == 'pull_request' &&
github.event.pull_request.head.repo.full_name == github.repository