bake-gem 0.14.0 → 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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/bake/gem/release/branch.rb +12 -18
- data/bake/gem/release/version.rb +7 -14
- data/bake/gem/release.rb +10 -0
- data/bake/gem.rb +14 -2
- data/context/getting-started.md +29 -15
- data/context/index.yaml +2 -0
- data/lib/bake/gem/helper.rb +36 -19
- data/lib/bake/gem/release.rb +103 -0
- data/lib/bake/gem/version.rb +1 -1
- data/readme.md +14 -7
- data/releases.md +7 -0
- data.tar.gz.sig +0 -0
- metadata +5 -2
- metadata.gz.sig +2 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 847773b347cc41d5b64aa246a96fc3770e932f15fe53121538156327a8e67a9f
|
|
4
|
+
data.tar.gz: e0396526fe9584882269a7326e99614885cc4e6f4c755d064e8cbf1f8af2e054
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4b18cd961a2cfd4fc06bec5ed0389c6b3d1b8eb65ace189ae393c7bf6ab9838711322f82dad8e17cb62a69937d35e4f3a2ad15a9c4c19d0053182d6dc2d02abf
|
|
7
|
+
data.tar.gz: 51874bafe6a43e93c62f464502e074974df47a5d03ec7e7c204c7e0cfa730f0bcaaedf27c9e63e4bd375f81b84732404426a0dc95d94f914d06d80eeffa9d2fd
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/bake/gem/release/branch.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2021-
|
|
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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
data/bake/gem/release/version.rb
CHANGED
|
@@ -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:
|
|
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
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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,10 +21,22 @@ 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 [
|
|
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
|
|
|
@@ -70,7 +82,7 @@ def release(tag: true)
|
|
|
70
82
|
raise
|
|
71
83
|
end
|
|
72
84
|
|
|
73
|
-
@helper.push_release(current_branch: current_branch)
|
|
85
|
+
@helper.push_release(current_branch: current_branch, tag: tag_name)
|
|
74
86
|
context["after_gem_release"]&.call(name: @helper.gemspec.name, version: version, tag: tag_name, path: path)
|
|
75
87
|
|
|
76
88
|
return {
|
data/context/getting-started.md
CHANGED
|
@@ -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
|
-
|
|
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
|
-
-
|
|
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
|
-
-
|
|
89
|
-
|
|
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
|
-
|
|
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
|
-
$
|
|
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
|
-
#
|
|
205
|
+
# Commits the version bump and release-hook output
|
|
206
|
+
# Leaves the branch local for inspection
|
|
191
207
|
|
|
192
|
-
#
|
|
193
|
-
$
|
|
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
|
data/lib/bake/gem/helper.rb
CHANGED
|
@@ -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
|
-
|
|
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(
|
|
143
|
+
File.write(path, lines.join)
|
|
141
144
|
|
|
142
145
|
if block_given?
|
|
143
146
|
yield new_version
|
|
@@ -194,6 +197,7 @@ module Bake
|
|
|
194
197
|
# @returns [String] The path to the built gem package.
|
|
195
198
|
def build_gem(root: "pkg", signing_key: nil)
|
|
196
199
|
# Ensure the output directory exists:
|
|
200
|
+
root = File.expand_path(root, @root)
|
|
197
201
|
FileUtils.mkdir_p(root)
|
|
198
202
|
|
|
199
203
|
output_path = File.join(root, @gemspec.file_name)
|
|
@@ -228,7 +232,7 @@ module Bake
|
|
|
228
232
|
# @parameter signing_key [String | Nil] The signing key to use for signing the package.
|
|
229
233
|
# @returns [String] The path to the built gem package.
|
|
230
234
|
def build_gem_in_worktree(root: "pkg", signing_key: nil)
|
|
231
|
-
original_pkg_path = File.
|
|
235
|
+
original_pkg_path = File.expand_path(root, @root)
|
|
232
236
|
|
|
233
237
|
# Create a unique temporary path for the worktree
|
|
234
238
|
timestamp = Time.now.strftime("%Y%m%d-%H%M%S-%N")
|
|
@@ -236,15 +240,13 @@ module Bake
|
|
|
236
240
|
|
|
237
241
|
begin
|
|
238
242
|
# Create worktree from current HEAD
|
|
239
|
-
unless system("git", "worktree", "add", worktree_path, "HEAD", chdir: @root)
|
|
243
|
+
unless system("git", "worktree", "add", "--detach", worktree_path, "HEAD", chdir: @root)
|
|
240
244
|
raise "Failed to create git worktree. Make sure you have at least one commit in the repository."
|
|
241
245
|
end
|
|
242
246
|
|
|
243
|
-
#
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
# Build gem directly into the target pkg directory
|
|
247
|
-
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)
|
|
248
250
|
|
|
249
251
|
output_path
|
|
250
252
|
ensure
|
|
@@ -253,16 +255,16 @@ module Bake
|
|
|
253
255
|
end
|
|
254
256
|
end
|
|
255
257
|
|
|
256
|
-
# Create a release branch
|
|
257
|
-
# @parameter
|
|
258
|
-
# @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.
|
|
259
260
|
# @returns [String] The name of the created branch.
|
|
260
|
-
def create_release_branch(
|
|
261
|
-
|
|
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?
|
|
262
266
|
|
|
263
267
|
system("git", "checkout", "-b", branch_name, chdir: @root)
|
|
264
|
-
system("git", "add", version_path, chdir: @root)
|
|
265
|
-
system("git", "commit", "-m", message, chdir: @root)
|
|
266
268
|
|
|
267
269
|
return branch_name
|
|
268
270
|
end
|
|
@@ -270,10 +272,25 @@ module Bake
|
|
|
270
272
|
# Commit version changes to the current branch.
|
|
271
273
|
# @parameter message [String] The commit message to use.
|
|
272
274
|
def commit_version_changes(message: "Bump version.")
|
|
275
|
+
guard_release_changes
|
|
273
276
|
system("git", "add", "--all", chdir: @root)
|
|
274
277
|
system("git", "commit", "-m", message, chdir: @root)
|
|
275
278
|
end
|
|
276
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
|
+
|
|
277
294
|
# Fetch remote tags and create a release tag for the specified version.
|
|
278
295
|
# @parameter tag [Boolean] Whether to tag the release.
|
|
279
296
|
# @parameter version [String] The version to tag.
|
|
@@ -298,13 +315,13 @@ module Bake
|
|
|
298
315
|
|
|
299
316
|
# Push changes and tags to the remote repository.
|
|
300
317
|
# @parameter current_branch [String | Nil] The current branch name, or nil if not on a branch.
|
|
301
|
-
def push_release(current_branch: nil)
|
|
318
|
+
def push_release(current_branch: nil, tag: nil)
|
|
302
319
|
# If we are on a branch, push, otherwise just push the tags (assuming shallow checkout):
|
|
303
320
|
if current_branch
|
|
304
321
|
system("git", "push", chdir: @root)
|
|
305
322
|
end
|
|
306
323
|
|
|
307
|
-
system("git", "push", "
|
|
324
|
+
system("git", "push", "origin", "refs/tags/#{tag}", chdir: @root) if tag
|
|
308
325
|
end
|
|
309
326
|
|
|
310
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
|
data/lib/bake/gem/version.rb
CHANGED
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
|
|
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
|
|
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
|
-
```
|
|
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
|
-
```
|
|
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.
|
|
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.
|
|
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
|
@@ -1,4 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
p��
|
|
4
|
-
�'ߪ2q�v��w�줃N����2�ܱ,2���c��Y,���-BM���0�A�ZHm��P�<�W�U�NRw��$�<F�G�Z��B1ԁ�C�K<w�MU��X�͔��~O_��@��H�u�N
|
|
1
|
+
'Z���5C������8Y���Y>�� ����ޤK��|��$PAiA,no^v=�S�?�CgO �o��5��̣#�����I�Д&����F�SED]?�*�0���`
|
|
2
|
+
����"?N��5m/�;W���<":o0��6�VpE$�?T���<TD��������I1
|