Skip to content

Commit 508e843

Browse files
committed
ci: use a github app token so release pushes survive branch protection
1 parent 6c44650 commit 508e843

1 file changed

Lines changed: 25 additions & 8 deletions

File tree

‎.github/workflows/on-release-main.yml‎

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
# Automated release: python-semantic-release analyzes the conventional
2-
# commits on main, and when a release is due it updates CHANGELOG.md,
3-
# commits, tags vX.Y.Z, pushes and creates the GitHub release. hatch-vcs
4-
# derives the package version from that tag, so no version file is bumped.
5-
# Publishing happens in this same run: pushes made with GITHUB_TOKEN do
6-
# not retrigger workflows, so a tag-triggered publish would never fire.
2+
# commits on main, and when a release is due it bumps the static version in
3+
# pyproject.toml and CITATION.cff, updates CHANGELOG.md, relocks uv.lock,
4+
# commits, tags vX.Y.Z, pushes and creates the GitHub release. Publishing
5+
# happens in this same run: pushes made with GITHUB_TOKEN do not retrigger
6+
# workflows, so a tag-triggered publish would never fire.
77
#
88
# Filename and environment name are load-bearing: the PyPI trusted
99
# publisher (OIDC) references workflow "on-release-main.yml" and
10-
# environment "pypi".
10+
# environment "pypi". That same "pypi" environment is also the release
11+
# gate: it has a required-reviewer protection rule (repo Settings ->
12+
# Environments -> pypi, configured out-of-repo), so this job pauses right
13+
# after checkout until a reviewer approves. Reject and nothing is tagged
14+
# or published. This is the deliberate-release control in place of a
15+
# staging branch.
1116

1217
name: release-main
1318

@@ -36,23 +41,35 @@ jobs:
3641
released: ${{ steps.psr.outputs.released }}
3742
version: ${{ steps.psr.outputs.version }}
3843
steps:
44+
# The default GITHUB_TOKEN cannot push to a ruleset-protected main
45+
# (fails with GH013). Mint a short-lived, repo-scoped (Contents: write)
46+
# GitHub App token instead; the app is on main's branch-protection
47+
# bypass list, so PSR's release commit and tag push succeed.
48+
- name: Generate app token
49+
id: app-token
50+
uses: actions/create-github-app-token@v1
51+
with:
52+
app-id: ${{ secrets.RELEASE_APP_ID }}
53+
private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
54+
3955
- name: Check out
4056
uses: actions/checkout@v4
4157
with:
42-
# full history: PSR analyzes commits, hatch-vcs needs the tags
58+
# full history so PSR can analyze commits and tags
4359
fetch-depth: 0
4460
# latest main, not the triggering SHA: runs queued behind the
4561
# concurrency group must include release commits pushed by the
4662
# previous run, or their own push is rejected
4763
ref: main
64+
token: ${{ steps.app-token.outputs.token }}
4865

4966
- name: Set up the environment
5067
uses: ./.github/actions/setup-python-env
5168

5269
- name: Version, tag and changelog with python-semantic-release
5370
id: psr
5471
env:
55-
GH_TOKEN: ${{ github.token }}
72+
GH_TOKEN: ${{ steps.app-token.outputs.token }}
5673
run: |
5774
git config user.name "github-actions[bot]"
5875
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"

0 commit comments

Comments
 (0)