You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: CONTRIBUTING.md
+43-11Lines changed: 43 additions & 11 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -126,29 +126,32 @@ The PR flow (introduced in 0.3.0) preserves an audit trail of every cask update;
126
126
127
127
- Repository secret `HOMEBREW_TAP_GITHUB_TOKEN` on `truestamp/truestamp-cli`. **This must be a fine-grained PAT scoped to `truestamp/homebrew-tap` only, with `Contents: Read and write` + `Pull requests: Read and write`.** Do not use a classic `repo`-scoped PAT — the classic scope is broader than the release pipeline needs and should not be reintroduced. The `Pull requests` scope is what lets GoReleaser open the cask update PR and what lets the follow-up step merge it.
128
128
-`mise install` locally so `task release-check` and `task release-snapshot` work for pre-flight testing.
129
+
-`protect-main` ruleset (repo Settings → Rules → Rulesets). Enforces linear history, blocks force-pushes and deletions, and **requires `Test (ubuntu-latest)` + `Test (macos-latest)` green on the exact SHA** before anything merges to `main`. The release flow below routes the CHANGELOG commit through a PR specifically to satisfy that rule. Release tags then trigger a second CI re-run (via `release.yml`'s `workflow_call` into `ci.yml`) before GoReleaser starts — two layers of "tests green on this SHA" before artifacts publish.
129
130
130
131
### Pre-flight checklist
131
132
132
133
```sh
133
134
# Working copy is clean and on top of the latest origin/main.
134
135
jj git fetch
135
-
jj log -r 'main@origin..@'# expect 0 commits not on origin
`release-snapshot` skips `sign` and `publish` because cosign keyless signing requires a GitHub OIDC token (only available inside the release workflow), and no dry-run should touch the GitHub Release API. Expect the `version` in the rendered cask to read `X.Y.Z-SNAPSHOT-<shortsha>` — that gets replaced with the real tag during the actual release.
151
+
149
152
### Update `CHANGELOG.md`
150
153
151
-
Move entries from `## [Unreleased]` into a new section for the version you're about to cut. Use today's date and the Keep-a-Changelog groupings. Add a matching link reference at the bottom.
154
+
Move entries from `## [Unreleased]` into a new section for the version you're about to cut. Use today's date and the Keep-a-Changelog groupings.
152
155
153
156
```md
154
157
## [Unreleased]
@@ -159,34 +162,63 @@ Move entries from `## [Unreleased]` into a new section for the version you're ab
159
162
- ...
160
163
```
161
164
162
-
### Commit and push the CHANGELOG
165
+
### Open a release PR for the CHANGELOG commit
163
166
164
-
This repo is a jj colocated workspace. Commit the CHANGELOG edit as a normal change and advance `main`:
167
+
The `protect-main` ruleset (see Prerequisites) requires CI checks to pass on the exact SHA before `main` accepts it, so the release commit must land via PR — direct `jj git push --bookmark main` is rejected with `GH013: Repository rule violations found`. This is by design: the PR gives CI a chance to run on the SHA that's about to be tagged.
165
168
166
169
```sh
167
-
jj describe -m "Prep release vX.Y.Z"
168
-
jj bookmark move main --to @
169
-
jj git push --bookmark main
170
+
# Commit the CHANGELOG edit.
171
+
jj describe -m "Release vX.Y.Z"
172
+
173
+
# Push to a release branch instead of directly to main.
174
+
jj bookmark create release-vX.Y.Z -r @
175
+
jj git push --bookmark release-vX.Y.Z
176
+
177
+
# Open the PR. Keep the title exactly "Release vX.Y.Z" — it's what
178
+
# the changelog and commit history expect.
179
+
gh pr create --base main --head release-vX.Y.Z \
180
+
--title "Release vX.Y.Z" \
181
+
--body "See CHANGELOG.md for the full release notes."
182
+
183
+
# Wait for CI to go green on the PR, then merge via rebase so the
184
+
# signed tag below points at the exact CHANGELOG commit (merge commits
185
+
# would introduce a different SHA, which the linear-history rule also
jj does not create annotated tags itself — use the git CLI in the same working copy (the jj repo is colocated with `.git/`):
197
+
jj does not create annotated tags itself — use the git CLI in the same working copy (the jj repo is colocated with `.git/`). Run `git tag -v` afterwards to confirm the tag was signed; the repo has `tag.gpgsign=true` + `user.signingkey` set, so plain `git tag -a` auto-signs.
175
198
176
199
```sh
177
200
git tag -a vX.Y.Z -m "vX.Y.Z - one-line summary of the headline change"
201
+
git tag -v vX.Y.Z # expect "Good 'git' signature ..." — abort if unsigned.
178
202
git push origin vX.Y.Z
179
203
```
180
204
181
205
The tag must point at the exact commit that `main` now holds, and must start with `v` so GoReleaser's trigger (`push: tags: ['v*']`) fires.
182
206
183
207
### Watch the release
184
208
209
+
The tag push triggers `release.yml`, which runs two top-level jobs:
210
+
211
+
1.`ci` — `workflow_call` into `ci.yml`, re-running the full lint + test matrix on the tagged SHA. If this fails, nothing publishes.
212
+
2.`goreleaser` (needs: ci) — runs `goreleaser check`, then a `--snapshot --clean` dry-run (local cross-compile + SBOM + cask template render, surfaces platform-specific breakage before the real publish), then the real `goreleaser release --clean`, then the homebrew-tap PR merge, then build-provenance attestation.
213
+
214
+
Total runtime: ~7-9 minutes (CI gate 3-5 min + snapshot ~1 min + real release ~2-3 min).
215
+
185
216
```sh
186
217
run_id=$(gh run list --workflow=release.yml --limit 1 --json databaseId -q '.[].databaseId')
Copy file name to clipboardExpand all lines: Taskfile.yml
+2-2Lines changed: 2 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -298,9 +298,9 @@ tasks:
298
298
- mise exec -- goreleaser check
299
299
300
300
release-snapshot:
301
-
desc: Build a local snapshot release into dist/ (no publishing, no network)
301
+
desc: "Local snapshot release into dist/ — skips cosign signing (keyless requires the CI OIDC token) and GitHub publishing, so this runs fully offline and is safe for pre-release inspection."
302
302
cmds:
303
-
- mise exec -- goreleaser release --snapshot --clean
303
+
- mise exec -- goreleaser release --snapshot --clean --skip=sign,publish
0 commit comments