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
{{ message }}
Repository navigation
Commit 528e52e
Browse filesBrowse the repository at this point in the historyBrowse files
ci(release): generate release notes against an explicit previous tag
Release notes have restated every PR back to v0.16.0 since v0.17.1.
GitHub infers the notes base by walking tags newest-to-oldest and taking
the first whose commit is an ancestor of the one being released. Our
release tags never satisfy that: each points at a Package.swift rewrite
committed on a local release/vX.Y.Z branch that is never pushed, so no
release tag is reachable from any other. GitHub falls back to v0.16.0 —
the last tag that does sit on trunk, created before this flow existed.
Resolve the base explicitly instead. set_github_release cannot express
previous_tag_name, so call the generate-notes endpoint directly and pass
the result through as `description`.
The base is the most recent stable release older than the version being
published; prereleases are skipped as candidates, matching GitHub's
default. Resolution is also run in `validate`, before anything is
published, so a wrong base surfaces while a re-run is still free.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: docs/releases.md
+24-4Lines changed: 24 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -60,26 +60,46 @@ Step 1 prints the SHA of the version-bump commit it just pushed. Trigger a new B
60
60
61
61
Pinning the commit matters — if you leave it blank, Buildkite resolves `trunk` to HEAD at trigger time, and a concurrent merge would tag the wrong commit.
62
62
63
-
The build runs a `:white_check_mark: Validate Swift release` step early on (gated on `NEW_VERSION`) that fast-fails if the tag name is malformed, or if the tag or GitHub Release already exists. After that, the `:rocket: Publish Swift release` step:
63
+
The build runs a `:white_check_mark: Validate Swift release` step early on (gated on `NEW_VERSION`) that fast-fails if the tag name is malformed, if the tag or GitHub Release already exists, or if no previous release tag can be resolved to generate notes against. It logs the tag the notes will be based on, so a wrong base surfaces before anything is published. After that, the `:rocket: Publish Swift release` step:
64
64
65
65
1. Rewrites `Package.swift` to consume the binary target via `.release(version:, checksum:)`
66
66
1. Uploads the XCFramework to `s3://a8c-apps-public-artifacts/gutenbergkit/vX.Y.Z/`
67
67
1. Commits the rewrite on a local `release/vX.Y.Z` branch (never pushed to origin), tags `vX.Y.Z`, and pushes **only the tag** — `git push <tag>` carries the commit along with the tag ref, so the commit becomes reachable on origin via the tag alone
68
+
1. Generates release notes against the previous stable release tag (see [Release Notes](#release-notes))
68
69
1. Creates the GitHub Release against the now-existing tag, uploading the XCFramework + checksum as assets (adds `--prerelease` when the version contains `-`)
69
70
70
71
The tag is pushed before the GitHub Release is created. Once the tag is on origin, SPM consumers pinning `vX.Y.Z` can resolve a `Package.swift` that fetches the prebuilt XCFramework from CDN — the GH Release is metadata and an asset mirror on top of that.
71
72
72
-
The tag's commit lives off `trunk`'s history (parented on `trunk` but only reachable via the tag ref), matching the `pr-build/<n>` snapshot-branch shape but published under a tag instead of a branch.
73
+
The tag's commit lives off `trunk`'s history (parented on `trunk` but only reachable via the tag ref), matching the `pr-build/<n>` snapshot-branch shape but published under a tag instead of a branch. One consequence: release tags are not reachable from one another, so GitHub cannot infer which tag to generate release notes against and the release lane must pass one explicitly. See [Release Notes](#release-notes).
73
74
74
75
### Recovering from a partial publish
75
76
76
77
If the build fails before the tag is pushed (validate, Package.swift rewrite, S3 upload, or local commit/tag), no tag exists and no consumer can resolve `vX.Y.Z`. Re-run Step 2 with the same `NEW_VERSION` once the underlying issue is fixed — `validate` will pass (no tag, no release), and S3 uploads are idempotent (`if_exists: :replace`).
77
78
78
-
If the build fails specifically on `gh release create` (tag pushed, but GH Release missing), the tag is the source of truth: SPM consumers resolving `vX.Y.Z` already work. To create the missing Release page, re-run `gh release create vX.Y.Z --title vX.Y.Z --generate-notes [--prerelease] <xcframework.zip> <checksum.txt>` manually against the existing tag — re-running the full Buildkite step would fail at `validate` because the tag now exists.
79
+
If the build fails specifically on `gh release create` (tag pushed, but GH Release missing), the tag is the source of truth: SPM consumers resolving `vX.Y.Z` already work. To create the missing Release page, run the following manually against the existing tag — re-running the full Buildkite step would fail at `validate` because the tag now exists.
80
+
81
+
```bash
82
+
gh release create vX.Y.Z \
83
+
--title vX.Y.Z \
84
+
--generate-notes \
85
+
--notes-start-tag vPREVIOUS \
86
+
[--prerelease] \
87
+
<xcframework.zip><checksum.txt>
88
+
```
89
+
90
+
`--notes-start-tag` is required, and `vPREVIOUS` must be the previous **stable** release (skip any intervening prereleases). Omitting it silently restates every release back to `v0.16.0` — see [Release Notes](#release-notes).
79
91
80
92
## Release Notes
81
93
82
-
GitHub automatically generates release notes when a release is created. Notes are organized into the following categories based on PR labels:
94
+
GitHub generates the release notes, but the release lane tells it explicitly which tag to generate them against — it does not let GitHub infer the base.
95
+
96
+
GitHub's inference picks the most recent tag whose commit is an **ancestor** of the one being released. Our release tags never satisfy that: each one points at a `Package.swift` rewrite committed on a local `release/vX.Y.Z` branch that is never pushed, so no release tag is reachable from any other. Left to infer, GitHub falls back to the last tag that does sit on `trunk` — `v0.16.0` — and restates every PR merged since. So `previous_release_tag` in the `Fastfile` resolves the base instead:
97
+
98
+
- The most recent **stable** release older than the version being published
99
+
- Prereleases are skipped as candidates, matching GitHub's default. A stable release therefore reports everything since the last stable release, including work already listed in its own alphas
100
+
- If no such release exists, the lane fails rather than publishing notes that might restate old releases
101
+
102
+
Notes are organized into the following categories based on PR labels:
0 commit comments