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
23 changes: 14 additions & 9 deletions .github/actions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ pr-review:
## Release actions

Three composite actions implement the org release flow — trunk-first
candidate, settle-by-PR, publish-once. They are language-agnostic: the only
candidate, environment-gated settle (or settle-by-PR), publish-once. They are language-agnostic: the only
repo-specific inputs are where the version lives (`version_file` +
`version_pattern`: `plain`, `toml`, `json`), an optional `bump_command` for
whatever else must move with the version (`cargo update --workspace` for a
Expand Down Expand Up @@ -386,16 +386,21 @@ Requirements in the consumer repo:
- Org variable `MEGA_MAXWELL_CLIENT_ID` (the Maxwell app's client id) / secret `MEGA_MAXWELL_PK`. PRs
and tag pushes must come from an App token: `GITHUB_TOKEN` does not trigger
downstream workflows.
- A reviewed settle PR is the human gate for creating a tag: the
`release-*` branch ruleset below requires it. No environment approval is
needed on the publish job (an `environment:` with required reviewers can
be added by repos that want a second, separate approver).
- The human gate for creating a tag is the settle dispatch: the templates
put `environment: release` on the settle job, so its required reviewers
approve the run before it starts (create the environment with reviewers,
`prevent self-review` off if the dispatcher approves, and a deployment
branch policy of the default branch only), and the action's
`settlers: admin` checks the dispatching actor again. A repo that settles
by PR instead (no `settle_mode`) has the reviewed settle PR as its gate:
the `release-*` branch ruleset below requires one.
- A tag ruleset for `v*` (no creation/deletion/force-push) with the app as a
bypass actor, so `release-publish` is the only tag creator.
- A branch ruleset for `release-*` requiring PRs, so settlement is always a
reviewed merge. Drift after a settle PR is opened is caught by
`release-publish` itself (it refuses if the branch tip at merge is not the
settled SHA), so no "up to date" status check is needed.
- A branch ruleset for `release-*` requiring PRs, with the app as a bypass
actor: nothing but the app's settle commit reaches a release branch
without a reviewed PR. In PR mode, drift after a settle PR is opened is
caught by `release-publish` itself (it refuses if the branch tip at merge
is not the settled SHA), so no "up to date" status check is needed.
- `gh` and `python3` on the runner (any GitHub-hosted image).
- The cut and publish stages only accept PRs opened by the app identity
(`pr_author`, default `mega-maxwell[bot]`); the templates also gate the
Expand Down
5 changes: 5 additions & 0 deletions workflow-templates/release-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ name: Release Publish
#
# This file must exist on the release branch (it does, when the branch is cut
# from a default branch that has it).
#
# Only settlement by PR reaches this workflow. With `settle_mode: direct` in
# release-settle.yml (the template's default) the settle job publishes
# itself and nothing here ever fires: the job gate above rejects any settle
# PR the app did not open.

on:
pull_request:
Expand Down
29 changes: 19 additions & 10 deletions workflow-templates/release-settle.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
name: Release Settle

# Propose settling a release candidate. Dispatch from any branch with the
# Settle a release candidate. Dispatch from the default branch with the
# version and the full SHA of the release-branch tip; the shared action
# verifies it, generates release notes from the commits since the previous
# tag, writes them to the changelog, and opens a settle PR onto the release
# branch. Merging that PR is the settlement decision (release-publish tags it).
# tag, commits them to the changelog on the release branch, and publishes:
# annotated tag at that commit, GitHub Release with the notes.
#
# The dispatch is the settlement decision, gated twice: the `release`
# environment on the job (its required reviewers approve the run before it
# starts; give it a deployment branch policy of the default branch only) and
# `settlers` in the action (the dispatching actor must be a repository
# admin, or a listed login). The app must be a bypass actor on the
# release-branch ruleset and on the `v*` tag ruleset.
#
# To settle by PR instead — a reviewed `chore/release-settle-vX.Y.Z` PR onto
# the release branch, tagged by release-publish.yml when it merges — remove
# `environment:`, `settle_mode` and `settlers` below.

on:
workflow_dispatch:
Expand All @@ -18,8 +29,8 @@ on:
required: true
type: string

# One settle per version: two dispatches for the same version would both
# force-push the same settle branch. Queue, never cancel.
# One settle per version: two dispatches for the same version would race on
# the release branch. Queue, never cancel.
concurrency:
group: ${{ github.workflow }}-${{ inputs.version }}
cancel-in-progress: false
Expand All @@ -30,6 +41,7 @@ permissions:
jobs:
settle:
runs-on: ubuntu-latest
environment: release
steps:
- uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3
id: app-token
Expand All @@ -50,8 +62,5 @@ jobs:
version_file: VERSION
version_pattern: plain
changelog_file: CHANGELOG.md
# Settle without a PR — the dispatch is the decision, enforced by
# `settlers` (logins and/or `admin` = repository admins). The app
# must be a bypass actor on the release-branch ruleset.
# settle_mode: direct
# settlers: admin
settle_mode: direct
settlers: admin
Loading