reissue 0.4.2 → 0.4.4

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: 58c406237f6e7ef96ad4a4e1ed1aa2ba3e4cb10145edd6d44bff791a8e37d5be
4
- data.tar.gz: 26b103713df3d7de9c1f9af49df079a2e9954b9b7e96a58bc8e3e203607e531d
3
+ metadata.gz: 23f7a25e06899fcdd212e472a07bedf1b9a7b6cfb81530370b8e1426a4a6ebdf
4
+ data.tar.gz: 2608f7b732e7b994276aac9237f67659bb2e19098c5692a8e2055c614f7e7673
5
5
  SHA512:
6
- metadata.gz: 01d186d7b5f87e5c3ef2be402eb758971ff4dec3626d2e2aed8d67d5fd6418d064687682176b509b038b39710e8c313279047e807e42d927c902e4b5bbee649e
7
- data.tar.gz: 63d5c29928e104484ce0f1c5ce6ef101a8909ed8727ae441c3a5bb81c9aaf6ecbfb46b7f4af69540f6665fc71ea8e9f9a73d1ea928371d3f8fb7a84b7077198c
6
+ metadata.gz: '048f4d0b836e36e31fa19f11c87dff4945b86a4c0c3265ad15264c47d47d3ff92d00101108b5868fd8faa029c52bcc706253a5254e4a2650ed5f5fa572b78a28'
7
+ data.tar.gz: 8ab5002c4637f8602177479da24c93a34a89000c4bff672f39b6b61b41a635f8c690d036e36289602f9685abf87684f2d373aaa8d0cfe601a088743318f5cab3
data/CHANGELOG.md CHANGED
@@ -5,14 +5,48 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](http://keepachangelog.com/)
6
6
  and this project adheres to [Semantic Versioning](http://semver.org/).
7
7
 
8
- ## [0.4.2] - 2025-09-16
8
+ ## [0.4.4] - 2025-10-17
9
9
 
10
10
  ### Changed
11
11
 
12
- - New version was never created after the last release.
12
+ - Derive TRAILER_REGEX from VALID_SECTIONS to eliminate duplication (32b963e)
13
+ - Updated example Rakefile to include version trailer configuration (4f2a254)
14
+ - Replace Qlty with native SimpleCov coverage reporting in CI (764d6ba)
13
15
 
14
- ## [0.4.2] - 2025-09-16
16
+ ### Added
17
+
18
+ - Version trailer parsing methods to GitFragmentHandler (0434f69)
19
+ - Version bump rake task with idempotency protection (9ff858a)
20
+ - Build task enhancement to process version trailers before finalize (b5a05b7)
21
+ - Release flow integration documentation and verification tests (e038230)
22
+ - Version bumping documentation to README.md (4f2a254)
23
+ - Version trailer examples and usage guide (4f2a254)
24
+ - PR comments showing code coverage percentage and threshold status (bfa4619)
25
+ - ChatNotifier to update slack about CI runs (55dfeb8)
26
+
27
+ ### Fixed
28
+
29
+ - Namespace loading problem when building a new release with Gem::Version. (c5fffd0)
30
+
31
+ ## [0.4.4] - 2025-10-17
15
32
 
16
33
  ### Changed
17
34
 
18
- - New version was never created after the last release.
35
+ - Derive TRAILER_REGEX from VALID_SECTIONS to eliminate duplication (32b963e)
36
+ - Updated example Rakefile to include version trailer configuration (4f2a254)
37
+ - Replace Qlty with native SimpleCov coverage reporting in CI (764d6ba)
38
+
39
+ ### Added
40
+
41
+ - Version trailer parsing methods to GitFragmentHandler (0434f69)
42
+ - Version bump rake task with idempotency protection (9ff858a)
43
+ - Build task enhancement to process version trailers before finalize (b5a05b7)
44
+ - Release flow integration documentation and verification tests (e038230)
45
+ - Version bumping documentation to README.md (4f2a254)
46
+ - Version trailer examples and usage guide (4f2a254)
47
+ - PR comments showing code coverage percentage and threshold status (bfa4619)
48
+ - ChatNotifier to update slack about CI runs (55dfeb8)
49
+
50
+ ### Fixed
51
+
52
+ - Namespace loading problem when building a new release with Gem::Version. (c5fffd0)
data/README.md CHANGED
@@ -196,6 +196,92 @@ rake release
196
196
 
197
197
  The changelog will be updated with the entries from your commit trailers.
198
198
 
199
+ ### Version Bumping with Git Trailers
200
+
201
+ When using git fragments (`task.fragment = :git`), you can also control version bumping through commit trailers. Add a `Version:` trailer to your commit messages to specify the type of version bump.
202
+
203
+ #### Configuration
204
+
205
+ The version bump feature is automatically enabled when using git fragments:
206
+
207
+ ```ruby
208
+ Reissue::Task.create :reissue do |task|
209
+ task.version_file = "lib/my_gem/version.rb"
210
+ task.fragment = :git # Enables both changelog and version trailers
211
+ end
212
+ ```
213
+
214
+ #### Version Trailer Syntax
215
+
216
+ Add a `Version:` trailer to specify the bump type:
217
+
218
+ ```bash
219
+ git commit -m "Add breaking API changes
220
+
221
+ Added: New REST API endpoints
222
+ Changed: Authentication now requires API keys
223
+ Version: major"
224
+ ```
225
+
226
+ Supported version bump types:
227
+ - `Version: major` - Increments major version (1.2.3 → 2.0.0)
228
+ - `Version: minor` - Increments minor version (1.2.3 → 1.3.0)
229
+ - `Version: patch` - Increments patch version (1.2.3 → 1.2.4)
230
+
231
+ #### Precedence Rules
232
+
233
+ When multiple commits contain `Version:` trailers, the highest precedence bump is applied:
234
+
235
+ **Precedence:** major > minor > patch
236
+
237
+ Examples:
238
+ - Commits with `Version: patch` and `Version: minor` → minor bump applied
239
+ - Commits with `Version: minor` and `Version: major` → major bump applied
240
+ - Multiple `Version: major` trailers → only one major bump applied
241
+
242
+ #### Idempotency
243
+
244
+ The version bump is idempotent - running `rake build` multiple times before releasing will only bump the version once:
245
+
246
+ 1. **First build:** Version bumped from 1.2.3 → 2.0.0 (based on `Version: major` trailer)
247
+ 2. **Second build:** Version bump skipped (already at 2.0.0)
248
+ 3. **Third build:** Version bump skipped (already at 2.0.0)
249
+ 4. **After release:** Patch bump to 2.0.1 (standard post-release behavior)
250
+
251
+ This is achieved by comparing the current version in your version file with the last git tag version. If they differ, the version was already bumped and the bump is skipped.
252
+
253
+ #### Example Workflow
254
+
255
+ ```bash
256
+ # Make changes with a major version bump
257
+ git commit -m "Redesign authentication system
258
+
259
+ Changed: Complete overhaul of auth architecture
260
+ Removed: Support for legacy OAuth 1.0
261
+ Added: OAuth 2.0 and JWT support
262
+ Version: major"
263
+
264
+ # Build (version bumps from 1.2.3 → 2.0.0)
265
+ rake build:checksum
266
+
267
+ # Build again (version bump skipped - already at 2.0.0)
268
+ rake build:checksum
269
+
270
+ # Release (creates v2.0.0 tag and bumps to 2.0.1)
271
+ rake release
272
+ ```
273
+
274
+ #### Case Insensitivity
275
+
276
+ Version trailers are case-insensitive:
277
+ - `Version: major`, `version: major`, `VERSION: MAJOR` all work
278
+
279
+ #### When to Use Version Trailers
280
+
281
+ - **Breaking changes:** Use `Version: major` for incompatible API changes
282
+ - **New features:** Use `Version: minor` for backwards-compatible new functionality
283
+ - **Bug fixes:** Use `Version: patch` for backwards-compatible bug fixes (or omit - patch is the default post-release bump)
284
+
199
285
  ## Development
200
286
 
201
287
  After checking out the repo, run `bin/setup` to install dependencies. Then run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt.
@@ -4,12 +4,12 @@ module Reissue
4
4
  class FragmentHandler
5
5
  # Handles reading changelog entries from git commit trailers
6
6
  class GitFragmentHandler < FragmentHandler
7
- # Regex to match changelog section trailers in commit messages
8
- TRAILER_REGEX = /^(Added|Changed|Deprecated|Removed|Fixed|Security):\s*(.+)$/i
9
-
10
7
  # Valid changelog sections that can be used as trailers
11
8
  VALID_SECTIONS = %w[Added Changed Deprecated Removed Fixed Security].freeze
12
9
 
10
+ # Regex to match changelog section trailers in commit messages
11
+ TRAILER_REGEX = /^(#{VALID_SECTIONS.join("|")}):\s*(.+)$/i
12
+
13
13
  # Read changelog entries from git commit trailers
14
14
  #
15
15
  # @return [Hash] A hash of changelog entries organized by section
@@ -27,6 +27,36 @@ module Reissue
27
27
  nil
28
28
  end
29
29
 
30
+ # Get the last version tag used for comparison
31
+ #
32
+ # @return [String, nil] The most recent version tag or nil if no tags found
33
+ def last_tag
34
+ return nil unless git_available? && in_git_repo?
35
+ find_last_tag
36
+ end
37
+
38
+ # Read version bump from git commit trailers
39
+ #
40
+ # @return [Symbol, nil] One of :major, :minor, :patch, or nil if none found
41
+ def read_version_bump
42
+ return nil unless git_available? && in_git_repo?
43
+
44
+ commits = commits_since_last_tag
45
+ parse_version_bump_from_commits(commits)
46
+ end
47
+
48
+ # Get the version from the last git tag
49
+ #
50
+ # @return [Gem::Version, nil] The version from the last tag, or nil if no tags exist
51
+ def last_tag_version
52
+ tag = last_tag
53
+ return nil unless tag
54
+
55
+ # Extract version number from tag (e.g., "v1.2.3" -> "1.2.3")
56
+ version_string = tag.sub(/^v/, "")
57
+ ::Gem::Version.new(version_string)
58
+ end
59
+
30
60
  private
31
61
 
32
62
  def git_available?
@@ -48,17 +78,35 @@ module Reissue
48
78
  "HEAD"
49
79
  end
50
80
 
51
- # Get commit messages with trailers, in reverse order (oldest first)
52
- output = `git log #{commit_range} --reverse --format=%B 2>/dev/null`
81
+ # Get commit hash and message using format specifiers
82
+ # %h = short hash, %x00 = null byte separator, %B = commit body
83
+ output = `git log #{commit_range} --reverse --format='%h%x00%B%x00' 2>/dev/null`
53
84
  return [] if output.empty?
54
85
 
55
- # Split by double newline to separate commits
56
- output.split(/\n\n+/)
86
+ # Split by null bytes and group into pairs of (hash, message)
87
+ parts = output.split("\x00")
88
+ commits = []
89
+
90
+ # Process pairs: hash, message, (empty from double null), repeat
91
+ i = 0
92
+ while i < parts.length - 1
93
+ sha = parts[i].strip
94
+ message = parts[i + 1] || ""
95
+
96
+ if !sha.empty?
97
+ commits << {sha: sha, message: message}
98
+ end
99
+
100
+ i += 2
101
+ end
102
+
103
+ commits
57
104
  end
58
105
 
59
106
  def find_last_tag
60
- # Try to find the most recent tag
61
- tag = `git describe --tags --abbrev=0 2>/dev/null`.strip
107
+ # Find the most recent semantic version tag (v*.*.*) by tag creation date across all branches
108
+ # This ensures we exclude commits that are already in ANY tagged release, not just the current branch
109
+ tag = `git for-each-ref --sort=-creatordate --format='%(refname:short)' 'refs/tags/v[0-9]*.[0-9]*.[0-9]*' --count=1 2>/dev/null`.strip
62
110
  tag.empty? ? nil : tag
63
111
  end
64
112
 
@@ -66,8 +114,11 @@ module Reissue
66
114
  result = {}
67
115
 
68
116
  commits.each do |commit|
69
- # Split commit into lines and look for trailers
70
- commit.lines.each do |line|
117
+ sha = commit[:sha]
118
+ message = commit[:message]
119
+
120
+ # Split commit message into lines and look for trailers
121
+ message.lines.each do |line|
71
122
  line = line.strip
72
123
  next if line.empty?
73
124
 
@@ -76,7 +127,8 @@ module Reissue
76
127
  trailer_value = match[2].strip
77
128
 
78
129
  result[section_name] ||= []
79
- result[section_name] << trailer_value
130
+ # Append the short SHA in parentheses
131
+ result[section_name] << "#{trailer_value} (#{sha})"
80
132
  end
81
133
  end
82
134
  end
@@ -88,6 +140,39 @@ module Reissue
88
140
  # Normalize to proper case (e.g., "FIXED" -> "Fixed", "added" -> "Added")
89
141
  name.capitalize
90
142
  end
143
+
144
+ def parse_version_bump_from_commits(commits)
145
+ # Precedence order (major > minor > patch)
146
+ precedence = {major: 3, minor: 2, patch: 1}
147
+
148
+ # Regex to match version trailers
149
+ version_regex = /^version:\s*(major|minor|patch)\s*$/i
150
+
151
+ highest_bump = nil
152
+ highest_precedence = 0
153
+
154
+ commits.each do |commit|
155
+ message = commit[:message]
156
+
157
+ # Split commit message into lines and look for version trailers
158
+ message.lines.each do |line|
159
+ line = line.strip
160
+ next if line.empty?
161
+
162
+ if (match = line.match(version_regex))
163
+ bump_value = match[1].downcase.to_sym
164
+
165
+ # Check if this bump has higher precedence
166
+ if precedence[bump_value] && precedence[bump_value] > highest_precedence
167
+ highest_bump = bump_value
168
+ highest_precedence = precedence[bump_value]
169
+ end
170
+ end
171
+ end
172
+ end
173
+
174
+ highest_bump
175
+ end
91
176
  end
92
177
  end
93
178
  end
data/lib/reissue/gem.rb CHANGED
@@ -11,8 +11,8 @@ module Reissue
11
11
  end
12
12
  Reissue::Task.prepend Reissue::Gem
13
13
 
14
- # Run rake reissue:finalize _before_ the build task as a prerequisite.
15
- Rake::Task[:build].enhance(["reissue:finalize"])
14
+ # Run rake reissue:bump and reissue:finalize _before_ the build task as prerequisites.
15
+ Rake::Task[:build].enhance(["reissue:bump", "reissue:finalize"])
16
16
 
17
17
  # Run the reissue task after the release task.
18
18
  Rake::Task["release"].enhance do
data/lib/reissue/rake.rb CHANGED
@@ -238,6 +238,18 @@ module Reissue
238
238
  if fragment
239
239
  require_relative "fragment_handler"
240
240
  handler = Reissue::FragmentHandler.for(fragment)
241
+
242
+ # Show comparison tag for git trailers
243
+ if fragment == :git && handler.respond_to?(:last_tag)
244
+ last_tag = handler.last_tag
245
+ if last_tag
246
+ puts "Comparing against: #{last_tag}"
247
+ puts " (Run 'git fetch --tags' if this seems out of date)\n\n"
248
+ else
249
+ puts "No version tags found (comparing against all commits)\n\n"
250
+ end
251
+ end
252
+
241
253
  entries = handler.read
242
254
 
243
255
  if entries.empty?
@@ -282,6 +294,46 @@ module Reissue
282
294
  end
283
295
  end
284
296
  end
297
+
298
+ desc "Bump version based on git trailers"
299
+ task "#{name}:bump" do
300
+ # Only check for version trailers when using git fragments
301
+ next unless fragment == :git
302
+
303
+ require_relative "fragment_handler"
304
+ require_relative "version_updater"
305
+
306
+ handler = Reissue::FragmentHandler.for(:git)
307
+
308
+ # Get current version from version file
309
+ version_content = File.read(version_file)
310
+ current_version = ::Gem::Version.new(version_content.match(Reissue::VersionUpdater::VERSION_MATCH)[0])
311
+
312
+ # Get version from last git tag
313
+ tag_version = handler.last_tag_version
314
+
315
+ # Only bump if current version matches tag version (hasn't been bumped yet)
316
+ if tag_version && current_version == tag_version
317
+ bump = handler.read_version_bump
318
+
319
+ if bump
320
+ updater = Reissue::VersionUpdater.new(version_file, version_redo_proc: version_redo_proc)
321
+ updater.call(bump)
322
+ puts "Version bumped (#{bump}) to #{updater.instance_variable_get(:@new_version)}"
323
+ end
324
+ elsif tag_version && current_version != tag_version
325
+ puts "Version already bumped (#{tag_version} → #{current_version}), skipping"
326
+ else
327
+ # No tag exists, check for version trailers anyway
328
+ bump = handler.read_version_bump
329
+
330
+ if bump
331
+ updater = Reissue::VersionUpdater.new(version_file, version_redo_proc: version_redo_proc)
332
+ updater.call(bump)
333
+ puts "Version bumped (#{bump}) to #{updater.instance_variable_get(:@new_version)}"
334
+ end
335
+ end
336
+ end
285
337
  end
286
338
  end
287
339
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Reissue
4
- VERSION = "0.4.2"
4
+ VERSION = "0.4.4"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: reissue
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.4.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jim Gay