mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-01 11:02:14 +00:00
ci: stop a PR run once Test and Lint has failed (#5530)
On run 30674613104 the e2e, ILM and sftp lanes had all failed while Test and Lint and the rio-v2 variant kept running past 70 minutes. The run's verdict was settled; the remaining lanes were spending sm-standard-4 time on a result nobody could act on, and with one full PR run needing about seven of those runners, that time comes out of other PRs' queue time. Two mechanisms, both scoped to pull_request so main pushes, the merge queue and the weekly schedule keep the full failure signal: - test-and-lint-protocols: fail-fast on PRs, so one failing protocol leg stops its sibling. This is the only part that also covers fork PRs, since it needs no token. - test-and-lint: on failure, cancel the run through the REST API. Only test-and-lint may cancel. The lanes that are not required checks (protocols, ILM, e2e, s3-tests) must never hold that power: a flake in one of them would turn the required "Test and Lint" into `cancelled`, which blocks the merge. A maintainer can merge today with sftp red, and that has to stay true. The cancel step uses curl, not `gh`: every existing `gh` call in this repo runs on ubuntu-latest, and the sm-standard-* images are custom and trimmed, so `gh` is not known to exist there. Fork PRs are excluded by an explicit condition rather than left to fail, since their GITHUB_TOKEN is forced read-only and job-level permissions cannot raise it. Job-level permissions must list contents: read alongside actions: write — job-level permissions replace the workflow block instead of merging with it, and dropping contents would break this job's checkout and the repo-token the setup action passes to setup-protoc. Because that token can now cancel runs and delete Actions caches, the checkout also sets persist-credentials: false so a PR's own build.rs or proc-macro cannot read it back out of .git/config. Refs: rustfs/backlog#1598, rustfs/backlog#1599
This commit is contained in:
@@ -143,11 +143,23 @@ jobs:
|
||||
needs: [ quick-checks ]
|
||||
runs-on: sm-standard-4
|
||||
timeout-minutes: 90
|
||||
# Both lines are required. Job-level `permissions` replaces the workflow
|
||||
# block rather than merging with it, so declaring only `actions: write`
|
||||
# would drop `contents: read` and break this job's checkout and the
|
||||
# repo-token the setup action hands to setup-protoc.
|
||||
permissions:
|
||||
contents: read
|
||||
actions: write
|
||||
env:
|
||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||
with:
|
||||
# This job's token can cancel runs and delete Actions caches. Checkout
|
||||
# otherwise writes it into .git/config, where a PR's own build.rs or
|
||||
# proc-macro could read it back out.
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup Rust environment
|
||||
uses: ./.github/actions/setup
|
||||
@@ -278,6 +290,48 @@ jobs:
|
||||
- name: Run rebalance/decommission migration proofs
|
||||
run: ./scripts/check_migration_gate_count.sh
|
||||
|
||||
# Early stop. Once this job has failed the PR cannot merge, so the sibling
|
||||
# lanes are burning runners on a result nobody can act on: on run
|
||||
# 30674613104 three lanes had already failed while Test and Lint and the
|
||||
# rio-v2 variant kept going past 70 minutes.
|
||||
#
|
||||
# Only this job may cancel. The lanes that are NOT required checks
|
||||
# (protocols, ILM, e2e, s3-tests) must never hold that power: a flake in
|
||||
# one of them would turn the required "Test and Lint" into `cancelled`,
|
||||
# which blocks the merge. Today a maintainer can merge with sftp red, and
|
||||
# that has to stay true.
|
||||
#
|
||||
# These steps run last so the `if: always()` artifact upload above still
|
||||
# captures logs and diagnostics before the run goes away.
|
||||
- name: Annotate early-stop reason
|
||||
if: failure() && github.event_name == 'pull_request'
|
||||
run: |
|
||||
echo "## CI early-stop" >> "$GITHUB_STEP_SUMMARY"
|
||||
echo "Job \`${GITHUB_JOB}\` (Test and Lint) failed; cancelling run ${GITHUB_RUN_ID} to free runners." >> "$GITHUB_STEP_SUMMARY"
|
||||
echo "Sibling jobs showing **cancelled** were stopped by this job, not by their own failure." >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
# curl rather than `gh`: every existing `gh` call in this repo runs on
|
||||
# ubuntu-latest, and the sm-standard-* images are custom and trimmed (they
|
||||
# ship no C toolchain, see the e2e job below), so `gh` is not known to
|
||||
# exist here.
|
||||
#
|
||||
# Fork PRs are excluded explicitly instead of relying on the error path:
|
||||
# their GITHUB_TOKEN is forced read-only and job-level permissions cannot
|
||||
# raise it, so the call would always 403. Skipping keeps their logs clean.
|
||||
- name: Cancel run on failure (same-repo PR only)
|
||||
if: >-
|
||||
failure() && github.event_name == 'pull_request'
|
||||
&& github.event.pull_request.head.repo.full_name == github.repository
|
||||
continue-on-error: true
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
curl -fsS -X POST \
|
||||
-H "Authorization: Bearer ${GH_TOKEN}" \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
"${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}/cancel" || true
|
||||
|
||||
# Dedicated serial lane for the ILM / lifecycle integration tests. These tests
|
||||
# drive the object layer through process-global singletons (the GLOBAL_ENV
|
||||
# ECStore, the global tier-config manager, background-expiry workers) and bind
|
||||
@@ -361,7 +415,13 @@ jobs:
|
||||
runs-on: sm-standard-4
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
fail-fast: false
|
||||
# On a PR, one failing protocol leg is enough to know the PR is not ready,
|
||||
# so stop the sibling leg instead of paying another ~40 minutes for it.
|
||||
# Everywhere else (main pushes, the merge queue, the weekly schedule) keep
|
||||
# the full signal: there we want to know whether swift AND sftp are broken,
|
||||
# not just whichever failed first. This is the only part of the early-stop
|
||||
# work that also covers fork PRs, since it needs no token.
|
||||
fail-fast: ${{ github.event_name == 'pull_request' }}
|
||||
matrix:
|
||||
features:
|
||||
- name: swift
|
||||
|
||||
Reference in New Issue
Block a user