kettle-dev 1.2.0 → 1.2.2
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 +2 -1
- data/CHANGELOG.md +25 -2
- data/README.md +1 -1
- data/README.md.example +1 -1
- data/Rakefile.example +1 -1
- data/exe/kettle-changelog +18 -3
- data/lib/kettle/dev/changelog_cli.rb +88 -22
- data/lib/kettle/dev/modular_gemfiles.rb +6 -5
- data/lib/kettle/dev/{appraisals_ast_merger.rb → prism_appraisals.rb} +53 -85
- data/lib/kettle/dev/prism_gemfile.rb +177 -0
- data/lib/kettle/dev/prism_gemspec.rb +284 -0
- data/lib/kettle/dev/prism_utils.rb +13 -0
- data/lib/kettle/dev/readme_backers.rb +1 -4
- data/lib/kettle/dev/setup_cli.rb +17 -28
- data/lib/kettle/dev/source_merger.rb +116 -3
- data/lib/kettle/dev/tasks/template_task.rb +21 -85
- data/lib/kettle/dev/template_helpers.rb +53 -116
- data/lib/kettle/dev/version.rb +1 -1
- data/lib/kettle/dev.rb +21 -3
- data.tar.gz.sig +0 -0
- metadata +7 -5
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: cc18821059e69cb633ba8dbde14b8edf85b999738d86044c5df905f82a203bab
|
|
4
|
+
data.tar.gz: b534a2bf911e1a6ff8618209caebb93fbad634e647a454344ccc4221a5a58b1f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3978928d9ef6fda478251deda2c79818bc645bff3b6150e44e4b2a8ebbf13c49de8a676d76eb8ff0795d3c93c7a326c5fa153562f8ac9a93f95e083e2d077723
|
|
7
|
+
data.tar.gz: 3686018133d386691fefdab49fa10e7dea1c4a4ae65e2486cd161091a0d98e7e2b76721b9f45edc536763dfa8d2f1dbc97bcc83f90a39d1149f8c414873ed02a
|
checksums.yaml.gz.sig
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
-����g*�y��aʨ��n]}�
|
|
2
|
+
���3�#���U4f�����ٖ�Q{�m߇��E�v����J�������9&4m��n��Q>t���ȋ�������5��G�����C��3��9�iS�ð��:;����!<�e)�H��۲=˄4q2�P��E���+���^��w�W�Z�ų�$m�I[��%��2�5lZL!�o߹�Z����v�{�T�]�K����Mw�Č�۠j�r�%�'����hr���8��p��;��VG{Se��6�,pgx���S�u�U�?�^�t3S��*PN[>��qb��y�<���$�����de�N�Ly��CQh_�������D�n2 !0�J����^�IL(Z
|
data/CHANGELOG.md
CHANGED
|
@@ -30,7 +30,28 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
30
30
|
|
|
31
31
|
### Security
|
|
32
32
|
|
|
33
|
-
## [1.2.
|
|
33
|
+
## [1.2.2] - 2025-11-27
|
|
34
|
+
|
|
35
|
+
- TAG: [v1.2.2][1.2.2t]
|
|
36
|
+
- COVERAGE: 93.28% -- 4596/4927 lines in 31 files
|
|
37
|
+
- BRANCH COVERAGE: 76.45% -- 1883/2463 branches in 31 files
|
|
38
|
+
- 70.00% documented
|
|
39
|
+
|
|
40
|
+
### Added
|
|
41
|
+
|
|
42
|
+
- Prism AST-based manipulation of ruby during templating
|
|
43
|
+
- Gemfiles
|
|
44
|
+
- gemspecs
|
|
45
|
+
- .simplecov
|
|
46
|
+
- Stop rescuing Exception in certain scenarios (just StandardError)
|
|
47
|
+
- Refactored logging logic and documentation
|
|
48
|
+
- Prevent self-referential gemfile injection
|
|
49
|
+
- in Gemfiles, gemspecs, and Appraisals
|
|
50
|
+
- Improve reliability of coverage and documentation stats
|
|
51
|
+
- in the changelog version heading
|
|
52
|
+
- fails hard when unable to generate stats, unless `--no-strict` provided
|
|
53
|
+
|
|
54
|
+
## [1.2.1] - 2025-11-25
|
|
34
55
|
|
|
35
56
|
- TAG: [v1.2.0][1.2.0t]
|
|
36
57
|
- COVERAGE: 94.38% -- 4066/4308 lines in 26 files
|
|
@@ -1470,7 +1491,9 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
1470
1491
|
- Selecting will run the selected workflow via `act`
|
|
1471
1492
|
- This may move to its own gem in the future.
|
|
1472
1493
|
|
|
1473
|
-
[Unreleased]: https://github.com/kettle-rb/kettle-dev/compare/v1.2.
|
|
1494
|
+
[Unreleased]: https://github.com/kettle-rb/kettle-dev/compare/v1.2.2...HEAD
|
|
1495
|
+
[1.2.2]: https://github.com/kettle-rb/kettle-dev/compare/v1.2.1...v1.2.2
|
|
1496
|
+
[1.2.2t]: https://github.com/kettle-rb/kettle-dev/releases/tag/v1.2.2
|
|
1474
1497
|
[1.2.0]: https://github.com/kettle-rb/kettle-dev/compare/v1.1.60...v1.2.0
|
|
1475
1498
|
[1.2.0t]: https://github.com/kettle-rb/kettle-dev/releases/tag/v1.2.0
|
|
1476
1499
|
[1.1.60]: https://github.com/kettle-rb/kettle-dev/compare/v1.1.59...v1.1.60
|
data/README.md
CHANGED
|
@@ -1026,7 +1026,7 @@ Thanks for RTFM. ☺️
|
|
|
1026
1026
|
[📌gitmoji]: https://gitmoji.dev
|
|
1027
1027
|
[📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
1028
1028
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
1029
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-4.
|
|
1029
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-4.927-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
|
1030
1030
|
[🔐security]: SECURITY.md
|
|
1031
1031
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
|
1032
1032
|
[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
|
data/README.md.example
CHANGED
|
@@ -548,7 +548,7 @@ Thanks for RTFM. ☺️
|
|
|
548
548
|
[📌gitmoji]: https://gitmoji.dev
|
|
549
549
|
[📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
550
550
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
551
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-4.
|
|
551
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-4.927-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
|
552
552
|
[🔐security]: SECURITY.md
|
|
553
553
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
|
554
554
|
[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
|
data/Rakefile.example
CHANGED
data/exe/kettle-changelog
CHANGED
|
@@ -50,22 +50,37 @@ end
|
|
|
50
50
|
begin
|
|
51
51
|
if ARGV.include?("-h") || ARGV.include?("--help")
|
|
52
52
|
puts <<~USAGE
|
|
53
|
-
Usage: kettle-changelog
|
|
53
|
+
Usage: kettle-changelog [--no-strict]
|
|
54
54
|
|
|
55
55
|
Generates a new CHANGELOG.md entry for the current version detected from lib/**/version.rb.
|
|
56
56
|
Moves entries from [Unreleased] into the new section, adds coverage and documentation stats,
|
|
57
57
|
and updates bottom link references to GitHub style, adding new compare/tag links.
|
|
58
58
|
|
|
59
|
+
Options:
|
|
60
|
+
--no-strict Allow missing coverage and yard data (warnings only, no errors)
|
|
61
|
+
|
|
62
|
+
Environment:
|
|
63
|
+
K_CHANGELOG_STRICT=false Disable strict mode (equivalent to --no-strict flag)
|
|
64
|
+
|
|
59
65
|
Prerequisites:
|
|
60
|
-
- coverage/coverage.json present (run:
|
|
66
|
+
- coverage/coverage.json present (run: bin/rake coverage to generate)
|
|
61
67
|
- yard installed and available via bin/yard
|
|
68
|
+
|
|
69
|
+
By default (strict mode), if coverage.json or yard stats are missing, the script will:
|
|
70
|
+
1. Attempt to generate them by running bin/rake coverage and bin/rake yard
|
|
71
|
+
2. Fail with an error if generation fails or data is still unavailable
|
|
72
|
+
|
|
73
|
+
Use --no-strict or K_CHANGELOG_STRICT=false to allow missing data (backward compatible behavior).
|
|
62
74
|
USAGE
|
|
63
75
|
exit(0)
|
|
64
76
|
end
|
|
65
77
|
end
|
|
66
78
|
|
|
67
79
|
begin
|
|
68
|
-
|
|
80
|
+
# Determine if strict mode is enabled (default: true)
|
|
81
|
+
strict_mode = !ARGV.include?("--no-strict") && ENV.fetch("K_CHANGELOG_STRICT", "true").downcase != "false"
|
|
82
|
+
|
|
83
|
+
Kettle::Dev::ChangelogCLI.new(strict: strict_mode).run
|
|
69
84
|
rescue LoadError => e
|
|
70
85
|
warn("#{script_basename}: could not load dependency: #{e.class}: #{e.message}")
|
|
71
86
|
warn(e.backtrace.join("\n")) if ENV["DEBUG"]
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "open3"
|
|
4
|
+
|
|
3
5
|
module Kettle
|
|
4
6
|
module Dev
|
|
5
7
|
# CLI for updating CHANGELOG.md with new version sections
|
|
@@ -11,10 +13,12 @@ module Kettle
|
|
|
11
13
|
|
|
12
14
|
# Initialize the changelog CLI
|
|
13
15
|
# Sets up paths for CHANGELOG.md and coverage.json
|
|
14
|
-
|
|
16
|
+
# @param strict [Boolean] when true (default), require coverage and yard data; raise errors if unavailable
|
|
17
|
+
def initialize(strict: true)
|
|
15
18
|
@root = Kettle::Dev::CIHelpers.project_root
|
|
16
19
|
@changelog_path = File.join(@root, "CHANGELOG.md")
|
|
17
20
|
@coverage_path = File.join(@root, "coverage", "coverage.json")
|
|
21
|
+
@strict = strict
|
|
18
22
|
end
|
|
19
23
|
|
|
20
24
|
# Main entry point to update CHANGELOG.md
|
|
@@ -215,11 +219,49 @@ module Kettle
|
|
|
215
219
|
end
|
|
216
220
|
|
|
217
221
|
def coverage_lines
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
+
if @strict
|
|
223
|
+
# Always generate fresh coverage data in strict mode
|
|
224
|
+
# Delete old coverage files to ensure we get current data
|
|
225
|
+
coverage_dir = File.dirname(@coverage_path)
|
|
226
|
+
if Dir.exist?(coverage_dir)
|
|
227
|
+
puts "Cleaning old coverage data from #{coverage_dir}..."
|
|
228
|
+
Dir.glob(File.join(coverage_dir, "*")).each do |file|
|
|
229
|
+
File.delete(file) if File.file?(file)
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
puts "Generating fresh coverage data by running: bin/rake coverage"
|
|
234
|
+
|
|
235
|
+
# Run bin/rake coverage to generate coverage.json
|
|
236
|
+
rake_cmd = File.join(@root, "bin", "rake")
|
|
237
|
+
unless File.executable?(rake_cmd)
|
|
238
|
+
raise "bin/rake not found or not executable; cannot generate coverage data"
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# Run the command exactly as the user would run it manually
|
|
242
|
+
# The coverage task knows how to configure itself properly
|
|
243
|
+
success = system(rake_cmd, "coverage", chdir: @root)
|
|
244
|
+
|
|
245
|
+
unless success
|
|
246
|
+
raise "bin/rake coverage failed with exit status #{$?.exitstatus || "unknown"}"
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
puts "Coverage generation complete."
|
|
250
|
+
|
|
251
|
+
# Check if coverage.json was generated
|
|
252
|
+
unless File.file?(@coverage_path)
|
|
253
|
+
raise "Coverage JSON not found at #{@coverage_path} after running bin/rake coverage"
|
|
254
|
+
end
|
|
255
|
+
else
|
|
256
|
+
# Non-strict mode: check if coverage.json exists, warn if not
|
|
257
|
+
unless File.file?(@coverage_path)
|
|
258
|
+
warn("Coverage JSON not found at #{@coverage_path}.")
|
|
259
|
+
warn("Run: bin/rake coverage to generate it")
|
|
260
|
+
return [nil, nil]
|
|
261
|
+
end
|
|
222
262
|
end
|
|
263
|
+
|
|
264
|
+
# Parse the coverage data
|
|
223
265
|
data = JSON.parse(File.read(@coverage_path))
|
|
224
266
|
files = data["coverage"] || {}
|
|
225
267
|
file_count = 0
|
|
@@ -252,31 +294,55 @@ module Kettle
|
|
|
252
294
|
line_str = format("COVERAGE: %.2f%% -- %d/%d lines in %d files", line_pct, covered_lines, total_lines, file_count)
|
|
253
295
|
branch_str = format("BRANCH COVERAGE: %.2f%% -- %d/%d branches in %d files", branch_pct, covered_branches, total_branches, file_count)
|
|
254
296
|
[line_str, branch_str]
|
|
297
|
+
rescue JSON::ParserError => e
|
|
298
|
+
if @strict
|
|
299
|
+
raise "Failed to parse coverage JSON at #{@coverage_path}: #{e.class}: #{e.message}"
|
|
300
|
+
else
|
|
301
|
+
warn("Failed to parse coverage: #{e.class}: #{e.message}")
|
|
302
|
+
[nil, nil]
|
|
303
|
+
end
|
|
255
304
|
rescue StandardError => e
|
|
256
|
-
|
|
257
|
-
|
|
305
|
+
if @strict
|
|
306
|
+
raise "Failed to get coverage data: #{e.class}: #{e.message}"
|
|
307
|
+
else
|
|
308
|
+
warn("Failed to get coverage data: #{e.class}: #{e.message}")
|
|
309
|
+
[nil, nil]
|
|
310
|
+
end
|
|
258
311
|
end
|
|
259
312
|
|
|
260
313
|
def yard_percent_documented
|
|
261
314
|
cmd = File.join(@root, "bin", "yard")
|
|
262
315
|
unless File.executable?(cmd)
|
|
263
|
-
|
|
264
|
-
|
|
316
|
+
if @strict
|
|
317
|
+
raise "bin/yard not found or not executable; ensure yard is installed via bundler"
|
|
318
|
+
else
|
|
319
|
+
warn("bin/yard not found or not executable; ensure yard is installed via bundler")
|
|
320
|
+
return
|
|
321
|
+
end
|
|
265
322
|
end
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
line
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
323
|
+
|
|
324
|
+
begin
|
|
325
|
+
# Run bin/yard to get documentation percentage
|
|
326
|
+
out, _ = Open3.capture2(cmd, {chdir: @root})
|
|
327
|
+
# Look for a line containing e.g., "95.35% documented"
|
|
328
|
+
line = out.lines.find { |l| l =~ /\d+(?:\.\d+)?%\s+documented/ }
|
|
329
|
+
|
|
330
|
+
if line
|
|
331
|
+
line.strip
|
|
332
|
+
elsif @strict
|
|
333
|
+
raise "Could not find documented percentage in bin/yard output"
|
|
334
|
+
else
|
|
335
|
+
warn("Could not find documented percentage in bin/yard output.")
|
|
336
|
+
nil
|
|
337
|
+
end
|
|
338
|
+
rescue StandardError => e
|
|
339
|
+
if @strict
|
|
340
|
+
raise "Failed to run bin/yard: #{e.class}: #{e.message}"
|
|
341
|
+
else
|
|
342
|
+
warn("Failed to run bin/yard: #{e.class}: #{e.message}")
|
|
343
|
+
nil
|
|
344
|
+
end
|
|
276
345
|
end
|
|
277
|
-
rescue StandardError => e
|
|
278
|
-
warn("Failed to run bin/yard: #{e.class}: #{e.message}")
|
|
279
|
-
nil
|
|
280
346
|
end
|
|
281
347
|
|
|
282
348
|
# Transform legacy release headings that include a tag suffix, e.g.:
|
|
@@ -36,9 +36,9 @@ module Kettle
|
|
|
36
36
|
modular_gemfile = "#{base}.gemfile"
|
|
37
37
|
src = helpers.prefer_example(File.join(gem_checkout_root, MODULAR_GEMFILE_DIR, modular_gemfile))
|
|
38
38
|
dest = File.join(project_root, MODULAR_GEMFILE_DIR, modular_gemfile)
|
|
39
|
-
existing = File.exist?(dest) ? File.read(dest) : nil
|
|
40
39
|
helpers.copy_file_with_prompt(src, dest, allow_create: true, allow_replace: true) do |content|
|
|
41
|
-
|
|
40
|
+
# Use apply_strategy for proper AST-based merging with Prism
|
|
41
|
+
helpers.apply_strategy(content, dest)
|
|
42
42
|
end
|
|
43
43
|
end
|
|
44
44
|
|
|
@@ -46,7 +46,6 @@ module Kettle
|
|
|
46
46
|
modular_gemfile = "style.gemfile"
|
|
47
47
|
src = helpers.prefer_example(File.join(gem_checkout_root, MODULAR_GEMFILE_DIR, modular_gemfile))
|
|
48
48
|
dest = File.join(project_root, MODULAR_GEMFILE_DIR, modular_gemfile)
|
|
49
|
-
existing_style = File.exist?(dest) ? File.read(dest) : nil
|
|
50
49
|
if File.basename(src).sub(/\.example\z/, "") == "style.gemfile"
|
|
51
50
|
helpers.copy_file_with_prompt(src, dest, allow_create: true, allow_replace: true) do |content|
|
|
52
51
|
# Adjust rubocop-lts constraint based on min_ruby
|
|
@@ -98,11 +97,13 @@ module Kettle
|
|
|
98
97
|
token = "{RUBOCOP|RUBY|GEM}"
|
|
99
98
|
content.gsub!(token, "rubocop-ruby#{rubocop_ruby_gem_version}") if content.include?(token)
|
|
100
99
|
end
|
|
101
|
-
|
|
100
|
+
# Use apply_strategy for proper AST-based merging with Prism
|
|
101
|
+
helpers.apply_strategy(content, dest)
|
|
102
102
|
end
|
|
103
103
|
else
|
|
104
104
|
helpers.copy_file_with_prompt(src, dest, allow_create: true, allow_replace: true) do |content|
|
|
105
|
-
|
|
105
|
+
# Use apply_strategy for proper AST-based merging with Prism
|
|
106
|
+
helpers.apply_strategy(content, dest)
|
|
106
107
|
end
|
|
107
108
|
end
|
|
108
109
|
|