Skip to content

Commit e2337a1

Browse files
Include versioned release notes in GitHub release descriptions.
1 parent 42957ef commit e2337a1

7 files changed

Lines changed: 78 additions & 2 deletions

File tree

‎bake-gem-github.gemspec‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Gem::Specification.new do |spec|
1414
spec.files = Dir.glob(["{bake,context,lib,templates}/**/*", "*.md", "release.cert"], base: __dir__)
1515
spec.required_ruby_version = ">= 3.3"
1616
spec.add_dependency "bake-gem", ">= 0.15.0"
17+
spec.add_dependency "bake-releases", "~> 0.6"
1718
spec.add_dependency "net-http"
1819
spec.add_dependency "bake", "~> 0.25"
1920
end

‎context/getting-started.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ After merge/squash, the publishing workflow verifies GitHub's merged PR record a
7575

7676
The workflow retains the gem, receipt and attestations before obtaining RubyGems publishing credentials. It verifies both attestations, checks the uploaded bytes and registry bundle, then pushes the specific version tag and creates the GitHub release. Existing tags/assets are checked and never overwritten. The old `after_gem_release` GitHub hook is not called by this pipeline, so there is one owner for release creation.
7777

78+
The draft release description includes the exact version's notes from `releases.md` in the merged release checkout, followed by the PR URL, source commit, and gem digest. Notes are extracted using `bake-releases`; a missing or empty section leaves the metadata as the description. Retries preserve the existing release description.
79+
7880
``` bash
7981
set -e
8082
for file in example-1.2.3.gem release.json; do

‎gems.rb‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,5 @@
1515

1616
group :maintenance, optional: true do
1717
gem "agent-context"
18-
gem "bake-releases"
1918
gem "utopia-project"
2019
end

‎guides/getting-started/readme.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ After merge/squash, the publishing workflow verifies GitHub's merged PR record a
7575

7676
The workflow retains the gem, receipt and attestations before obtaining RubyGems publishing credentials. It verifies both attestations, checks the uploaded bytes and registry bundle, then pushes the specific version tag and creates the GitHub release. Existing tags/assets are checked and never overwritten. The old `after_gem_release` GitHub hook is not called by this pipeline, so there is one owner for release creation.
7777

78+
The draft release description includes the exact version's notes from `releases.md` in the merged release checkout, followed by the PR URL, source commit, and gem digest. Notes are extracted using `bake-releases`; a missing or empty section leaves the metadata as the description. Retries preserve the existing release description.
79+
7880
``` bash
7981
set -e
8082
for file in example-1.2.3.gem release.json; do

‎lib/bake/gem/github/publisher.rb‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
# Copyright, 2026, by Samuel Williams.
55

66
require_relative "project"
7+
require "bake/releases"
78
require "digest"
89
require "net/http"
910
require "openssl"
@@ -146,10 +147,12 @@ def preserve_release(receipt)
146147
tag = "v#{receipt.fetch(:version)}"
147148
release = github_release(tag)
148149
unless release
150+
notes = Bake::Releases.notes(tag, path: File.join(@root, "releases.md"))
151+
metadata = "#{receipt.fetch(:pull_request_url)}\n\nSource: #{receipt.fetch(:commit)}\nSHA256: #{receipt.fetch(:sha256)}\n"
149152
Tempfile.create("release") do |file|
150153
file.write(JSON.generate(
151154
tag_name: tag, draft: true, target_commitish: receipt.fetch(:commit), name: "#{receipt.fetch(:name)} #{tag}",
152-
body: "#{receipt.fetch(:pull_request_url)}\n\nSource: #{receipt.fetch(:commit)}\nSHA256: #{receipt.fetch(:sha256)}\n\nSee releases.md at the release tag for release notes.\n"
155+
body: [notes, metadata].compact.join("\n")
153156
))
154157
file.flush
155158
# The release list can remain stale after a successful creation:

‎releases.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## Unreleased
44

5+
- Include the version's release notes in GitHub releases using `bake-releases`.
56
- Update generated release files in the working tree with `gem:github:setup:update`.
67

78
## v0.0.5

‎test/bake/gem/github/publisher/recovery.rb‎

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,74 @@ def restore
2929
Bake::Context.load(root).call("gem:github:release:build", "number=42")
3030
end
3131

32+
it "includes notes for the exact released version before the artifact metadata" do
33+
File.write(File.join(root, "releases.md"), <<~MARKDOWN)
34+
# Releases
35+
36+
## Unreleased
37+
38+
Future changes.
39+
40+
## v2.0.0
41+
42+
Newer release.
43+
44+
## v1.0.1
45+
46+
- Fixed a `bug`.
47+
48+
### Details
49+
50+
Read the [guide](https://example.com/guide).
51+
52+
## v1.0.0
53+
54+
Older release.
55+
MARKDOWN
56+
57+
receipt = @publisher.publish(42)
58+
59+
expect(@publisher.releases.first.fetch("body")).to be == <<~MARKDOWN
60+
- Fixed a `bug`.
61+
62+
## Details
63+
64+
Read the [guide](https://example.com/guide).
65+
66+
https://github.com/socketry/example/pull/42
67+
68+
Source: #{receipt.fetch(:commit)}
69+
SHA256: #{receipt.fetch(:sha256)}
70+
MARKDOWN
71+
end
72+
73+
it "uses the artifact metadata when release notes are missing" do
74+
receipt = @publisher.publish(42)
75+
76+
expect(@publisher.releases.first.fetch("body")).to be == <<~MARKDOWN
77+
https://github.com/socketry/example/pull/42
78+
79+
Source: #{receipt.fetch(:commit)}
80+
SHA256: #{receipt.fetch(:sha256)}
81+
MARKDOWN
82+
end
83+
84+
it "preserves the existing draft description when finalization is retried" do
85+
File.write(File.join(root, "releases.md"), "## v1.0.1\n\nOriginal notes.\n")
86+
@publisher.fail_release = true
87+
expect{@publisher.publish(42)}.to raise_exception(RuntimeError, message: be =~ /GitHub unavailable/)
88+
body = @publisher.releases.first.fetch("body") + "\nMaintainer addition.\n"
89+
@publisher.releases.first["body"] = body
90+
@publisher.fail_release = false
91+
restore
92+
93+
@publisher.publish(42)
94+
95+
expect(@publisher.releases.size).to be == 1
96+
expect(@publisher.releases.first.fetch("body")).to be == body
97+
expect(@publisher.releases.first.fetch("draft")).to be == false
98+
end
99+
32100
it "resumes finalization after upload without uploading or rebuilding again" do
33101
@publisher.fail_release = true
34102
expect{@publisher.publish(42)}.to raise_exception(RuntimeError, message: be =~ /GitHub unavailable/)

0 commit comments

Comments
 (0)