Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 50 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ name: Release

on:
push:
branches: [v2.x]
branches:
- v2.x
- 'release-please--branches--**'

permissions:
contents: read

jobs:
release-please:
if: github.ref == 'refs/heads/v2.x'
runs-on: ubuntu-latest
outputs:
releases_created: ${{ steps.release.outputs.releases_created }}
Expand All @@ -24,6 +27,52 @@ jobs:
# branch (master) and never builds a release PR for this branch.
target-branch: v2.x

# The branch ruleset requires verified signatures on every PR commit, but two
# paths put unsigned commits on the release branch: release-please creates its
# commits through the REST API (which cannot sign), and the "Update branch"
# rebase button rewrites the commit unsigned. Reacting to pushes on the release
# branch itself covers both: whenever its head commit is unsigned, amend it with
# the bot's GPG key (same key and setup as logto-io/js).
sign-release-branch:
if: startsWith(github.ref_name, 'release-please--branches--')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
token: ${{ secrets.BOT_PAT }}
# Amending in the default shallow clone rewrites the head commit into a
# parentless orphan (its parents are behind the shallow boundary) — the
# full history is required for the amend to keep the parent.
fetch-depth: 0

- name: Import bot GPG key
uses: crazy-max/ghaction-import-gpg@v6
with:
gpg_private_key: ${{ secrets.BOT_GPG_KEY }}
passphrase: ${{ secrets.BOT_GPG_PASSPHRASE }}
git_user_signingkey: true
git_commit_gpgsign: true

- name: Sign the head commit when unsigned
run: |
# Only amend truly unsigned commits ("N"); an already-signed commit
# ("E"/"U"/"G") is left alone so this job does not retrigger itself.
if [ "$(git log -1 --format=%G?)" != "N" ]; then
echo "Head commit is already signed, nothing to do"
exit 0
fi
git config user.name silverhand-bot
git config user.email bot@silverhand.io
git commit --amend --no-edit --gpg-sign
# Never push a history rewrite: the amended commit must keep its parent
# (an empty %P means the orphan bug above — abort instead of clobbering
# the branch and auto-closing the release PR).
if [ -z "$(git log -1 --format=%P)" ]; then
echo "Amended commit lost its parent; refusing to push" >&2
exit 1
fi
git push --force origin HEAD:${{ github.ref_name }}

# GitHub marks the most recently created release as "Latest" by default,
# so a maintenance release cut here would steal the badge from the v3 line.
unmark-latest:
Expand Down
7 changes: 7 additions & 0 deletions RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ Releases are automated via [release-please](https://github.com/googleapis/releas
| `feat!:` or commit body containing `BREAKING CHANGE:` | major (**X+1**.0.0) |
| `chore:` / `refactor:` / `docs:` / `test:` / `ci:` / `revert:` | no bump (still listed in changelog) |

release-please creates the release PR commit through the REST API, which cannot
produce a GPG signature, and the "Update branch" rebase button also rewrites the
commit unsigned — either way the branch ruleset's required-signatures rule would
block the merge. Every push to the release branch therefore runs a job that
amends an unsigned head commit with the bot's GPG key (`BOT_GPG_KEY` org secret,
shared with logto-io/js).

3. Merging the release PR triggers the workflow again. release-please creates the git tag `vX.Y.Z` and a GitHub Release with auto-generated notes immediately, then sets `releases_created=true`.
4. The publish job (gated on `releases_created`) runs next:
- Builds and signs `io.logto.sdk:kotlin` and `io.logto.sdk:android` with in-memory PGP keys.
Expand Down
Loading