bake-gem 0.13.1 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1921512c8e66685c7ced03e581fa8ecafea58e93720540dc80dd6ee84ebafaf9
4
- data.tar.gz: 9ffa14838c160f994189bf54499420a891c6364d7629834c88b9babafdf30237
3
+ metadata.gz: 847773b347cc41d5b64aa246a96fc3770e932f15fe53121538156327a8e67a9f
4
+ data.tar.gz: e0396526fe9584882269a7326e99614885cc4e6f4c755d064e8cbf1f8af2e054
5
5
  SHA512:
6
- metadata.gz: 76ef768494dcf189e0aaf4651a7c3c03bc0d5f4bcd0e87ccb5fd5c890f8d20b49ffb2149e523ae912d752a15ad2614f8dd2a1aaf6d0b5091890d749d9fac105e
7
- data.tar.gz: 27740a73d10724a9b88d5bf880621a4c80e644ad5a6accd714b4014b67ba055e1548a0d9a8c83accd08ecddafb892bf7c64ce269ca55a05d8e876739e606635e
6
+ metadata.gz: 4b18cd961a2cfd4fc06bec5ed0389c6b3d1b8eb65ace189ae393c7bf6ab9838711322f82dad8e17cb62a69937d35e4f3a2ad15a9c4c19d0053182d6dc2d02abf
7
+ data.tar.gz: 51874bafe6a43e93c62f464502e074974df47a5d03ec7e7c204c7e0cfa730f0bcaaedf27c9e63e4bd375f81b84732404426a0dc95d94f914d06d80eeffa9d2fd
checksums.yaml.gz.sig CHANGED
Binary file
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2021-2025, by Samuel Williams.
4
+ # Copyright, 2021-2026, by Samuel Williams.
5
5
 
6
6
  # Increment the patch number of the current version.
7
7
  def patch
@@ -25,21 +25,15 @@ end
25
25
  def commit(bump, message: "Bump version.")
26
26
  release = context.lookup("gem:release")
27
27
  helper = release.instance.helper
28
- gemspec = helper.gemspec
29
-
30
- # helper.guard_clean
31
-
32
- version_path = context.lookup("gem:release:version:increment").call(bump, message: message)
33
-
34
- if version_path
35
- branch_name = helper.create_release_branch(version_path, message: message)
36
- else
37
- raise "Could not find version number!"
38
- end
39
-
40
- return {
41
- version: gemspec.version,
42
- version_path: version_path,
43
- branch: branch_name,
44
- }
28
+ helper.guard_clean
29
+ helper.guard_last_commit_not_version_bump
30
+ path = helper.version_path or raise "Could not find version file!"
31
+ line = File.read(File.expand_path(path, helper.root))
32
+ version = nil
33
+ Bake::Gem::Version.update_version(line){|current| version = current.increment(bump)}
34
+ raise "Could not find version number!" unless version
35
+ branch_name = helper.create_release_branch(version: version.join)
36
+ result = context.lookup("gem:release:version:increment").call(bump, message: message)
37
+ helper.commit_version_changes(message: message)
38
+ return result.merge(branch: branch_name)
45
39
  end
@@ -27,7 +27,7 @@ def increment(bump, message: "Bump version.")
27
27
  helper = release.instance.helper
28
28
  gemspec = helper.gemspec
29
29
 
30
- helper.update_version(bump) do |version|
30
+ version_path = helper.update_version(bump) do |version|
31
31
  Console.info(self, "Updated version:", version: version)
32
32
 
33
33
  # Ensure that any subsequent tasks use the correct version!
@@ -35,10 +35,12 @@ def increment(bump, message: "Bump version.")
35
35
 
36
36
  after_increment(version)
37
37
  end
38
+ raise "Could not find version number!" unless version_path
39
+ helper.guard_release_changes
38
40
 
39
41
  return {
40
42
  version: gemspec.version,
41
- version_path: helper.version_path,
43
+ version_path: version_path,
42
44
  }
43
45
  end
44
46
 
@@ -52,18 +54,9 @@ def commit(bump, message: "Bump version.")
52
54
 
53
55
  helper.guard_clean
54
56
 
55
- version_path = increment(bump, message: message)
56
-
57
- if version_path
58
- helper.commit_version_changes(message: message)
59
- else
60
- raise "Could not find version number!"
61
- end
62
-
63
- return {
64
- version: helper.gemspec.version,
65
- version_path: version_path,
66
- }
57
+ result = increment(bump, message: message)
58
+ helper.commit_version_changes(message: message)
59
+ return result
67
60
  end
68
61
 
69
62
  protected
data/bake/gem/release.rb CHANGED
@@ -35,3 +35,13 @@ def major(tag: true)
35
35
  release_task = context.lookup("gem:release")
36
36
  release_task.call(tag: tag)
37
37
  end
38
+
39
+ # Regenerate release content from the base commit and compare it with the candidate.
40
+ # @parameter base [String] The current target commit (first parent when publishing).
41
+ # @parameter candidate [String] The proposed or merged release commit.
42
+ # @parameter optional [Boolean] Accept ordinary PRs with no version change.
43
+ def validate(base:, candidate: "HEAD", optional: false)
44
+ require_relative "../../lib/bake/gem/helper"
45
+ require_relative "../../lib/bake/gem/release"
46
+ Bake::Gem::Release.new(context.root).validate(base: base, candidate: candidate, optional: optional)
47
+ end
data/bake/gem.rb CHANGED
@@ -21,18 +21,36 @@ def files
21
21
  @helper.gemspec.files
22
22
  end
23
23
 
24
+ # Inspect the gem name, version, and version file in the current checkout.
25
+ def metadata
26
+ gemspec = @helper.gemspec
27
+ raise "No gemspec found." unless gemspec
28
+
29
+ return {name: gemspec.name, version: gemspec.version.to_s, version_path: @helper.version_path}
30
+ end
31
+
24
32
  # Build the gem into the pkg directory.
25
33
  # @parameter root [String] The root directory to build the gem into. Defaults to `pkg`.
26
- # @parameter signing_key [Boolean] Whether to use a signing key.
34
+ # @parameter signing_key [String | Nil] A signing key path, "true" to require signing, or "false" to disable signing.
27
35
  def build(root: "pkg", signing_key: nil)
36
+ # Accept boolean command line options while preserving signing key paths:
37
+ signing_key = true if signing_key == "true"
38
+ signing_key = false if signing_key == "false"
39
+
28
40
  @helper.build_gem(root: root, signing_key: signing_key)
29
41
  end
30
42
 
31
43
  # Build and install the gem into system gems.
32
44
  # @parameter local [Boolean] only use locally available caches.
33
45
  def install(local: false)
34
- # For installing the gem, don't bother with signinng it:
35
- path = @helper.build_gem(signing_key: false)
46
+ changes = @helper.uncommitted_changes
47
+
48
+ if changes.any?
49
+ Console.warn(self, "Installing from clean git worktree; uncommitted changes are not included in the installed gem.", changes: changes.map(&:chomp))
50
+ end
51
+
52
+ # For installing the gem, don't bother with signing it:
53
+ path = @helper.build_gem_in_worktree(signing_key: false)
36
54
 
37
55
  arguments = []
38
56
  arguments << "--local" if local
@@ -64,7 +82,7 @@ def release(tag: true)
64
82
  raise
65
83
  end
66
84
 
67
- @helper.push_release(current_branch: current_branch)
85
+ @helper.push_release(current_branch: current_branch, tag: tag_name)
68
86
  context["after_gem_release"]&.call(name: @helper.gemspec.name, version: version, tag: tag_name, path: path)
69
87
 
70
88
  return {
@@ -20,6 +20,8 @@ end
20
20
 
21
21
  ## Usage
22
22
 
23
+ Run Bake tasks from the gem project's root directory. When using `Bake::Gem::Helper` directly, construct and use it with that directory as the process's working directory. Gemspec evaluation and packaging resolve relative paths there; the helper does not change the working directory.
24
+
23
25
  Before using `bake-gem`, ensure you have:
24
26
 
25
27
  1. A properly configured `gemspec` file in your project root
@@ -73,7 +75,7 @@ $ bake gem:release
73
75
 
74
76
  ### Automated CI/CD Pipeline
75
77
 
76
- For releasing gems via automated pipelines, use a two-step process:
78
+ Use `bake-gem-github` for GitHub pull requests, native approval rules, Trusted Publishing and attestations. The provider-independent preparation tasks below work identically locally and in CI.
77
79
 
78
80
  #### Step 1: Create Release Branch (Locally)
79
81
 
@@ -83,22 +85,25 @@ $ bake gem:release:branch:patch # or minor/major
83
85
  ```
84
86
 
85
87
  This will:
86
- - Create a new branch named `releases/v[new-version]`
88
+ - Require a clean checkout on a branch
89
+ - Create a new branch named `releases/v[new-version]` before modifying files
87
90
  - Bump the gem version
88
- - Commit the version change
89
- - Push the branch to origin
91
+ - Run `after_gem_release_version_increment` and commit all changes, including added and deleted documentation
92
+
93
+ This task does not push, open a PR, create tags or publish. Select a current base before running it; the GitHub companion additionally fetches and checks the default branch. Failed hooks leave changes available for inspection.
90
94
 
91
95
  #### Step 2: Release from CI (After Merge)
92
96
 
93
- Once the release branch is merged into main:
97
+ The GitHub companion handles publishing the exact merged commit. To independently validate release content, supply the current target commit and proposed commit:
94
98
 
95
99
  ``` bash
96
- $ export RUBYGEMS_HOST=https://rubygems.org
97
- $ export GEM_HOST_API_KEY=your_api_key
98
-
99
- $ bake gem:release
100
+ $ bundle exec bake gem:release:validate base=origin/main candidate=HEAD
100
101
  ```
101
102
 
103
+ Validation creates a temporary checkout of the base, applies the proposed patch/minor/major bump, runs the same hooks, and compares the complete generated tree with the candidate. It never bumps the candidate again or modifies your checkout. Stale notes and unexpected file additions/deletions fail with a diff. A rebase passes when the generated content still matches. Hooks must be repeatable for the same source and version.
104
+
105
+ For an ordinary PR check, add `optional=true` to accept candidates without a version change. After merge, use the merged commit's first parent as `base` and the merged commit as `candidate`; later changes on `main` do not affect that release boundary.
106
+
102
107
  ### Individual Commands
103
108
 
104
109
  You can also run individual steps:
@@ -113,6 +118,9 @@ $ bake gem:install
113
118
  # List files that will be included in the gem
114
119
  $ bake gem:files
115
120
 
121
+ # Inspect the gem name, version, and version file as JSON
122
+ $ bake gem:metadata output format=json
123
+
116
124
  # Build without signing
117
125
  $ bake gem:build signing_key=false
118
126
  ```
@@ -127,6 +135,8 @@ The tool automatically prevents consecutive version bumps by checking the last c
127
135
  ### Clean Worktree Building
128
136
  Gems are built in isolated git worktrees to ensure the build environment exactly matches your committed code, preventing issues with uncommitted changes affecting the build.
129
137
 
138
+ Worktree builds and release validation run Bake tasks in fresh Ruby processes launched with the checkout as their working directory, so version constants and hook state come from each checkout. The parent process's working directory is unchanged.
139
+
130
140
  ### Repository Cleanliness Check
131
141
  Before any release operation, the tool ensures your repository has no uncommitted changes.
132
142
 
@@ -141,6 +151,12 @@ spec.signing_key = "path/to/private_key.pem"
141
151
  spec.cert_chain = ["path/to/certificate.pem"]
142
152
  ```
143
153
 
154
+ To supply a signing key when building:
155
+
156
+ ``` bash
157
+ $ bake gem:build signing_key=/path/to/private_key.pem
158
+ ```
159
+
144
160
  Or disable signing explicitly:
145
161
 
146
162
  ``` bash
@@ -186,11 +202,9 @@ $ bake gem:release:patch
186
202
  # Create release branch
187
203
  $ bake gem:release:branch:minor
188
204
  # Creates branch: releases/v1.3.0
189
- # Commits version bump
190
- # Pushes branch
205
+ # Commits the version bump and release-hook output
206
+ # Leaves the branch local for inspection
191
207
 
192
- # After code review and merge:
193
- $ git checkout main
194
- $ git pull
195
- $ bake gem:release
208
+ # Validate before pushing or opening a PR:
209
+ $ bake gem:release:validate base=main
196
210
  ```
data/context/index.yaml CHANGED
@@ -3,6 +3,8 @@
3
3
  ---
4
4
  description: Release management for Ruby gems.
5
5
  metadata:
6
+ bug_tracker_uri: https://github.com/ioquatix/bake-gem/issues
7
+ changelog_uri: https://github.com/ioquatix/bake-gem/blob/main/releases.md
6
8
  documentation_uri: https://ioquatix.github.io/bake-gem/
7
9
  funding_uri: https://github.com/sponsors/ioquatix/
8
10
  source_code_uri: https://github.com/ioquatix/bake-gem.git
@@ -82,11 +82,13 @@ module Bake
82
82
  end
83
83
 
84
84
  # Helper class for performing gem-related operations like building, installing, and publishing gems.
85
+ # The process must already be in the gem project's root directory when constructing and using a helper.
86
+ # Gemspec evaluation and packaging resolve relative paths against that working directory; the helper does not change it.
85
87
  class Helper
86
88
  include Shell
87
89
 
88
90
  # Initialize a new helper with the specified root directory and optional gemspec.
89
- # @parameter root [String] The root directory of the gem project.
91
+ # @parameter root [String] The root directory of the gem project, which must also be the process's working directory.
90
92
  # @parameter gemspec [Gem::Specification | Nil] The gemspec to use, or nil to find it automatically.
91
93
  def initialize(root = Dir.pwd, gemspec: nil)
92
94
  @root = root
@@ -127,7 +129,8 @@ module Bake
127
129
  # Guard against consecutive version bumps
128
130
  guard_last_commit_not_version_bump
129
131
 
130
- lines = File.readlines(version_path)
132
+ path = File.expand_path(version_path, @root)
133
+ lines = File.readlines(path)
131
134
  new_version = nil
132
135
 
133
136
  lines.each do |line|
@@ -137,7 +140,7 @@ module Bake
137
140
  end
138
141
 
139
142
  if new_version
140
- File.write(version_path, lines.join)
143
+ File.write(path, lines.join)
141
144
 
142
145
  if block_given?
143
146
  yield new_version
@@ -151,7 +154,7 @@ module Bake
151
154
  # @returns [Boolean] True if the repository is clean.
152
155
  # @raises [RuntimeError] If there are uncommitted changes in the repository.
153
156
  def guard_clean
154
- lines = readlines("git", "status", "--porcelain", chdir: @root)
157
+ lines = uncommitted_changes
155
158
 
156
159
  if lines.any?
157
160
  raise "Repository has uncommited changes!\n#{lines.join('')}"
@@ -160,6 +163,12 @@ module Bake
160
163
  return true
161
164
  end
162
165
 
166
+ # Get the list of uncommitted changes in the repository.
167
+ # @returns [Array(String)] The porcelain status lines for uncommitted changes.
168
+ def uncommitted_changes
169
+ readlines("git", "status", "--porcelain", chdir: @root)
170
+ end
171
+
163
172
  # Verify that the last commit was not a version bump.
164
173
  # @returns [Boolean] True if the last commit was not a version bump.
165
174
  # @raises [RuntimeError] If the last commit was a version bump.
@@ -188,6 +197,7 @@ module Bake
188
197
  # @returns [String] The path to the built gem package.
189
198
  def build_gem(root: "pkg", signing_key: nil)
190
199
  # Ensure the output directory exists:
200
+ root = File.expand_path(root, @root)
191
201
  FileUtils.mkdir_p(root)
192
202
 
193
203
  output_path = File.join(root, @gemspec.file_name)
@@ -222,7 +232,7 @@ module Bake
222
232
  # @parameter signing_key [String | Nil] The signing key to use for signing the package.
223
233
  # @returns [String] The path to the built gem package.
224
234
  def build_gem_in_worktree(root: "pkg", signing_key: nil)
225
- original_pkg_path = File.join(@root, root)
235
+ original_pkg_path = File.expand_path(root, @root)
226
236
 
227
237
  # Create a unique temporary path for the worktree
228
238
  timestamp = Time.now.strftime("%Y%m%d-%H%M%S-%N")
@@ -230,15 +240,13 @@ module Bake
230
240
 
231
241
  begin
232
242
  # Create worktree from current HEAD
233
- unless system("git", "worktree", "add", worktree_path, "HEAD", chdir: @root)
243
+ unless system("git", "worktree", "add", "--detach", worktree_path, "HEAD", chdir: @root)
234
244
  raise "Failed to create git worktree. Make sure you have at least one commit in the repository."
235
245
  end
236
246
 
237
- # Create helper for the worktree
238
- worktree_helper = self.class.new(worktree_path)
239
-
240
- # Build gem directly into the target pkg directory
241
- output_path = worktree_helper.build_gem(root: original_pkg_path, signing_key: signing_key)
247
+ # Build using the worktree's gemspec in a fresh interpreter:
248
+ require_relative "release"
249
+ output_path = Release.new(@root).bake(worktree_path, "gem:build", root: original_pkg_path, signing_key: signing_key)
242
250
 
243
251
  output_path
244
252
  ensure
@@ -247,16 +255,16 @@ module Bake
247
255
  end
248
256
  end
249
257
 
250
- # Create a release branch, add the version file, and commit the changes.
251
- # @parameter version_path [String] The path to the version file that was updated.
252
- # @parameter message [String] The commit message to use.
258
+ # Create a release branch before generating release changes.
259
+ # @parameter version [String] The proposed release version.
253
260
  # @returns [String] The name of the created branch.
254
- def create_release_branch(version_path, message: "Bump version.")
255
- branch_name = "release-v#{@gemspec.version}"
261
+ def create_release_branch(version:)
262
+ guard_clean
263
+ raise "Release preparation requires a branch checkout." unless current_branch
264
+ branch_name = "releases/v#{version}"
265
+ raise "Release tag v#{version} already exists." unless readlines("git", "tag", "--list", "v#{version}", chdir: @root).empty?
256
266
 
257
267
  system("git", "checkout", "-b", branch_name, chdir: @root)
258
- system("git", "add", version_path, chdir: @root)
259
- system("git", "commit", "-m", message, chdir: @root)
260
268
 
261
269
  return branch_name
262
270
  end
@@ -264,10 +272,25 @@ module Bake
264
272
  # Commit version changes to the current branch.
265
273
  # @parameter message [String] The commit message to use.
266
274
  def commit_version_changes(message: "Bump version.")
275
+ guard_release_changes
267
276
  system("git", "add", "--all", chdir: @root)
268
277
  system("git", "commit", "-m", message, chdir: @root)
269
278
  end
270
279
 
280
+ # Reject generated package output and private keys before staging release changes.
281
+ def guard_release_changes
282
+ paths = readlines("git", "diff", "--name-only", "--diff-filter=ACM", "-z", "HEAD", chdir: @root).join.split("\0")
283
+ paths.concat(readlines("git", "ls-files", "--others", "--exclude-standard", "-z", chdir: @root).join.split("\0"))
284
+ paths.uniq.each do |path|
285
+ raise "Release changes include build output: #{path}" if path.start_with?("pkg/") || path.end_with?(".gem")
286
+ absolute = File.expand_path(path, @root)
287
+ next unless File.file?(absolute) && !File.symlink?(absolute)
288
+ if File.binread(absolute).match?(/^-----BEGIN (?:[A-Z]+ )?PRIVATE KEY-----/)
289
+ raise "Release changes include a private key: #{path}"
290
+ end
291
+ end
292
+ end
293
+
271
294
  # Fetch remote tags and create a release tag for the specified version.
272
295
  # @parameter tag [Boolean] Whether to tag the release.
273
296
  # @parameter version [String] The version to tag.
@@ -292,13 +315,13 @@ module Bake
292
315
 
293
316
  # Push changes and tags to the remote repository.
294
317
  # @parameter current_branch [String | Nil] The current branch name, or nil if not on a branch.
295
- def push_release(current_branch: nil)
318
+ def push_release(current_branch: nil, tag: nil)
296
319
  # If we are on a branch, push, otherwise just push the tags (assuming shallow checkout):
297
320
  if current_branch
298
321
  system("git", "push", chdir: @root)
299
322
  end
300
323
 
301
- system("git", "push", "--tags", chdir: @root)
324
+ system("git", "push", "origin", "refs/tags/#{tag}", chdir: @root) if tag
302
325
  end
303
326
 
304
327
  # Figure out if there is a current branch, if not, return `nil`.
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2026, by Samuel Williams.
5
+
6
+ require_relative "helper"
7
+ require "json"
8
+ require "tmpdir"
9
+
10
+ module Bake
11
+ module Gem
12
+ # Regenerates release content from its base without modifying the checkout.
13
+ class Release
14
+ include Shell
15
+
16
+ # Supported stable version increments.
17
+ BUMPS = {"patch" => [nil, nil, 1], "minor" => [nil, 1, 0], "major" => [1, 0, 0]}.freeze
18
+
19
+ # @parameter root [String] The repository containing the commits to compare.
20
+ def initialize(root)
21
+ @root = File.expand_path(root)
22
+ end
23
+
24
+ # Resolve a commit before passing it to other Git commands.
25
+ def resolve(reference)
26
+ git("rev-parse", "--verify", "--end-of-options", "#{reference}^{commit}").strip
27
+ end
28
+
29
+ # Yield a temporary detached worktree and remove it even on failure.
30
+ def worktree(reference)
31
+ commit = resolve(reference)
32
+ Dir.mktmpdir("bake-gem-release-") do |directory|
33
+ path = File.join(directory, "source")
34
+ system("git", "worktree", "add", "--detach", path, commit, chdir: @root, out: File::NULL)
35
+ begin
36
+ yield path
37
+ ensure
38
+ system("git", "worktree", "remove", "--force", path, chdir: @root, out: File::NULL)
39
+ end
40
+ end
41
+ end
42
+
43
+ # Run Bake tasks in a fresh interpreter, avoiding cached version constants.
44
+ # @parameter path [String] The checkout in which to run the tasks.
45
+ # @parameter arguments [Array(String)] Task names and command line arguments.
46
+ # @parameter options [Hash] Task options; nil values use the task defaults.
47
+ def bake(path, *arguments, **options)
48
+ Dir.mktmpdir("bake-gem-result-") do |directory|
49
+ result = File.join(directory, "result.json")
50
+ options.each{|key, value| arguments << "#{key}=#{value}" unless value.nil?}
51
+ system("bake", *arguments, "output", "file=#{result}", "format=json", chdir: path)
52
+ JSON.parse(File.read(result), symbolize_names: true)
53
+ end
54
+ end
55
+
56
+ # Inspect a committed gem in isolation.
57
+ def metadata(reference)
58
+ worktree(reference) {|path| bake(path, "gem:metadata")}
59
+ end
60
+
61
+ # Validate an ordinary patch, minor, or major transition.
62
+ def bump(previous, target)
63
+ unless previous.match?(/\A\d+\.\d+\.\d+\z/) && target.match?(/\A\d+\.\d+\.\d+\z/)
64
+ raise "Release validation supports stable three-part versions only."
65
+ end
66
+ BUMPS.each do |name, increment|
67
+ version = Version.new(previous.split(".").map(&:to_i), nil).increment(increment)
68
+ return name if version.join == target
69
+ end
70
+ raise "Unsupported release transition: #{previous} -> #{target}."
71
+ end
72
+
73
+ # Compare an independently generated release tree to the candidate, including added and deleted files.
74
+ # @parameter base [String] Current target commit, or the merged commit's first parent when publishing.
75
+ # @parameter candidate [String] Proposed or merged release commit.
76
+ # @parameter optional [Boolean] Allow ordinary PRs which do not change the version.
77
+ def validate(base:, candidate: "HEAD", optional: false)
78
+ base = resolve(base)
79
+ candidate = resolve(candidate)
80
+ proposed = metadata(candidate)
81
+ worktree(base) do |path|
82
+ previous = bake(path, "gem:metadata")
83
+ raise "Release changes the gem name." unless proposed[:name] == previous[:name]
84
+ return nil if optional && proposed[:version] == previous[:version]
85
+ increment = bump(previous[:version], proposed[:version])
86
+ generated = bake(path, "gem:release:version:increment", BUMPS.fetch(increment).join(","))
87
+ raise "Generated version does not match proposal." unless generated[:version] == proposed[:version]
88
+ system("git", "add", "--all", chdir: path)
89
+ expected = readlines("git", "write-tree", chdir: path).join.strip
90
+ diff = git("diff", "--no-ext-diff", "--no-textconv", candidate, expected, "--")
91
+ raise "Release content is stale or contains unrelated changes. Expected changes:\n#{diff}" unless diff.empty?
92
+ return proposed.merge(base: base, commit: candidate, bump: increment)
93
+ end
94
+ end
95
+
96
+ private
97
+
98
+ def git(*arguments)
99
+ readlines("git", *arguments, chdir: @root).join
100
+ end
101
+ end
102
+ end
103
+ end
@@ -11,6 +11,9 @@ module Bake
11
11
  module Gem
12
12
  # Exception raised when a command execution fails.
13
13
  class CommandExecutionError < RuntimeError
14
+ # Initialize the exception with the specified message and process status.
15
+ # @parameter message [String] The error message.
16
+ # @parameter status [Process::Status] The status object of the failed command.
14
17
  def initialize(message, status)
15
18
  super(message)
16
19
  @status = status
@@ -5,6 +5,6 @@
5
5
 
6
6
  module Bake
7
7
  module Gem
8
- VERSION = "0.13.1"
8
+ VERSION = "0.15.0"
9
9
  end
10
10
  end
data/readme.md CHANGED
@@ -14,6 +14,13 @@ Please see the [project documentation](https://ioquatix.github.io/bake-gem/) for
14
14
 
15
15
  Please see the [project releases](https://ioquatix.github.io/bake-gem/releases/index) for all releases.
16
16
 
17
+ ### v0.15.0
18
+
19
+ - Prepare release branches with `gem:release:branch:patch/minor/major`, committing the version bump and all release-hook changes before review.
20
+ - Add `gem:release:validate` to detect stale generated release content and unrelated changes.
21
+ - Build committed source in a fresh Ruby process and accept an explicit signing key path with `gem:build`.
22
+ - Push only the intended release tag when publishing locally.
23
+
17
24
  ### v0.13.1
18
25
 
19
26
  - Better `version.rb` detection in `version_path` method.
@@ -52,26 +59,26 @@ Please see the [project releases](https://ioquatix.github.io/bake-gem/releases/i
52
59
 
53
60
  We welcome contributions to this project.
54
61
 
55
- 1. Fork it.
62
+ 1. Fork the repository.
56
63
  2. Create your feature branch (`git checkout -b my-new-feature`).
57
- 3. Commit your changes (`git commit -am 'Add some feature'`).
64
+ 3. Commit your changes (`git commit -am 'Add some feature.'`).
58
65
  4. Push to the branch (`git push origin my-new-feature`).
59
- 5. Create new Pull Request.
66
+ 5. Create a new pull request.
60
67
 
61
68
  ### Running Tests
62
69
 
63
70
  To run the test suite:
64
71
 
65
- ``` shell
66
- bundle exec sus
72
+ ``` bash
73
+ $ bundle exec sus
67
74
  ```
68
75
 
69
76
  ### Making Releases
70
77
 
71
78
  To make a new release:
72
79
 
73
- ``` shell
74
- bundle exec bake gem:release:patch # or minor or major
80
+ ``` bash
81
+ $ bundle exec bake gem:release:patch # or minor or major
75
82
  ```
76
83
 
77
84
  ### Developer Certificate of Origin
data/releases.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Releases
2
2
 
3
+ ## v0.15.0
4
+
5
+ - Prepare release branches with `gem:release:branch:patch/minor/major`, committing the version bump and all release-hook changes before review.
6
+ - Add `gem:release:validate` to detect stale generated release content and unrelated changes.
7
+ - Build committed source in a fresh Ruby process and accept an explicit signing key path with `gem:build`.
8
+ - Push only the intended release tag when publishing locally.
9
+
3
10
  ## v0.13.1
4
11
 
5
12
  - Better `version.rb` detection in `version_path` method.
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bake-gem
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.1
4
+ version: 0.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -66,6 +66,7 @@ files:
66
66
  - context/index.yaml
67
67
  - lib/bake/gem.rb
68
68
  - lib/bake/gem/helper.rb
69
+ - lib/bake/gem/release.rb
69
70
  - lib/bake/gem/shell.rb
70
71
  - lib/bake/gem/version.rb
71
72
  - license.md
@@ -75,6 +76,8 @@ homepage: https://github.com/ioquatix/bake-gem
75
76
  licenses:
76
77
  - MIT
77
78
  metadata:
79
+ bug_tracker_uri: https://github.com/ioquatix/bake-gem/issues
80
+ changelog_uri: https://github.com/ioquatix/bake-gem/blob/main/releases.md
78
81
  documentation_uri: https://ioquatix.github.io/bake-gem/
79
82
  funding_uri: https://github.com/sponsors/ioquatix/
80
83
  source_code_uri: https://github.com/ioquatix/bake-gem.git
@@ -92,7 +95,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
92
95
  - !ruby/object:Gem::Version
93
96
  version: '0'
94
97
  requirements: []
95
- rubygems_version: 4.0.6
98
+ rubygems_version: 4.0.16
96
99
  specification_version: 4
97
100
  summary: Release management for Ruby gems.
98
101
  test_files: []
metadata.gz.sig CHANGED
Binary file