Skip to content

Commit b1f910d

Browse files
authored
Merge pull request #6 from artiz/ci/release-pat
ci: release via admin PAT + force_version dispatch (unblock master ruleset)
2 parents 7e6f6d4 + eda5b9f commit b1f910d

2 files changed

Lines changed: 40 additions & 13 deletions

File tree

.github/workflows/ci.yml

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,15 @@ on:
55
branches: [master]
66
pull_request:
77
branches: [master]
8-
# Manual re-run from the Actions tab / `gh workflow run`. Runs lint + test only;
9-
# the release job is gated to `push` events, so a manual run never publishes.
8+
# Manual re-run from the Actions tab / `gh workflow run`. Left blank it runs lint
9+
# + test only; set `force_version` to (re)publish that exact version — use it to
10+
# release a version a failed/blocked run skipped (e.g. the master-ruleset reject).
1011
workflow_dispatch:
12+
inputs:
13+
force_version:
14+
description: "Force a release at this exact version (e.g. 0.3.0). Blank = lint+test only, no publish."
15+
required: false
16+
default: ""
1117

1218
# Cancel superseded PR runs, but never interrupt a master run (it may publish).
1319
concurrency:
@@ -62,25 +68,33 @@ jobs:
6268
publish:
6369
name: release & publish
6470
needs: [lint, test]
65-
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
71+
if: >-
72+
(github.event_name == 'push' && github.ref == 'refs/heads/master') ||
73+
(github.event_name == 'workflow_dispatch' && github.event.inputs.force_version != '')
6674
runs-on: ubuntu-latest
6775
permissions:
6876
contents: write # push the version-bump commit + tag
6977
steps:
7078
- uses: actions/checkout@v4
7179
with:
7280
fetch-depth: 0 # full history + tags, for the semantic version bump
81+
# Push the release commit + tag as an admin PAT so it satisfies the
82+
# `master` ruleset; the default GITHUB_TOKEN can't be granted a bypass.
83+
token: ${{ secrets.RELEASE_PAT }}
7384

7485
- uses: dtolnay/rust-toolchain@stable
7586

7687
- uses: Swatinem/rust-cache@v2
7788

78-
# Decide the next version from conventional commits since the last tag; if
79-
# there is one, bump + commit + tag it, push to master, and publish the
80-
# crates (in dependency order, skipping any already on crates.io). A no-op
81-
# when no release-worthy commit landed. The release commit is pushed with
82-
# GITHUB_TOKEN and carries [skip ci], so it does not re-trigger CI.
89+
# Decide the next version from conventional commits since the last tag (or
90+
# use force_version on a manual dispatch); if there is one, bump + commit +
91+
# tag it, push to master, and publish the crates (in dependency order,
92+
# skipping any already on crates.io). A no-op when no release-worthy commit
93+
# landed. The release commit is pushed with RELEASE_PAT (an admin token, so
94+
# it satisfies the master ruleset) and carries [skip ci], so it does not
95+
# re-trigger CI.
8396
- name: Release & publish
8497
env:
8598
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
99+
FORCE_VERSION: ${{ github.event.inputs.force_version }}
86100
run: bash scripts/release.sh

scripts/release.sh

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,23 @@
66
# publishes the changed crates. A clean no-op when no release-worthy commit
77
# landed since the last tag.
88
#
9-
# The release commit is pushed with the workflow's GITHUB_TOKEN and carries
10-
# `[skip ci]`, so it does not re-trigger CI (no release loop).
9+
# The release commit is pushed with RELEASE_PAT (an admin token, so it satisfies
10+
# the master branch ruleset) and carries `[skip ci]`, so it does not re-trigger CI.
11+
#
12+
# Set FORCE_VERSION=X.Y.Z to (re)publish that exact version instead of computing it
13+
# from the commit history — used to release a version a failed/blocked run skipped.
1114
#
1215
# Requires: CARGO_REGISTRY_TOKEN (publish) and push access to master.
1316
# Usage: scripts/release.sh
1417
set -euo pipefail
1518
cd "$(dirname "$0")/.."
1619

17-
new="$(scripts/bump_version.sh)"
20+
new="${FORCE_VERSION:-$(scripts/bump_version.sh)}"
1821
if [[ -z "$new" ]]; then
1922
echo "No release-worthy commits since the last tag — nothing to release."
2023
exit 0
2124
fi
25+
[[ -n "${FORCE_VERSION:-}" ]] && echo ">> forced release of v$new"
2226

2327
current="$(grep -m1 '^version = ' Cargo.toml | sed -E 's/.*"([^"]+)".*/\1/')"
2428
echo ">> releasing v$new (was v$current)"
@@ -36,8 +40,17 @@ done
3640
git config user.name "github-actions[bot]"
3741
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
3842
git add Cargo.toml crates/*/Cargo.toml
39-
git commit -m "chore(release): v$new [skip ci]"
40-
git tag -a "v$new" -m "v$new"
43+
# Commit only if the bump changed something — a forced re-publish of a version
44+
# whose manifests are already at $new has nothing to commit.
45+
if git diff --cached --quiet; then
46+
echo ">> manifests already at v$new — re-tagging / re-publishing only"
47+
else
48+
git commit -m "chore(release): v$new [skip ci]"
49+
fi
50+
# Tag only if it doesn't already exist (idempotent for a forced re-publish).
51+
if ! git rev-parse -q --verify "refs/tags/v$new" >/dev/null; then
52+
git tag -a "v$new" -m "v$new"
53+
fi
4154
git push origin HEAD:master
4255
git push origin "v$new"
4356

0 commit comments

Comments
 (0)