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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c5ef625cbc6016859cd2c88105ce957e3719465cee97356df1fc77a30c8504c1
4
- data.tar.gz: e18d15a0d1da90c31991b4b6601b698633dad3e377145724f8fb277ec7b2a75a
3
+ metadata.gz: cc18821059e69cb633ba8dbde14b8edf85b999738d86044c5df905f82a203bab
4
+ data.tar.gz: b534a2bf911e1a6ff8618209caebb93fbad634e647a454344ccc4221a5a58b1f
5
5
  SHA512:
6
- metadata.gz: 227cb01388512c937d73fddf46deac2edf2b062f93a97b8e788ac0af4e21f8bd1b3a941dc4bf8eabfd5b494401e935e08a8d28d10fc1954b728e7148953e531b
7
- data.tar.gz: 336fe91aab36fd2ca958967fbc3cfaaa2d6cea7dbb5b1e4d63882526b1271561920d41c016f301b93eb533cb636d252e923882859c9be58fbe4bd586b29d870d
6
+ metadata.gz: 3978928d9ef6fda478251deda2c79818bc645bff3b6150e44e4b2a8ebbf13c49de8a676d76eb8ff0795d3c93c7a326c5fa153562f8ac9a93f95e083e2d077723
7
+ data.tar.gz: 3686018133d386691fefdab49fa10e7dea1c4a4ae65e2486cd161091a0d98e7e2b76721b9f45edc536763dfa8d2f1dbc97bcc83f90a39d1149f8c414873ed02a
checksums.yaml.gz.sig CHANGED
@@ -1 +1,2 @@
1
- !�5å����Ԇ��,@K:�v���Fr���%�������&��lv��,j_��r��Wy��yU%GU����6�knu|�b������b�g/&��5"K������DF`t<|�q����sǩ�:5^��'B `1����*˲���hV�J�ҥ,��.��*(�y���+�im(�$-�T�W-�x>o%Psw���kt)� �~F�Ȕ�h�‡,�\ �� d̎�������AEkH���>J�S���"9�,Y̛;�̄C�����ZN��ƍ �$hLx`�=�U����� �1J�;l~T��_��FiOm���6�dSс��o�aD^�1��/���Uw�����F|�3aX�31��A��T'$���b�N#�P{�Fz���v�
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�,p޲gx���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.0] - 2025-11-25
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.0...HEAD
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.308-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
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.308-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
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
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # kettle-dev Rakefile v1.2.0 - 2025-11-25
3
+ # kettle-dev Rakefile v1.2.2 - 2025-11-27
4
4
  # Ruby 2.3 (Safe Navigation) or higher required
5
5
  #
6
6
  # MIT License (see License.txt)
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: K_SOUP_COV_FORMATTERS="json" bin/rspec)
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
- Kettle::Dev::ChangelogCLI.new.run
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
- def initialize
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
- unless File.file?(@coverage_path)
219
- warn("Coverage JSON not found at #{@coverage_path}.")
220
- warn("Run: K_SOUP_COV_FORMATTERS=\"json\" bin/rspec")
221
- return [nil, nil]
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
- warn("Failed to parse coverage: #{e.class}: #{e.message}")
257
- [nil, nil]
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
- warn("bin/yard not found or not executable; ensure yard is installed via bundler")
264
- return
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
- out, _ = Open3.capture2(cmd)
267
- # Look for a line containing e.g., "95.35% documented"
268
- line = out.lines.find { |l| l =~ /\d+(?:\.\d+)?%\s+documented/ }
269
- if line
270
- line = line.strip
271
- # Return exactly as requested: e.g. "95.35% documented"
272
- line
273
- else
274
- warn("Could not find documented percentage in bin/yard output.")
275
- nil
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
- existing ? helpers.merge_gemfile_dependencies(content, existing) : content
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
- existing_style ? helpers.merge_gemfile_dependencies(content, existing_style) : content
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
- existing_style ? helpers.merge_gemfile_dependencies(content, existing_style) : content
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