kettle-dev 1.2.4 → 2.0.1

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.
Files changed (152) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +232 -3
  4. data/CITATION.cff +6 -6
  5. data/CONTRIBUTING.md +64 -46
  6. data/FUNDING.md +1 -1
  7. data/LICENSE.md +12 -0
  8. data/README.md +448 -457
  9. data/certs/pboling.pem +27 -0
  10. data/exe/kettle-changelog +24 -13
  11. data/exe/kettle-check-eof +7 -0
  12. data/exe/kettle-check-eof.sh +118 -0
  13. data/exe/kettle-dev-setup +12 -63
  14. data/exe/kettle-gh-release +82 -0
  15. data/lib/kettle/dev/changelog_cli.rb +373 -62
  16. data/lib/kettle/dev/ci_monitor.rb +2 -2
  17. data/lib/kettle/dev/dvcs_cli.rb +1 -1
  18. data/lib/kettle/dev/gem_spec_reader.rb +100 -10
  19. data/lib/kettle/dev/git_adapter.rb +37 -1
  20. data/lib/kettle/dev/open_collective_config.rb +15 -3
  21. data/lib/kettle/dev/pre_release_cli.rb +4 -4
  22. data/lib/kettle/dev/rakelib/reek.rake +9 -6
  23. data/lib/kettle/dev/rakelib/spec_test.rake +25 -25
  24. data/lib/kettle/dev/rakelib/yard.rake +17 -17
  25. data/lib/kettle/dev/readme_backers.rb +4 -4
  26. data/lib/kettle/dev/release_cli.rb +27 -24
  27. data/lib/kettle/dev/tasks/ci_task.rb +4 -4
  28. data/lib/kettle/dev/version.rb +2 -87
  29. data/lib/kettle/dev.rb +31 -17
  30. data/sig/kettle/dev/source_merger.rbs +40 -56
  31. data/sig/kettle/dev/version.rbs +8 -0
  32. data.tar.gz.sig +0 -0
  33. metadata +63 -165
  34. metadata.gz.sig +0 -0
  35. data/.aiignore.example +0 -19
  36. data/.devcontainer/apt-install/devcontainer-feature.json +0 -9
  37. data/.devcontainer/apt-install/install.sh +0 -11
  38. data/.devcontainer/devcontainer.json +0 -28
  39. data/.env.local.example +0 -31
  40. data/.envrc +0 -47
  41. data/.envrc.example +0 -51
  42. data/.envrc.no-osc.example +0 -51
  43. data/.git-hooks/commit-msg +0 -54
  44. data/.git-hooks/commit-subjects-goalie.txt +0 -8
  45. data/.git-hooks/footer-template.erb.txt +0 -16
  46. data/.git-hooks/prepare-commit-msg +0 -8
  47. data/.github/.codecov.yml.example +0 -14
  48. data/.github/FUNDING.yml +0 -13
  49. data/.github/FUNDING.yml.no-osc.example +0 -13
  50. data/.github/dependabot.yml +0 -13
  51. data/.github/workflows/ancient.yml +0 -83
  52. data/.github/workflows/ancient.yml.example +0 -81
  53. data/.github/workflows/auto-assign.yml +0 -21
  54. data/.github/workflows/codeql-analysis.yml +0 -70
  55. data/.github/workflows/coverage.yml +0 -127
  56. data/.github/workflows/coverage.yml.example +0 -127
  57. data/.github/workflows/current.yml +0 -116
  58. data/.github/workflows/current.yml.example +0 -115
  59. data/.github/workflows/dep-heads.yml +0 -117
  60. data/.github/workflows/dependency-review.yml +0 -20
  61. data/.github/workflows/discord-notifier.yml.example +0 -39
  62. data/.github/workflows/heads.yml +0 -117
  63. data/.github/workflows/heads.yml.example +0 -116
  64. data/.github/workflows/jruby.yml +0 -82
  65. data/.github/workflows/jruby.yml.example +0 -72
  66. data/.github/workflows/legacy.yml +0 -76
  67. data/.github/workflows/license-eye.yml +0 -40
  68. data/.github/workflows/locked_deps.yml +0 -85
  69. data/.github/workflows/opencollective.yml +0 -40
  70. data/.github/workflows/style.yml +0 -67
  71. data/.github/workflows/supported.yml +0 -75
  72. data/.github/workflows/truffle.yml +0 -99
  73. data/.github/workflows/unlocked_deps.yml +0 -84
  74. data/.github/workflows/unsupported.yml +0 -76
  75. data/.gitignore +0 -50
  76. data/.gitlab-ci.yml.example +0 -134
  77. data/.idea/.gitignore +0 -45
  78. data/.junie/guidelines-rbs.md +0 -49
  79. data/.junie/guidelines.md +0 -141
  80. data/.junie/guidelines.md.example +0 -140
  81. data/.licenserc.yaml +0 -7
  82. data/.opencollective.yml +0 -3
  83. data/.opencollective.yml.example +0 -3
  84. data/.qlty/qlty.toml +0 -79
  85. data/.rspec +0 -9
  86. data/.rubocop.yml +0 -13
  87. data/.rubocop_rspec.yml +0 -33
  88. data/.simplecov +0 -16
  89. data/.simplecov.example +0 -11
  90. data/.tool-versions +0 -1
  91. data/.yardignore +0 -13
  92. data/.yardopts +0 -14
  93. data/Appraisal.root.gemfile +0 -10
  94. data/Appraisals +0 -151
  95. data/Appraisals.example +0 -102
  96. data/CHANGELOG.md.example +0 -47
  97. data/CONTRIBUTING.md.example +0 -227
  98. data/FUNDING.md.no-osc.example +0 -63
  99. data/Gemfile +0 -40
  100. data/Gemfile.example +0 -34
  101. data/LICENSE.txt +0 -21
  102. data/README.md.example +0 -570
  103. data/README.md.no-osc.example +0 -536
  104. data/REEK +0 -0
  105. data/Rakefile.example +0 -68
  106. data/bin/setup +0 -8
  107. data/gemfiles/modular/coverage.gemfile +0 -6
  108. data/gemfiles/modular/debug.gemfile +0 -13
  109. data/gemfiles/modular/documentation.gemfile +0 -14
  110. data/gemfiles/modular/erb/r2/v3.0.gemfile +0 -1
  111. data/gemfiles/modular/erb/r2.3/default.gemfile +0 -6
  112. data/gemfiles/modular/erb/r2.6/v2.2.gemfile +0 -3
  113. data/gemfiles/modular/erb/r3/v5.0.gemfile +0 -1
  114. data/gemfiles/modular/erb/r3.1/v4.0.gemfile +0 -2
  115. data/gemfiles/modular/erb/vHEAD.gemfile +0 -2
  116. data/gemfiles/modular/injected.gemfile +0 -60
  117. data/gemfiles/modular/mutex_m/r2/v0.3.gemfile +0 -2
  118. data/gemfiles/modular/mutex_m/r2.4/v0.1.gemfile +0 -3
  119. data/gemfiles/modular/mutex_m/r3/v0.3.gemfile +0 -2
  120. data/gemfiles/modular/mutex_m/vHEAD.gemfile +0 -2
  121. data/gemfiles/modular/optional.gemfile +0 -8
  122. data/gemfiles/modular/optional.gemfile.example +0 -5
  123. data/gemfiles/modular/runtime_heads.gemfile +0 -10
  124. data/gemfiles/modular/runtime_heads.gemfile.example +0 -8
  125. data/gemfiles/modular/stringio/r2/v3.0.gemfile +0 -5
  126. data/gemfiles/modular/stringio/r2.4/v0.0.2.gemfile +0 -4
  127. data/gemfiles/modular/stringio/r3/v3.0.gemfile +0 -5
  128. data/gemfiles/modular/stringio/vHEAD.gemfile +0 -2
  129. data/gemfiles/modular/style.gemfile +0 -25
  130. data/gemfiles/modular/style.gemfile.example +0 -25
  131. data/gemfiles/modular/templating.gemfile +0 -3
  132. data/gemfiles/modular/x_std_libs/r2/libs.gemfile +0 -3
  133. data/gemfiles/modular/x_std_libs/r2.3/libs.gemfile +0 -3
  134. data/gemfiles/modular/x_std_libs/r2.4/libs.gemfile +0 -3
  135. data/gemfiles/modular/x_std_libs/r2.6/libs.gemfile +0 -3
  136. data/gemfiles/modular/x_std_libs/r3/libs.gemfile +0 -3
  137. data/gemfiles/modular/x_std_libs/r3.1/libs.gemfile +0 -3
  138. data/gemfiles/modular/x_std_libs/vHEAD.gemfile +0 -3
  139. data/gemfiles/modular/x_std_libs.gemfile +0 -2
  140. data/kettle-dev.gemspec.example +0 -154
  141. data/lib/kettle/dev/modular_gemfiles.rb +0 -119
  142. data/lib/kettle/dev/prism_appraisals.rb +0 -351
  143. data/lib/kettle/dev/prism_gemfile.rb +0 -177
  144. data/lib/kettle/dev/prism_gemspec.rb +0 -284
  145. data/lib/kettle/dev/prism_utils.rb +0 -201
  146. data/lib/kettle/dev/rakelib/install.rake +0 -10
  147. data/lib/kettle/dev/rakelib/template.rake +0 -10
  148. data/lib/kettle/dev/setup_cli.rb +0 -403
  149. data/lib/kettle/dev/source_merger.rb +0 -655
  150. data/lib/kettle/dev/tasks/install_task.rb +0 -553
  151. data/lib/kettle/dev/tasks/template_task.rb +0 -975
  152. data/lib/kettle/dev/template_helpers.rb +0 -685
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 73ca5267629934af0b0f044598295a93c287cbace6c0ac2f5e2d1a701a72ca89
4
- data.tar.gz: 1743ac37975a516f979d135d52c62b8a9fa28171d6df1a82fb58cce4d1676ea1
3
+ metadata.gz: 423e786ae241791214751d2cd3496033ba0986b4279d738d62feda1eb197837b
4
+ data.tar.gz: 7c7436dcf0a65dea2d9241263bfd6d357c64a5f4a1a12432325fb5aecfe2cd38
5
5
  SHA512:
6
- metadata.gz: afd0cdb05a6f08db4665b634cf38d4f959d08ea73ff526f1757d9168d3aab0a6a6d81ba90a5f20905f8888bd88bbbe55c1c53d15f0d1898202448dac0f204bd3
7
- data.tar.gz: 92a005b6bb76771bffe3e0e3e3762bc6e11699286119dc009cb61e4c72278666552e07cf0a547c215c586caf7abeea7305767fce2d008342758b5d8fe80cc676
6
+ metadata.gz: 2f7e35c2eedd5a7f4b75bd9ce4bfb0e98e269a05694875a6c53311aaab885d5a3d8839283b3ca986cd3b694f1f48b3bc3ed0dc28171decb1e5391ef61b0df0c2
7
+ data.tar.gz: abd66bf76d22b3d13303228bf46d22b4fbb7f69c26d0740e54ec6c693f3f31d10b34f9cc4491fb12be0e073777af8ca812d57eb740cd27af65b644bb445bba60
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -22,14 +22,237 @@ Please file a bug if you notice a violation of semantic versioning.
22
22
 
23
23
  ### Changed
24
24
 
25
+ - **BREAKING**: Raised the minimum Ruby version to 2.4.0, matching
26
+ `kettle-test` 2.x and its runtime `turbo_tests2` dependency.
27
+ - `kettle-test` is now declared as a runtime dependency because the shipped rake
28
+ and changelog tasks invoke `bundle exec kettle-test`.
29
+ - Refreshed generated template output for README badge formatting and
30
+ Ruby 2.4-targeted RuboCop LTS style dependencies.
31
+
25
32
  ### Deprecated
26
33
 
27
34
  ### Removed
28
35
 
36
+ - Removed Ruby 2.3 and JRuby 9.1 CI workflows and appraisal gemfiles.
37
+
29
38
  ### Fixed
30
39
 
40
+ - Appraisal-based CI gemfiles now load the version-appropriate VCR/WebMock
41
+ recording dependencies required by the spec helper without falling back to the
42
+ root Gemfile.
43
+ - Reek, RuboCop-LTS, and coverage task specs now run in coverage CI without
44
+ requiring style-only dependencies.
45
+ - Reek rake task specs no longer change the process working directory, avoiding
46
+ cross-spec project root leakage under turbo workers.
47
+ - `rake reek:update` now raises a normal task error on unexpected reek exits
48
+ instead of calling `Kernel.abort`, so specs can assert the failure path without
49
+ poisoning the process exit status.
50
+ - Coverage CI thresholds now match the repository `mise.toml` thresholds instead
51
+ of requiring unreachable 100% line and branch coverage.
52
+ - Regenerated templating now keeps `kettle-test` as a runtime dependency only
53
+ instead of duplicating it as both runtime and development dependency.
54
+ - Replaced non-capturing `=~` checks with `Regexp#match?` so unlocked/style CI
55
+ stays clean with newer RuboCop performance cops.
56
+ - Cleared the remaining `rubocop_gradual` backlog and removed the lock file.
57
+
31
58
  ### Security
32
59
 
60
+ ## [2.0.1] - 2026-05-25
61
+
62
+ - TAG: [v2.0.1][2.0.1t]
63
+ - COVERAGE: 94.88% -- 2911/3068 lines in 21 files
64
+ - BRANCH COVERAGE: 78.43% -- 1200/1530 branches in 21 files
65
+ - 76.25% documented
66
+
67
+ ### Added
68
+
69
+ - Added `kettle-changelog --update-prep` to refresh the most recent prepared
70
+ release section in place, including date, coverage, documentation stats, and
71
+ any follow-up Unreleased notes.
72
+
73
+ ### Changed
74
+
75
+ - `kettle-changelog` now generates strict coverage data with
76
+ `bundle exec kettle-test`, preserving the faster `turbo_tests2` runner.
77
+ - `kettle-changelog` now treats configured coverage thresholds as a changelog
78
+ preparation gate by default; use `--no-coverage-threshold` or
79
+ `K_CHANGELOG_COVERAGE_HARD=false` to generate changelog metadata without
80
+ threshold enforcement.
81
+ - The shared `rake spec` task now delegates to `bundle exec kettle-test`, so
82
+ projects using kettle-dev automatically pick up kettle-test's default
83
+ `turbo_tests2` runner and summary output.
84
+ - The shared `:yard` task now installs `yard-fence` and `yard-timekeeper` integrations explicitly so documentation prep and post-processing only run during `rake yard`
85
+
86
+ - Refreshed generated kettle-jem templates, CI workflows, curated binstubs, and
87
+ local modular Gemfile wiring.
88
+ - `kettle-changelog` now auto-selects the correct no-argument action by
89
+ comparing `version.rb`, the latest live release, and the most recent
90
+ CHANGELOG.md release section before prompting for confirmation.
91
+ - Updated the development dependency on `kettle-test` to require 2.0.1 or newer.
92
+
93
+ ### Fixed
94
+
95
+ - Loading YARD during unrelated rake tasks no longer triggers documentation plugin side effects that rewrite or clear `docs/`
96
+
97
+ - `rake reek:update` now resolves the Reek gem executable directly instead of
98
+ shelling through `bundle exec reek`, avoiding stale project binstubs, and no
99
+ longer fails the default task solely because Reek reported smells while
100
+ refreshing the `REEK` backlog file.
101
+ - `rake reek:update` now keeps `REEK` zero-byte when Reek reports no smells
102
+ instead of writing a single blank line.
103
+
104
+ ## [2.0.0] - 2026-02-25
105
+
106
+ - TAG: [v2.0.0][2.0.0t]
107
+ - COVERAGE: 96.06% -- 2683/2793 lines in 20 files
108
+ - BRANCH COVERAGE: 79.16% -- 1113/1406 branches in 20 files
109
+ - 80.25% documented
110
+
111
+ ### Added
112
+
113
+ - New `kettle-gh-release` executable for standalone GitHub release creation
114
+ - Extracted from `kettle-release` step 18
115
+ - Useful when RubyGems release succeeded but GitHub release failed
116
+ - Supports explicit version via `version=<VERSION>` argument
117
+ - Auto-detects version from `lib/**/version.rb` if not specified
118
+ - Requires `GITHUB_TOKEN` with `repo:public_repo` (classic) or `contents:write` scope
119
+ - Added `.kettle-dev.yml` configuration file for per-file merge options
120
+ - Hybrid format: `defaults` for shared merge options, `patterns` for glob fallbacks, `files` for per-file config
121
+ - Nested directory structure under `files` allows individual file configuration
122
+ - Supports all `Prism::Merge::SmartMerger` options: `preference`, `add_template_only_nodes`, `freeze_token`, `max_recursion_depth`
123
+ - Added `TemplateHelpers.kettle_config`, `.config_for`, `.find_file_config` methods
124
+ - Added spec coverage in `template_helpers_config_spec.rb`
125
+
126
+ ### Changed
127
+
128
+ - Updated documentation on hostile takeover of RubyGems
129
+ - https://dev.to/galtzo/hostile-takeover-of-rubygems-my-thoughts-5hlo
130
+ - **BREAKING**: Replaced `template_manifest.yml` with `.kettle-dev.yml`
131
+ - New hybrid format supports both glob patterns and per-file configuration
132
+ - `TemplateHelpers.load_manifest` now reads from `.kettle-dev.yml` patterns section
133
+ - `TemplateHelpers.strategy_for` checks explicit file configs before falling back to patterns
134
+ - **BREAKING**: Simplified `SourceMerger` to fully rely on prism-merge for AST merging
135
+ - Reduced from ~610 lines to ~175 lines (71% reduction)
136
+ - Removed custom newline normalization - prism-merge preserves original formatting
137
+ - Removed custom comment deduplication logic - prism-merge handles this natively
138
+ - All strategies (`:skip`, `:replace`, `:append`, `:merge`) now use prism-merge consistently
139
+ - Freeze blocks (`kettle-dev:freeze` / `kettle-dev:unfreeze`) handled by prism-merge's `freeze_token` option
140
+
141
+ ### Removed
142
+
143
+ - Removed all `.example` template files from the kettle-dev root and subdirectories
144
+ (27 files). Template files now live exclusively in kettle-jem's `template/` directory.
145
+ Only `.env.local.example` is retained as a dev resource for all destination gems.
146
+ - Removed unused methods from `SourceMerger`:
147
+ - `normalize_source` - replaced by prism-merge
148
+ - `normalize_newlines` - prism-merge preserves original formatting
149
+ - `shebang?`, `magic_comment?`, `ruby_magic_comment_key?` - no longer needed
150
+ - Comment extraction/deduplication: `extract_magic_comments`, `extract_file_leading_comments`,
151
+ `create_comment_tuples`, `deduplicate_comment_sequences`, `deduplicate_sequences_pass1`,
152
+ `deduplicate_singles_pass2`, `extract_nodes_with_comments`, `count_blank_lines_before`,
153
+ `build_source_from_nodes`
154
+ - Unused comment restoration: `restore_custom_leading_comments`, `deduplicate_leading_comment_block`,
155
+ `extract_comment_lines`, `normalize_comment`, `leading_comment_block`
156
+ - Removed unused constants: `RUBY_MAGIC_COMMENT_KEYS`, `MAGIC_COMMENT_REGEXES`
157
+
158
+ ### Fixed
159
+
160
+ - Fixed `PrismAppraisals` various comment chunk spacing
161
+ - extract_block_header:
162
+ - skips the blank spacer immediately above an `appraise` block
163
+ - treats any following blank line as the stop boundary once comment lines have been collected
164
+ - prevents preamble comments from being pulled into the first block’s header
165
+ - restores expected ordering:
166
+ - magic comments and their blank line stay at the top
167
+ - block headers remain adjacent to their blocks
168
+ - preserves blank lines between comment chunks
169
+ - Fixed `SourceMerger` freeze block location preservation
170
+ - Freeze blocks now stay in their original location in the file structure
171
+ - Skip normalization for files with existing freeze blocks to prevent movement
172
+ - Only include contiguous comments immediately before freeze markers (no arbitrary 3-line lookback)
173
+ - Don't add freeze reminder to files that already have freeze/unfreeze blocks
174
+ - Prevents unrelated comments from being incorrectly captured in freeze block ranges
175
+ - Added comprehensive test coverage for multiple freeze blocks at different nesting levels
176
+ - Fixed `TemplateTask` to not override template summary/description with empty strings from destination gemspec
177
+ - Only carries over summary/description when they contain actual content (non-empty)
178
+ - Allows token replacements to work correctly (e.g., `kettle-dev summary` → `my-gem summary`)
179
+ - Prevents empty destination fields from erasing meaningful template values
180
+ - Fixed `SourceMerger` magic comment ordering and freeze block protection
181
+ - Magic comments now preserve original order
182
+ - No blank lines inserted between consecutive magic comments
183
+ - Freeze reminder block properly separated from magic comments (not merged)
184
+ - Leverages Prism's built-in `parse_result.magic_comments` API for accurate detection
185
+ - Detects `kettle-dev:freeze/unfreeze` pairs using Prism, then reclassifies as file-level comments to keep blocks intact
186
+ - Removed obsolete `is_magic_comment?` method in favor of Prism's native detection
187
+ - Fixed `PrismGemspec` and `PrismGemfile` to use pure Prism AST traversal instead of regex fallbacks
188
+ - Removed regex-based `extract_gemspec_emoji` that parsed `spec.summary =` and `spec.description =` with regex
189
+ - Now traverses Prism AST to find Gem::Specification block, extracts summary/description nodes, and gets literal values
190
+ - Removed regex-based source line detection in `PrismGemfile.merge_gem_calls`
191
+ - Now uses `PrismUtils.statement_key` to find source statements via AST instead of `ln =~ /^\s*source\s+/`
192
+ - Aligns with project goal: move away from regex parsing toward proper AST manipulation with Prism
193
+ - All functionality preserved, tested, and working correctly
194
+ - Fixed `PrismGemspec.replace_gemspec_fields` block parameter extraction to use Prism AST
195
+ - **CRITICAL**: Was using regex fallback that incorrectly captured entire block body as parameter name
196
+ - Removed buggy regex fallback in favor of pure Prism AST traversal
197
+ - Now properly extracts block parameter from Prism::BlockParametersNode → Prism::ParametersNode → Prism::RequiredParameterNode
198
+ - Fixed `PrismGemspec.replace_gemspec_fields` insert offset calculation for emoji-containing gemspecs
199
+ - **CRITICAL**: Was using character length (`String#length`) instead of byte length (`String#bytesize`) to calculate insert offset
200
+ - When gemspecs contain multi-byte UTF-8 characters (emojis like 🍲), character length != byte length
201
+ - This caused fields to be inserted at wrong byte positions, resulting in truncated strings and massive corruption
202
+ - Changed `body_src.rstrip.length` to `body_src.rstrip.bytesize` for correct byte-offset calculations
203
+ - Prevents gemspec templating from producing corrupted output with truncated dependency lines
204
+ - Added comprehensive debug logging to trace byte offset calculations and edit operations
205
+ - Fixed `SourceMerger` variable assignment duplication during merge operations
206
+ - `node_signature` now identifies variable/constant assignments by name only, not full source
207
+ - Previously used full source text as signature, causing duplicates when assignment bodies differed
208
+ - Added specific handlers for: LocalVariableWriteNode, InstanceVariableWriteNode, ClassVariableWriteNode, ConstantWriteNode, GlobalVariableWriteNode
209
+ - Also added handlers for ClassNode and ModuleNode to match by name
210
+ - Example: `gem_version = ...` assignments with different bodies now correctly merge instead of duplicating
211
+ - Prevents `bin/kettle-dev-setup` from creating duplicate variable assignments in gemspecs and other files
212
+ - Added comprehensive specs for variable assignment deduplication and idempotency
213
+ - Fixed `SourceMerger` conditional block duplication during merge operations
214
+ - `node_signature` now identifies conditional nodes (if/unless/case) by their predicate only
215
+ - Previously used full source text, causing duplicate blocks when template updates conditional bodies
216
+ - Example: if ENV["FOO"] blocks with different bodies now correctly merge instead of duplicating
217
+ - Prevents `bin/kettle-dev-setup` from creating duplicate if/else blocks in gemfiles
218
+ - Added comprehensive specs for conditional merging behavior and idempotency
219
+ - Fixed `PrismGemspec.replace_gemspec_fields` to use byte-aware string operations
220
+ - **CRITICAL**: Was using character-based `String#[]=` with Prism's byte offsets
221
+ - This caused catastrophic corruption when emojis or multi-byte UTF-8 characters were present
222
+ - Symptoms: gemspec blocks duplicated/fragmented, statements escaped outside blocks
223
+ - Now uses `byteslice` and byte-aware concatenation for all edit operations
224
+ - Prevents gemspec templating from producing mangled output with duplicated Gem::Specification blocks
225
+ - Fixed `PrismGemspec.replace_gemspec_fields` to correctly handle multi-byte UTF-8 characters (e.g., emojis)
226
+ - Prism uses byte offsets, not character offsets, when parsing Ruby code
227
+ - Changed string slicing from `String#[]` to `String#byteslice` for all offset-based operations
228
+ - Added validation to use `String#bytesize` instead of `String#length` for offset bounds checking
229
+ - Prevents `TypeError: no implicit conversion of nil into String` when gemspecs contain emojis
230
+ - Ensures gemspec field carryover works correctly with emoji in summary/description fields
231
+ - Enhanced error reporting to show backtraces when debug mode is enabled
232
+
233
+ ## [1.2.5] - 2025-11-28
234
+
235
+ - TAG: [v1.2.5][1.2.5t]
236
+ - COVERAGE: 93.53% -- 4726/5053 lines in 31 files
237
+ - BRANCH COVERAGE: 76.62% -- 1924/2511 branches in 31 files
238
+ - 69.89% documented
239
+
240
+ ### Added
241
+
242
+ - Comprehensive newline normalization in templated Ruby files:
243
+ - Magic comments (frozen_string_literal, encoding, etc.) always followed by single blank line
244
+ - No more than one consecutive blank line anywhere in file
245
+ - Single newline at end of file (no trailing blank lines)
246
+ - Freeze reminder block now includes blank line before and empty comment line after for better visual separation
247
+
248
+ ### Changed
249
+
250
+ - Updated `FREEZE_REMINDER` constant to include blank line before and empty comment line after
251
+
252
+ ### Fixed
253
+
254
+ - Fixed `reminder_present?` to correctly detect freeze reminder when it has leading blank line
255
+
33
256
  ## [1.2.4] - 2025-11-28
34
257
 
35
258
  - TAG: [v1.2.4][1.2.4t]
@@ -45,7 +268,7 @@ Please file a bug if you notice a violation of semantic versioning.
45
268
  - Ensures truly idempotent behavior when running templating multiple times on the same file
46
269
  - Example: `frozen_string_literal` comments no longer multiply from 1→4→5→6 on repeated runs
47
270
 
48
- ## [1.2.3] - 2025-11-28
271
+ ## [1.2.3] - 2025-11-28vari
49
272
 
50
273
  - TAG: [v1.2.3][1.2.3t]
51
274
  - COVERAGE: 93.43% -- 4681/5010 lines in 31 files
@@ -1138,7 +1361,7 @@ Please file a bug if you notice a violation of semantic versioning.
1138
1361
  - <!-- RELEASE-NOTES-FOOTER-END -->
1139
1362
  - truffle workflow: Repeat attempts for bundle install and appraisal bundle before failure
1140
1363
  - global token replacement during kettle:dev:install
1141
- - {KETTLE|DEV|GEM} => kettle-dev
1364
+ - kettle-dev => kettle-dev
1142
1365
  - {RUBOCOP|LTS|CONSTRAINT} => dynamic
1143
1366
  - {RUBOCOP|RUBY|GEM} => dynamic
1144
1367
  - default to rubocop-ruby1_8 if no minimum ruby specified
@@ -1522,7 +1745,13 @@ Please file a bug if you notice a violation of semantic versioning.
1522
1745
  - Selecting will run the selected workflow via `act`
1523
1746
  - This may move to its own gem in the future.
1524
1747
 
1525
- [Unreleased]: https://github.com/kettle-rb/kettle-dev/compare/v1.2.4...HEAD
1748
+ [Unreleased]: https://github.com/kettle-rb/kettle-dev/compare/v2.0.1...HEAD
1749
+ [2.0.1]: https://github.com/kettle-rb/kettle-dev/compare/v2.0.0...v2.0.1
1750
+ [2.0.1t]: https://github.com/kettle-rb/kettle-dev/releases/tag/v2.0.1
1751
+ [2.0.0]: https://github.com/kettle-rb/kettle-dev/compare/v1.2.5...v2.0.0
1752
+ [2.0.0t]: https://github.com/kettle-rb/kettle-dev/releases/tag/v2.0.0
1753
+ [1.2.5]: https://github.com/kettle-rb/kettle-dev/compare/v1.2.4...v1.2.5
1754
+ [1.2.5t]: https://github.com/kettle-rb/kettle-dev/releases/tag/v1.2.5
1526
1755
  [1.2.4]: https://github.com/kettle-rb/kettle-dev/compare/v1.2.3...v1.2.4
1527
1756
  [1.2.4t]: https://github.com/kettle-rb/kettle-dev/releases/tag/v1.2.4
1528
1757
  [1.2.3]: https://github.com/kettle-rb/kettle-dev/compare/v1.2.2...v1.2.3
data/CITATION.cff CHANGED
@@ -1,19 +1,19 @@
1
1
  cff-version: 1.2.0
2
- title: kettle-dev
2
+ title: "kettle-dev"
3
3
  message: >-
4
4
  If you use this work and you want to cite it,
5
5
  then you can use the metadata from this file.
6
6
  type: software
7
7
  authors:
8
- - given-names: Peter Hurn
9
- family-names: Boling
10
- email: peter@railsbling.com
11
- affiliation: railsbling.com
8
+ - given-names: "Peter H."
9
+ family-names: "Boling"
10
+ email: "floss@galtzo.com"
11
+ affiliation: "galtzo.com"
12
12
  orcid: 'https://orcid.org/0009-0008-8519-441X'
13
13
  identifiers:
14
14
  - type: url
15
15
  value: 'https://github.com/kettle-rb/kettle-dev'
16
- description: kettle-dev
16
+ description: "kettle-dev"
17
17
  repository-code: 'https://github.com/kettle-rb/kettle-dev'
18
18
  abstract: >-
19
19
  kettle-dev
data/CONTRIBUTING.md CHANGED
@@ -8,25 +8,34 @@ To submit a patch, please fork the project, create a patch with tests, and send
8
8
 
9
9
  Remember to [![Keep A Changelog][📗keep-changelog-img]][📗keep-changelog] if you make changes.
10
10
 
11
+ ## Developer Certificate of Origin
12
+
13
+ In order to protect users of this project, we require all contributors to comply with the
14
+ [Developer Certificate of Origin](https://developercertificate.org/).
15
+ This ensures that all contributions are properly licensed and attributed.
16
+
11
17
  ## Help out!
12
18
 
13
- Take a look at the `reek` list which is the file called `REEK` and find something to improve.
19
+ Take a look at the open issues and pull requests, or use the gem and find something to improve.
14
20
 
15
21
  Follow these instructions:
16
22
 
17
- 1. Fork the repository
18
- 2. Create a feature branch (`git checkout -b my-new-feature`)
19
- 3. Make some fixes.
20
- 4. Commit changes (`git commit -am 'Added some feature'`)
21
- 5. Push to the branch (`git push origin my-new-feature`)
22
- 6. Make sure to add tests for it. This is important, so it doesn't break in a future release.
23
- 7. Create new Pull Request.
23
+ 1. Join the Discord: [![Live Chat on Discord][✉️discord-invite-img]][✉️discord-invite]
24
+ 2. Fork the repository
25
+ 3. Create your feature branch (`git checkout -b my-new-feature`)
26
+ 4. Make some fixes.
27
+ 5. Commit your changes (`git commit -am 'Added some feature'`)
28
+ 6. Push to the branch (`git push origin my-new-feature`)
29
+ 7. Make sure to add tests for it. This is important, so it doesn't break in a future release.
30
+ 8. Create new Pull Request.
31
+ 9. Announce it in the channel for this org in the [Discord][✉️discord-invite]!
24
32
 
25
33
  ## Executables vs Rake tasks
26
34
 
27
- Executables shipped by kettle-dev can be used with or without generating the binstubs.
28
- They will work when kettle-dev is installed globally (i.e., `gem install kettle-dev`) and do not require that kettle-dev be in your bundle.
35
+ Executables shipped by dependencies, such as kettle-dev, and stone_checksums, are available
36
+ after running `bin/setup`. These include:
29
37
 
38
+ - gem_checksums
30
39
  - kettle-changelog
31
40
  - kettle-commit-msg
32
41
  - kettle-dev-setup
@@ -35,20 +44,26 @@ They will work when kettle-dev is installed globally (i.e., `gem install kettle-
35
44
  - kettle-readme-backers
36
45
  - kettle-release
37
46
 
38
- However, the rake tasks provided by kettle-dev do require kettle-dev to be added as a development dependency and loaded in your Rakefile.
39
- See the full list of rake tasks in head of Rakefile
47
+ There are many Rake tasks available as well. You can see them by running:
40
48
 
41
- **Gemfile**
42
- ```ruby
43
- group :development do
44
- gem "kettle-dev", require: false
45
- end
49
+ ```shell
50
+ bin/rake -T
46
51
  ```
47
52
 
48
- **Rakefile**
49
- ```ruby
50
- # Rakefile
51
- require "kettle/dev"
53
+ ## Code quality checks
54
+
55
+ Run the Reek task when you want a smell check that fails on current findings:
56
+
57
+ ```shell
58
+ bin/rake reek
59
+ ```
60
+
61
+ Refresh the checked-in `REEK` backlog through the rake task, not by redirecting
62
+ the raw `reek` executable output. The rake task uses the project bundle and
63
+ avoids stale generated binstubs shadowing the Reek gem executable:
64
+
65
+ ```shell
66
+ bin/rake reek:update
52
67
  ```
53
68
 
54
69
  ## Environment Variables for Local Development
@@ -61,7 +76,7 @@ General/runtime
61
76
  - CI: When set to true, adjusts default rake tasks toward CI behavior
62
77
 
63
78
  Coverage (kettle-soup-cover / SimpleCov)
64
- - K_SOUP_COV_DO: Enable coverage collection (default: true in .envrc)
79
+ - K_SOUP_COV_DO: Enable coverage collection (default: true in `mise.toml`)
65
80
  - K_SOUP_COV_FORMATTERS: Comma-separated list of formatters (html, xml, rcov, lcov, json, tty)
66
81
  - K_SOUP_COV_MIN_LINE: Minimum line coverage threshold (integer, e.g., 100)
67
82
  - K_SOUP_COV_MIN_BRANCH: Minimum branch coverage threshold (integer, e.g., 100)
@@ -77,7 +92,9 @@ GitHub API and CI helpers
77
92
  Releasing and signing
78
93
  - SKIP_GEM_SIGNING: If set, skip gem signing during build/release
79
94
  - GEM_CERT_USER: Username for selecting your public cert in `certs/<USER>.pem` (defaults to $USER)
80
- - SOURCE_DATE_EPOCH: Reproducible build timestamp. `kettle-release` will set this automatically for the session.
95
+ - SOURCE_DATE_EPOCH: Reproducible build timestamp.
96
+ - `kettle-release` will set this automatically for the session.
97
+ - Not needed on bundler >= 2.7.0, as reproducible builds have become the default.
81
98
 
82
99
  Git hooks and commit message helpers (exe/kettle-commit-msg)
83
100
  - GIT_HOOK_BRANCH_VALIDATE: Branch name validation mode (e.g., `jira`) or `false` to disable
@@ -85,7 +102,7 @@ Git hooks and commit message helpers (exe/kettle-commit-msg)
85
102
  - GIT_HOOK_FOOTER_SENTINEL: Required when footer append is enabled — a unique first-line sentinel to prevent duplicates
86
103
  - GIT_HOOK_FOOTER_APPEND_DEBUG: Extra debug output in the footer template (true/false)
87
104
 
88
- For a quick starting point, this repository’s `.envrc` shows sane defaults, and `.env.local` can override them locally.
105
+ For a quick starting point, this repository’s `mise.toml` defines the shared defaults, and `.env.local` can override them locally. Copy `.env.local.example` to `.env.local`, use `KEY=value` lines, and either activate `mise` in your shell or run commands through `mise exec -C /path/to/project -- ...`.
89
106
 
90
107
  ## Appraisals
91
108
 
@@ -104,22 +121,20 @@ bin/rake appraisal:reset
104
121
 
105
122
  When adding an appraisal to CI, check the [runner tool cache][🏃‍♂️runner-tool-cache] to see which runner to use.
106
123
 
107
- ## The Reek List
108
-
109
- Take a look at the `reek` list which is the file called `REEK` and find something to improve.
124
+ ## Run Tests
110
125
 
111
- To refresh the `reek` list:
126
+ Run tests via `kettle-test` (provided by `kettle-test`). It runs RSpec, writes the full log to
127
+ `tmp/kettle-test/rspec-TIMESTAMP.log`, and prints a compact highlight block with timing, seed,
128
+ pass/fail count, failing example list, and SimpleCov coverage percentages.
112
129
 
113
130
  ```console
114
- bundle exec reek > REEK
131
+ bundle exec kettle-test
115
132
  ```
116
133
 
117
- ## Run Tests
118
-
119
- To run all tests
134
+ For targeted runs, disable the hard coverage threshold to avoid false failures:
120
135
 
121
136
  ```console
122
- bundle exec rake test
137
+ K_SOUP_COV_MIN_HARD=false bundle exec kettle-test spec/path/to/spec.rb
123
138
  ```
124
139
 
125
140
  ### Spec organization (required)
@@ -148,7 +163,7 @@ For more detailed information about using RuboCop in this project, please see th
148
163
  Never add `# rubocop:disable ...` / `# rubocop:enable ...` comments to code or specs (except when following the few existing `rubocop:disable` patterns for a rule already being disabled elsewhere in the code). Instead:
149
164
 
150
165
  - Prefer configuration-based exclusions when a rule should not apply to certain paths or files (e.g., via `.rubocop.yml`).
151
- - When a violation is temporary and you plan to fix it later, record it in `.rubocop_gradual.lock` using the gradual workflow:
166
+ - When a violation is temporary, and you plan to fix it later, record it in `.rubocop_gradual.lock` using the gradual workflow:
152
167
  - `bundle exec rake rubocop_gradual:autocorrect` (preferred)
153
168
  - `bundle exec rake rubocop_gradual:force_update` (only when you cannot fix the violations immediately)
154
169
 
@@ -183,39 +198,41 @@ NOTE: To build without signing the gem set `SKIP_GEM_SIGNING` to any value in th
183
198
  1. Update version.rb to contain the correct version-to-be-released.
184
199
  2. Run `bundle exec kettle-changelog`.
185
200
  3. Run `bundle exec kettle-release`.
201
+ 4. Stay awake and monitor the release process for any errors, and answer any prompts.
186
202
 
187
203
  #### Manual process
188
204
 
189
205
  1. Run `bin/setup && bin/rake` as a "test, coverage, & linting" sanity check
190
206
  2. Update the version number in `version.rb`, and ensure `CHANGELOG.md` reflects changes
191
207
  3. Run `bin/setup && bin/rake` again as a secondary check, and to update `Gemfile.lock`
192
- 4. Run `git commit -am "🔖 Prepare release v<VERSION>"` to commit the changes
193
- 5. Run `git push` to trigger the final CI pipeline before release, and merge PRs
208
+ 4. Run `bin/rake yard` to regenerate the docs site using the canonical docs task
209
+ 5. Run `git commit -am "🔖 Prepare release v<VERSION>"` to commit the changes
210
+ 6. Run `git push` to trigger the final CI pipeline before release, and merge PRs
194
211
  - NOTE: Remember to [check the build][🧪build].
195
- 6. Run `export GIT_TRUNK_BRANCH_NAME="$(git remote show origin | grep 'HEAD branch' | cut -d ' ' -f5)" && echo $GIT_TRUNK_BRANCH_NAME`
196
- 7. Run `git checkout $GIT_TRUNK_BRANCH_NAME`
197
- 8. Run `git pull origin $GIT_TRUNK_BRANCH_NAME` to ensure latest trunk code
198
- 9. Optional for older Bundler (< 2.7.0): Set `SOURCE_DATE_EPOCH` so `rake build` and `rake release` use the same timestamp and generate the same checksums
212
+ 7. Run `export GIT_TRUNK_BRANCH_NAME="$(git remote show origin | grep 'HEAD branch' | cut -d ' ' -f5)" && echo $GIT_TRUNK_BRANCH_NAME`
213
+ 8. Run `git checkout $GIT_TRUNK_BRANCH_NAME`
214
+ 9. Run `git pull origin $GIT_TRUNK_BRANCH_NAME` to ensure latest trunk code
215
+ 10. Optional for older Bundler (< 2.7.0): Set `SOURCE_DATE_EPOCH` so `rake build` and `rake release` use the same timestamp and generate the same checksums
199
216
  - If your Bundler is >= 2.7.0, you can skip this; builds are reproducible by default.
200
217
  - Run `export SOURCE_DATE_EPOCH=$EPOCHSECONDS && echo $SOURCE_DATE_EPOCH`
201
218
  - If the echo above has no output, then it didn't work.
202
219
  - Note: `zsh/datetime` module is needed, if running `zsh`.
203
220
  - In older versions of `bash` you can use `date +%s` instead, i.e. `export SOURCE_DATE_EPOCH=$(date +%s) && echo $SOURCE_DATE_EPOCH`
204
- 10. Run `bundle exec rake build`
205
- 11. Run `bin/gem_checksums` (more context [1][🔒️rubygems-checksums-pr], [2][🔒️rubygems-guides-pr])
221
+ 11. Run `bundle exec rake build`
222
+ 12. Run `bin/gem_checksums` (more context [1][🔒️rubygems-checksums-pr], [2][🔒️rubygems-guides-pr])
206
223
  to create SHA-256 and SHA-512 checksums. This functionality is provided by the `stone_checksums`
207
224
  [gem][💎stone_checksums].
208
225
  - The script automatically commits but does not push the checksums
209
- 12. Sanity check the SHA256, comparing with the output from the `bin/gem_checksums` command:
226
+ 13. Sanity check the SHA256, comparing with the output from the `bin/gem_checksums` command:
210
227
  - `sha256sum pkg/<gem name>-<version>.gem`
211
- 13. Run `bundle exec rake release` which will create a git tag for the version,
228
+ 14. Run `bundle exec rake release` which will create a git tag for the version,
212
229
  push git commits and tags, and push the `.gem` file to the gem host configured in the gemspec.
213
230
 
214
- [📜src-gl]: https://gitlab.com/kettle-rb/kettle-dev/
231
+ [📜src-gl]: https://gitlab.com/kettle-rb/kettle-dev
215
232
  [📜src-cb]: https://codeberg.org/kettle-rb/kettle-dev
216
233
  [📜src-gh]: https://github.com/kettle-rb/kettle-dev
217
234
  [🧪build]: https://github.com/kettle-rb/kettle-dev/actions
218
- [🤝conduct]: https://gitlab.com/kettle-rb/kettle-dev/-/blob/main/CODE_OF_CONDUCT.md
235
+ [🤝conduct]: https://github.com/kettle-rb/kettle-dev/blob/main/CODE_OF_CONDUCT.md
219
236
  [🖐contrib-rocks]: https://contrib.rocks
220
237
  [🖐contributors]: https://github.com/kettle-rb/kettle-dev/graphs/contributors
221
238
  [🚎contributors-gl]: https://gitlab.com/kettle-rb/kettle-dev/-/graphs/main
@@ -231,3 +248,4 @@ NOTE: To build without signing the gem set `SKIP_GEM_SIGNING` to any value in th
231
248
  [📌major-versions-not-sacred]: https://tom.preston-werner.com/2022/05/23/major-version-numbers-are-not-sacred.html
232
249
  [🚎appraisal2]: https://github.com/appraisal-rb/appraisal2
233
250
  [🏃‍♂️runner-tool-cache]: https://github.com/ruby/ruby-builder/releases/tag/toolcache
251
+ [✉️discord-invite]: https://discord.gg/3qme4XHNKN
data/FUNDING.md CHANGED
@@ -19,7 +19,7 @@ Many paths lead to being a sponsor or a backer of this project. Are you on such
19
19
  [🖇polar-img]: https://img.shields.io/badge/polar-donate-a51611.svg?style=flat
20
20
  [🖇polar]: https://polar.sh/pboling
21
21
  [🖇kofi-img]: https://img.shields.io/badge/ko--fi-%E2%9C%93-a51611.svg?style=flat
22
- [🖇kofi]: https://ko-fi.com/O5O86SNP4
22
+ [🖇kofi]: https://ko-fi.com/pboling
23
23
  [🖇patreon-img]: https://img.shields.io/badge/patreon-donate-a51611.svg?style=flat
24
24
  [🖇patreon]: https://patreon.com/galtzo
25
25
  [🖇buyme-small-img]: https://img.shields.io/badge/buy_me_a_coffee-%E2%9C%93-a51611.svg?style=flat
data/LICENSE.md ADDED
@@ -0,0 +1,12 @@
1
+ # License
2
+
3
+ This project is made available under the following license.
4
+ Choose the option that best fits your use case:
5
+
6
+ - [AGPL-3.0-only](AGPL-3.0-only.md)
7
+
8
+ If none of the above licenses fit your use case, please [contact us](mailto:floss@galtzo.com) to discuss a custom commercial license.
9
+
10
+ ## Copyright Notice
11
+
12
+ Copyright (c) 2023, 2025-2026 Peter H. Boling