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
2 changes: 1 addition & 1 deletion .github/actions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ input, output, step and error tables are generated from its `action.yml`.
| [`release-candidate`](release-candidate/README.md) | [Release pipeline](RELEASE.md) | Start a release (trunk-first). `stage: propose` bumps the version file on the default branch, drafts this release's changelog entry (dated at settle) from the commits since the previous tag, syncs the previous release's entry from its tag, and opens a `chore/release-candidate-vX.Y.Z` PR; `stage: cut`, run when that PR merges, creates `release-vX.Y.Z` at the merge commit. No tag is created at either stage — tags come from release-publish, once, at settlement. Run as a step in a job the consumer owns; the consumer checks the repository out first (`fetch-depth: 0`, `persist-credentials: false`). Guide: .github/actions/RELEASE.md in megaeth-labs/.github. |
| [`release-publish`](release-publish/README.md) | [Release pipeline](RELEASE.md) | Publish a settled release. Normally runs when a `chore/release-settle-vX.Y.Z` PR merges into its release branch (or, with `commit` + `version` given, on an explicit commit that `release-settle` in `direct` mode just made): creates the annotated tag `vX.Y.Z` at the merge commit (exactly once — refuses if it exists, or if the branch moved after the settle PR was opened) and publishes the GitHub Release with the changelog section as notes. This is the only place in the release flow that creates a tag; merging the settle PR is the approval. The default branch's changelog catches up in the next release candidate PR — nothing is back-merged. The consumer checks the repository out first (`fetch-depth: 0`, `persist-credentials: false`). Guide: .github/actions/RELEASE.md in megaeth-labs/.github. |
| [`release-publish-rust-crates`](release-publish-rust-crates/README.md) | [Release pipeline](RELEASE.md) | Publish an explicit list of workspace crates to crates.io at the release version. Verifies every listed crate's manifest version first, skips crates already published at that version (so a re-run after a partial failure finishes the rest), publishes the remainder in one `cargo publish -p … -p …` invocation — Cargo orders by dependency and waits for the index between crates (requires Cargo ≥ 1.90) — then polls crates.io until every crate reports the version. `dry_run` runs `cargo publish --dry-run`: full packaging and build verification, nothing uploaded. Run inside a job that has checked out the release tag and installed the toolchain the crates need. Never use `--workspace`: a crate without `publish = false` that was never meant to be published would go out with it. Guide: .github/actions/RELEASE.md in megaeth-labs/.github. |
| [`release-settle`](release-settle/README.md) | [Release pipeline](RELEASE.md) | Propose settling a release candidate: verify `commit` is the tip of the release branch and carries the expected version, generate release notes from the commits since the previous tag, write them into the changelog (stamping the date onto the candidate's `## vX.Y.Z` entry), and — in the default `pr` mode — open a `chore/release-settle-vX.Y.Z` PR onto the release branch; merging that PR is the settlement decision and release-publish then tags the merge commit once. In `direct` mode the dispatch itself is the decision: the dispatching actor must be authorised by `settlers`, the changelog commit is pushed straight to the release branch (the app must be a bypass actor on that branch's ruleset), and release-publish runs immediately on that commit. Run as a step in a job the consumer owns; the consumer checks the repository out first (`fetch-depth: 0`, `persist-credentials: false`). Needs `gh` and `python3` on the runner. Guide: .github/actions/RELEASE.md in megaeth-labs/.github. |
| [`release-settle`](release-settle/README.md) | [Release pipeline](RELEASE.md) | Propose settling a release candidate: verify `commit` is the tip of the release branch and carries the expected version, generate release notes from the commits since the previous tag, write them into the changelog (stamping the date onto the candidate's `## vX.Y.Z` entry), and — in the default `pr` mode — open a `chore/release-settle-vX.Y.Z` PR onto the release branch; merging that PR is the settlement decision and release-publish then tags the merge commit once. In `direct` mode the dispatch itself is the decision, gated by the `release` environment the consumer puts on the settle job (optionally also by `settlers`); the changelog commit is pushed straight to the release branch (the app must be a bypass actor on that branch's ruleset), and release-publish runs immediately on that commit. Run as a step in a job the consumer owns; the consumer checks the repository out first (`fetch-depth: 0`, `persist-credentials: false`). Needs `gh` and `python3` on the runner. Guide: .github/actions/RELEASE.md in megaeth-labs/.github. |
| [`release-upload-artifact`](release-upload-artifact/README.md) | [Release pipeline](RELEASE.md) | Upload one file to Google Artifact Registry (generic repository) or a Cloud Storage bucket, idempotently: if the destination already holds a file, its hash is compared — identical means "already there" (success, nothing uploaded), different means failure, never a silent overwrite. Every destination is an input; nothing is defaulted. Authentication is the caller's job: run `google-github-actions/auth` (service-account key or Workload Identity Federation) before this step so `gcloud` is authenticated. `dry_run` computes the checksum and checks the destination but uploads nothing. Guide: .github/actions/RELEASE.md in megaeth-labs/.github. |
| [`release-verify-version`](release-verify-version/README.md) | [Release pipeline](RELEASE.md) | Run a command that prints a built artifact's version (`my-binary --version`) and require the output to match the release version, so a binary built from the wrong tree — or a tag that does not match the manifest — never reaches a publish step. By default the expected output is `<name> <version>` (the clap shape: the command's basename, then the version without its leading `v`); `expected` overrides it. A command that cannot run at all — missing library, crash, no such flag — fails the step even on a dry run: an artifact that does not execute is never publishable, and its exit code is never swallowed. A mismatch is a warning on a dry run, so a rehearsal reports what a real run would refuse and carries on, and a hard stop otherwise. Guide: .github/actions/RELEASE.md in megaeth-labs/.github. |
<!-- /generated -->
Expand Down
17 changes: 10 additions & 7 deletions .github/actions/RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ The choices that shape it:
create them.
- **One human gate.** The settle dispatch is the release decision. A
`release` GitHub environment on the settle job makes the run wait for its
required reviewers, and the action checks that the dispatching actor is
authorised (`settlers`). Everything after the click is mechanical.
required reviewers; that click is the approval. An optional `settlers`
list can additionally restrict who may start a settle. Everything after
the click is mechanical.
- **The changelog has one owner per phase.** The candidate PR drafts the
entry (`## vX.Y.Z`, no date) from merged PR titles and syncs the previous
release's final entry from its tag; settlement finalises it (date, any
Expand Down Expand Up @@ -113,8 +114,8 @@ click, the action verifies the commit is a full SHA, the release branch
exists, `v1.2.3` does not, the commit is the branch tip, the version file at
that commit says `1.2.3`, and `1.2.3` is newer than the latest tag. It warns
if the tip lacks a workflow the default branch has (see
[Operations](#operations-and-recovery)). It checks the dispatcher against
`settlers`. Then it regenerates the notes up to the tip, writes
[Operations](#operations-and-recovery)). If `settlers` is set, it checks
the dispatcher against it. Then it regenerates the notes up to the tip, writes
`## v1.2.3 (YYYY-MM-DD)` into the changelog, commits that straight onto
`release-v1.2.3` (the app bypasses the branch ruleset), creates the annotated
tag `v1.2.3` at that commit, and publishes the GitHub Release, marked latest,
Expand Down Expand Up @@ -213,8 +214,10 @@ same values in all three: `version_file` and `version_pattern`, and
`changelog_file` if not `CHANGELOG.md`. In `release-candidate.yml`, set
`bump_command` if anything else must move with the version, and install the
toolchain it needs in the `propose` job before the action step. Keep
`settle_mode: direct` and `settlers: admin` (or a list of logins) and the
`environment: release` line in the settle job. Keep `release-publish.yml`
`settle_mode: direct` and the `environment: release` line in the settle job;
add `settlers: admin` (or a list of logins) only if starting a settle should
be restricted beyond what the environment's reviewers approve. Keep
`release-publish.yml`
even though direct settlement never triggers it: it is the PR-mode fallback,
and its job gate rejects anything the app did not open.

Expand Down Expand Up @@ -260,7 +263,7 @@ toolchain it needs. Examples in use:

| `settle_mode` | Decision | Requirements |
|---|---|---|
| `direct` (the templates) | the dispatch, approved through the `release` environment and checked against `settlers` | `settlers`: comma-separated logins and/or `admin` (the dispatcher must have admin permission, checked with the job token); the app bypasses the release-branch ruleset |
| `direct` (the templates) | the dispatch, approved through the `release` environment | the environment's required reviewers; the app bypasses the release-branch ruleset. `settlers` (default `any`) may additionally name who can start a settle: comma-separated logins and/or `admin` (the dispatcher must have admin permission, checked with the job token) |
| `pr` (the action default) | merging the settle PR | the release-branch ruleset requires a reviewed PR; `release-publish.yml` present on the release branch |

**Labels** (`pr_labels`, candidate and settle): for repositories whose
Expand Down
20 changes: 10 additions & 10 deletions .github/actions/release-settle/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
`uses: megaeth-labs/.github/.github/actions/release-settle@main`

<!-- generated: description -->
Propose settling a release candidate: verify `commit` is the tip of the release branch and carries the expected version, generate release notes from the commits since the previous tag, write them into the changelog (stamping the date onto the candidate's `## vX.Y.Z` entry), and — in the default `pr` mode — open a `chore/release-settle-vX.Y.Z` PR onto the release branch; merging that PR is the settlement decision and release-publish then tags the merge commit once. In `direct` mode the dispatch itself is the decision: the dispatching actor must be authorised by `settlers`, the changelog commit is pushed straight to the release branch (the app must be a bypass actor on that branch's ruleset), and release-publish runs immediately on that commit. Run as a step in a job the consumer owns; the consumer checks the repository out first (`fetch-depth: 0`, `persist-credentials: false`). Needs `gh` and `python3` on the runner. Guide: .github/actions/RELEASE.md in megaeth-labs/.github.
Propose settling a release candidate: verify `commit` is the tip of the release branch and carries the expected version, generate release notes from the commits since the previous tag, write them into the changelog (stamping the date onto the candidate's `## vX.Y.Z` entry), and — in the default `pr` mode — open a `chore/release-settle-vX.Y.Z` PR onto the release branch; merging that PR is the settlement decision and release-publish then tags the merge commit once. In `direct` mode the dispatch itself is the decision, gated by the `release` environment the consumer puts on the settle job (optionally also by `settlers`); the changelog commit is pushed straight to the release branch (the app must be a bypass actor on that branch's ruleset), and release-publish runs immediately on that commit. Run as a step in a job the consumer owns; the consumer checks the repository out first (`fetch-depth: 0`, `persist-credentials: false`). Needs `gh` and `python3` on the runner. Guide: .github/actions/RELEASE.md in megaeth-labs/.github.
<!-- /generated -->

Family: [Release pipeline](../RELEASE.md).
Expand All @@ -22,7 +22,7 @@ Family: [Release pipeline](../RELEASE.md).
| `release_branch_prefix` | no | `release-v` | Release branch name prefix; the branch is `<prefix>X.Y.Z`. |
| `changelog_file` | no | `CHANGELOG.md` | Changelog the entry is written to (Keep-a-Changelog style, newest first). |
| `settle_mode` | no | `pr` | `pr` (default): open a settle PR. `direct`: settle and publish now, from this dispatch. |
| `settlers` | no | | Who may settle in `direct` mode: comma-separated GitHub logins, and/or the keyword `admin` (the dispatching actor must have admin permission on the repository, checked with `github_token`). Required for `direct`. |
| `settlers` | no | `any` | Who may settle in `direct` mode. `any` (default): no actor check — the settle job's `release` environment and its required reviewers are the gate, so use it only with `environment:` on that job. Otherwise a comma-separated list of GitHub logins and/or the keyword `admin` (the dispatching actor must have admin permission on the repository, checked with `github_token`), as an extra restriction on who may start a settle. |
| `github_token` | no | `${{ github.token }}` | Job token used for the `admin` permission check in `direct` mode. |
| `pr_labels` | no | | Comma-separated labels for the settle PR (for repos whose label gates apply to release branches too). |
| `git_user_name` | no | `mega-maxwell[bot]` | Committer identity for the commits this action makes. |
Expand Down Expand Up @@ -65,7 +65,6 @@ Family: [Release pipeline](../RELEASE.md).
- `$COMMIT is not the tip of $branch (tip is $tip). Settle the tip, or move the branch first.`
- `$FILE at $COMMIT says $actual, expected $version`
- `$version is not newer than the latest tag ${latest:-<none>}`
- `settle_mode: direct requires settlers (logins and/or`
- `$ACTOR is not authorised to settle directly (settlers: $SETTLERS)`
- `$CHANGELOG already carries exactly this v$VERSION entry; nothing to settle`
- `could not push the settle commit to $BRANCH — the branch moved since $COMMIT, or the app is not a bypass actor on its ruleset`
Expand All @@ -87,11 +86,11 @@ reviewers before this step runs:
version_pattern: toml
changelog_file: CHANGELOG.md
settle_mode: direct
settlers: admin
# settlers: admin # optional extra restriction on who may start a settle
```

Leave out `settle_mode` and `settlers` (and the job's `environment:`) to
settle by PR instead.
Leave out `settle_mode` (and the job's `environment:`) to settle by PR
instead.

## Notes

Expand All @@ -100,10 +99,11 @@ settle by PR instead.
says the version; the version is newer than the latest `v*` tag. Then a
warning if `commit` lacks a workflow the default branch has (a `release`
event runs `on-release.yml` from the tag's tree).
- `direct`: the dispatcher must match `settlers`; the dated entry is
committed straight onto the release branch (the app must bypass its
ruleset) and `release-publish` runs in the same job with `commit` and
`version` set.
- `direct`: the settle job's `release` environment reviewers are the gate
(`settlers: any`, the default); a login list or `admin` in `settlers`
additionally checks the dispatcher. The dated entry is committed straight
onto the release branch (the app must bypass its ruleset) and
`release-publish` runs in the same job with `commit` and `version` set.
- `pr`: pushes `chore/release-settle-vX.Y.Z` and opens the settle PR. A
re-run closes the previous settle PR, deletes its branch and pushes a fresh
one; nothing is force-pushed.
Expand Down
25 changes: 15 additions & 10 deletions .github/actions/release-settle/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ description: >-
`pr` mode — open a `chore/release-settle-vX.Y.Z` PR onto the release
branch; merging that PR is the settlement decision and release-publish
then tags the merge commit once. In `direct` mode the dispatch itself is
the decision: the dispatching actor must be authorised by `settlers`, the
changelog commit is pushed straight to the release branch (the app must be
a bypass actor on that branch's ruleset), and release-publish runs
immediately on that commit. Run as a step in a job the consumer owns; the
the decision, gated by the `release` environment the consumer puts on the
settle job (optionally also by `settlers`); the changelog commit is pushed
straight to the release branch (the app must be a bypass actor on that
branch's ruleset), and release-publish runs immediately on that commit. Run as a step in a job the consumer owns; the
consumer checks the repository out first (`fetch-depth: 0`,
`persist-credentials: false`). Needs `gh` and `python3` on the runner.
Guide: .github/actions/RELEASE.md in megaeth-labs/.github.
Expand Down Expand Up @@ -55,11 +55,15 @@ inputs:
default: pr
settlers:
description: >-
Who may settle in `direct` mode: comma-separated GitHub logins, and/or
the keyword `admin` (the dispatching actor must have admin permission
on the repository, checked with `github_token`). Required for `direct`.
Who may settle in `direct` mode. `any` (default): no actor check — the
settle job's `release` environment and its required reviewers are the
gate, so use it only with `environment:` on that job. Otherwise a
comma-separated list of GitHub logins and/or the keyword `admin` (the
dispatching actor must have admin permission on the repository, checked
with `github_token`), as an extra restriction on who may start a
settle.
required: false
default: ""
default: any
github_token:
description: "Job token used for the `admin` permission check in `direct` mode."
required: false
Expand Down Expand Up @@ -198,8 +202,9 @@ runs:
MODE: ${{ inputs.settle_mode }}
run: |
set -euo pipefail
if [[ -z "$SETTLERS" ]]; then
echo "::error::settle_mode: direct requires settlers (logins and/or 'admin')"; exit 1
if [[ -z "$SETTLERS" || "$SETTLERS" == "any" ]]; then
echo "settlers: any — no actor check; the settle job's environment reviewers are the gate"
exit 0
fi
ok=false
IFS=',' read -ra entries <<<"$SETTLERS"
Expand Down
17 changes: 9 additions & 8 deletions workflow-templates/release-settle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,17 @@ name: Release Settle
# 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.
# The dispatch is the settlement decision, gated by the `release`
# environment on the job: its required reviewers approve the run before it
# starts (give the environment a deployment branch policy of the default
# branch only). The app must be a bypass actor on the release-branch ruleset
# and on the `v*` tag ruleset. To also restrict who may *start* a settle, set
# `settlers` on the action (logins and/or `admin`); the default `any` relies
# on the environment alone.
#
# 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.
# `environment:` and `settle_mode` below.
#
# Guide: https://github.com/megaeth-labs/.github/blob/main/.github/actions/RELEASE.md

Expand Down Expand Up @@ -65,4 +66,4 @@ jobs:
version_pattern: plain
changelog_file: CHANGELOG.md
settle_mode: direct
settlers: admin
# settlers: admin # optional: also require the dispatcher to be an admin (or a listed login)
Loading