build: strip release binaries and gate publishing on CI
Two gaps left over from the v6.0.0 release.
The v6.0.0 archives shipped unstripped: 3.63 MB vs 4.53 MB locally, 168
symbols instead of 9483. Setting it on the profile rather than in the
workflow covers every target at once and `cargo install` along with them.
Nothing gated the crates.io publish. A published version can be yanked but
never withdrawn, so the release job now waits for the CI run on the same
commit and refuses to publish unless it is green. release-pr deliberately
does not wait; opening the release PR is harmless.
This is not hypothetical: CI failed on eef7bf7, the v6.0.0 release commit.
It was a flaky e2e timeout rather than a regression - the very next commit
touched no code and passed - but the gate would have stopped that release,
which is the point. The gate reads the newest CI run for the commit, so
re-running a flaky job and then re-running Release clears it.
This commit is contained in:
@@ -18,6 +18,44 @@ env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
jobs:
|
||||
# CI runs on this same push. Nothing may reach crates.io until it has passed,
|
||||
# because a published version cannot be withdrawn, only yanked. Deliberately
|
||||
# not a dependency of release-pr: opening the release PR is harmless and
|
||||
# should not wait.
|
||||
ci-gate:
|
||||
name: Wait for CI
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'push'
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
steps:
|
||||
- name: Wait for CI to pass on this commit
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
# jq reduces the run to a single word so there is no shell word
|
||||
# splitting to get wrong. `last` picks the newest run for the commit,
|
||||
# so re-running a flaky CI job flips this to success and re-running
|
||||
# the Release workflow then goes through.
|
||||
for _ in $(seq 1 90); do
|
||||
verdict=$(gh api "repos/$GITHUB_REPOSITORY/actions/runs?head_sha=$GITHUB_SHA" \
|
||||
--jq '[.workflow_runs[] | select(.path==".github/workflows/ci.yml")]
|
||||
| sort_by(.run_number) | last
|
||||
| if . == null then "absent"
|
||||
elif .status != "completed" then "running"
|
||||
else (.conclusion // "unknown") end' \
|
||||
2>/dev/null || echo "unreachable")
|
||||
case "$verdict" in
|
||||
success) echo "CI passed for $GITHUB_SHA"; exit 0 ;;
|
||||
absent|running|unreachable) ;;
|
||||
*) echo "::error::CI concluded '$verdict' for $GITHUB_SHA - refusing to release"; exit 1 ;;
|
||||
esac
|
||||
sleep 20
|
||||
done
|
||||
echo "::error::timed out waiting for CI on $GITHUB_SHA - refusing to release"
|
||||
exit 1
|
||||
|
||||
# Opens (or updates) a "chore: release vX.Y.Z" PR with the version bump and
|
||||
# changelog derived from the conventional commits on master. Merging it is the
|
||||
# release trigger.
|
||||
@@ -47,6 +85,11 @@ jobs:
|
||||
release:
|
||||
name: Tag and publish
|
||||
runs-on: ubuntu-latest
|
||||
needs: ci-gate
|
||||
# ci-gate is skipped on workflow_dispatch, which would skip this job too
|
||||
# without always(). A ci-gate failure leaves both clauses false, so a red
|
||||
# CI blocks the publish.
|
||||
if: always() && (github.event_name == 'workflow_dispatch' || needs.ci-gate.result == 'success')
|
||||
concurrency:
|
||||
group: release-${{ github.ref }}
|
||||
cancel-in-progress: false
|
||||
|
||||
Reference in New Issue
Block a user