kettle-dev 2.2.18 → 2.2.20

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: 9f361805b0355ac14c6b5a3f5d2555feb722b8c640a2550f46d2a8f7ab0c80c6
4
- data.tar.gz: a39ee59b4404715e976240bca10e818f9b2b85e88575bac566ba02cd1116c4c9
3
+ metadata.gz: 22a0bb59de4bca05c100302f2050a300c2a60a90a2124f2f5aa07c215c6b6919
4
+ data.tar.gz: 6b314236d27b59baa482317413c5b5c95303b9530b33693ee03841491ed00bc6
5
5
  SHA512:
6
- metadata.gz: af5802350e819dcf37618a8cc3eac5c1ee98ad1e8f14f3e724ac1083875746139565ee34ccd697d6dd5c8950d2bf17e58b4b98416014a190cde2e62bd316df09
7
- data.tar.gz: 7407dd36a674f8271b645e2bb97c3b84a15461cd14010e870f1036a53ebfb8ba00d959a341694c43ae1d8cf884d97d1a758815080f90fc4e65aebc46579668a2
6
+ metadata.gz: 1f8a2d831b26d101a1ea8e381ff3cfc7bbce6d88682e70ec43c22a37b3ba047da5376247b5f32b1184f088514da8a1377f54ffcbe4def383b249515c70c3c518
7
+ data.tar.gz: 1aa2b1ceb5886238f9034491256e3c7fbdd5cbba121c27393288bced653f92051e43fec7f242a35b4cab7e316731e422a46c73c054548c96ee4b1537c6b371ac
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -30,6 +30,48 @@ Please file a bug if you notice a violation of semantic versioning.
30
30
 
31
31
  ### Security
32
32
 
33
+ ## [2.2.20] - 2026-06-27
34
+
35
+ - TAG: [v2.2.20][2.2.20t]
36
+ - COVERAGE: 91.82% -- 4131/4499 lines in 33 files
37
+ - BRANCH COVERAGE: 72.73% -- 1632/2244 branches in 33 files
38
+ - 61.04% documented
39
+
40
+ ### Added
41
+
42
+ - `kettle-release` now accepts `skip_steps=...` / `--skip-steps ...` to skip
43
+ selected numbered release steps while running the rest of the release flow.
44
+
45
+ ### Fixed
46
+
47
+ - `kettle-release` now suppresses inherited Bundler/debug verbosity when running
48
+ release child commands and Appraisal bundle installs.
49
+
50
+ - `kettle-release` now switches a local `RUBOCOP_LTS_LOCAL` checkout to the
51
+ branch matching the project's selected `rubocop-rubyN_N` style gem before
52
+ running setup and default rake tasks.
53
+
54
+ - Restored Ruby 2.4 parser compatibility for recent release and CI helper code.
55
+
56
+ ### Changed
57
+
58
+ - `kettle-release` now reads RuboCop LTS branch selection from
59
+ `Kettle::Rb::CompatMatrix`.
60
+
61
+ ## [2.2.19] - 2026-06-26
62
+
63
+ - TAG: [v2.2.19][2.2.19t]
64
+ - COVERAGE: 91.75% -- 4082/4449 lines in 33 files
65
+ - BRANCH COVERAGE: 72.94% -- 1615/2214 branches in 33 files
66
+ - 61.84% documented
67
+
68
+ ### Changed
69
+
70
+ - `kettle-release` now runs `bin/rake appraisal:generate` by default when
71
+ `Appraisals` is present; use `--appraisal-update` or
72
+ `KETTLE_RELEASE_APPRAISAL_TASK=appraisal:update` for the slower lock-resolving
73
+ update path.
74
+
33
75
  ## [2.2.18] - 2026-06-24
34
76
 
35
77
  - TAG: [v2.2.18][2.2.18t]
@@ -2279,7 +2321,11 @@ Please file a bug if you notice a violation of semantic versioning.
2279
2321
  - Selecting will run the selected workflow via `act`
2280
2322
  - This may move to its own gem in the future.
2281
2323
 
2282
- [Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v2.2.18...HEAD
2324
+ [Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v2.2.20...HEAD
2325
+ [2.2.20]: https://github.com/kettle-dev/kettle-dev/compare/v2.2.19...v2.2.20
2326
+ [2.2.20t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v2.2.20
2327
+ [2.2.19]: https://github.com/kettle-dev/kettle-dev/compare/v2.2.18...v2.2.19
2328
+ [2.2.19t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v2.2.19
2283
2329
  [2.2.18]: https://github.com/kettle-dev/kettle-dev/compare/v2.2.17...v2.2.18
2284
2330
  [2.2.18t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v2.2.18
2285
2331
  [2.2.17]: https://github.com/kettle-dev/kettle-dev/compare/v2.2.16...v2.2.17
data/CONTRIBUTING.md CHANGED
@@ -131,9 +131,12 @@ toolchain, and it may be higher than the gemspec runtime floor.
131
131
  They are created and updated with the commands:
132
132
 
133
133
  ```console
134
- bin/rake appraisal:update
134
+ bin/rake appraisal:generate
135
135
  ```
136
136
 
137
+ Use `bin/rake appraisal:update` when you intentionally need to resolve fresh
138
+ appraisal locks.
139
+
137
140
  If you need to reset all gemfiles/*.gemfile.lock files:
138
141
 
139
142
  ```console
data/README.md CHANGED
@@ -874,7 +874,7 @@ Thanks for RTFM. ☺️
874
874
  [📌gitmoji]: https://gitmoji.dev
875
875
  [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
876
876
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
877
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-4.446-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
877
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-4.499-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
878
878
  [🔐security]: https://github.com/kettle-dev/kettle-dev/blob/main/SECURITY.md
879
879
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
880
880
  [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
data/exe/kettle-changelog CHANGED
@@ -52,59 +52,57 @@ rescue LoadError => e
52
52
  exit(1)
53
53
  end
54
54
 
55
- begin
56
- if ARGV.include?("-h") || ARGV.include?("--help")
57
- puts <<~USAGE
58
- Usage: kettle-changelog [--version VERSION] [--update-prep] [--pending-release] [--release-state] [--add-unreleased-entry --section SECTION --entry TEXT] [--json] [--no-strict] [--no-coverage-threshold]
59
-
60
- Detects the current version from lib/**/version.rb, the latest live release, and
61
- the most recent CHANGELOG.md release section, then prompts to confirm the selected plan:
62
- create a new release section, update the prepared release section in place, or reformat only.
63
-
64
- Release plans add coverage and documentation stats, move entries from [Unreleased],
65
- and update bottom link references to GitHub style.
66
-
67
- Options:
68
- --version VERSION Use this version instead of detecting VERSION from lib/**/version.rb
69
- --update-prep Force updating the most recent prepared release section in place
70
- --pending-release Query whether the changelog has release work pending; exits 0 for yes, 1 for no
71
- --release-state,
72
- --release-status Print changelog release state, including latest published release and pending sources
73
- --add-unreleased-entry Add one entry to an existing section under ## [Unreleased]
74
- --section SECTION Unreleased section to receive the entry (Added, Changed, Deprecated, Removed, Fixed, Security)
75
- --entry TEXT Changelog entry text; "- " is added when omitted
76
- --json Print query output as JSON
77
- --no-strict Allow missing coverage and yard data (warnings only, no errors)
78
- --no-coverage-threshold Generate coverage without hard-failing below configured thresholds
79
-
80
- Environment:
81
- K_CHANGELOG_STRICT=false Disable strict mode (equivalent to --no-strict flag)
82
- K_CHANGELOG_COVERAGE_HARD=false Disable coverage threshold hard-failure
83
- K_CHANGELOG_VERSION_FILE=path Read VERSION from this file instead of lib/**/version.rb
84
-
85
- Data generation:
86
- Strict mode is the default. Release plans remove stale coverage output,
87
- run bundle exec kettle-test with JSON coverage enabled, read the resulting
88
- coverage/coverage.json, and collect documentation stats from bin/rake yard
89
- or bin/yard.
90
-
91
- Strict mode fails if specs fail, coverage JSON is not produced, coverage
92
- is below the configured project thresholds, or documentation stats cannot
93
- be collected.
94
-
95
- Non-strict mode does not generate missing coverage or documentation data;
96
- it warns and leaves unavailable stats blank.
97
-
98
- Runtime requirements:
99
- - bundle exec kettle-test available for strict coverage generation
100
- - bin/rake yard or bin/yard available for strict documentation stats
101
-
102
- Use --no-strict or K_CHANGELOG_STRICT=false to allow missing data.
103
- Use --no-coverage-threshold or K_CHANGELOG_COVERAGE_HARD=false to run fresh
104
- coverage without hard-failing below configured thresholds.
105
- USAGE
106
- exit(0)
107
- end
55
+ if ARGV.include?("-h") || ARGV.include?("--help")
56
+ puts <<~USAGE
57
+ Usage: kettle-changelog [--version VERSION] [--update-prep] [--pending-release] [--release-state] [--add-unreleased-entry --section SECTION --entry TEXT] [--json] [--no-strict] [--no-coverage-threshold]
58
+
59
+ Detects the current version from lib/**/version.rb, the latest live release, and
60
+ the most recent CHANGELOG.md release section, then prompts to confirm the selected plan:
61
+ create a new release section, update the prepared release section in place, or reformat only.
62
+
63
+ Release plans add coverage and documentation stats, move entries from [Unreleased],
64
+ and update bottom link references to GitHub style.
65
+
66
+ Options:
67
+ --version VERSION Use this version instead of detecting VERSION from lib/**/version.rb
68
+ --update-prep Force updating the most recent prepared release section in place
69
+ --pending-release Query whether the changelog has release work pending; exits 0 for yes, 1 for no
70
+ --release-state,
71
+ --release-status Print changelog release state, including latest published release and pending sources
72
+ --add-unreleased-entry Add one entry to an existing section under ## [Unreleased]
73
+ --section SECTION Unreleased section to receive the entry (Added, Changed, Deprecated, Removed, Fixed, Security)
74
+ --entry TEXT Changelog entry text; "- " is added when omitted
75
+ --json Print query output as JSON
76
+ --no-strict Allow missing coverage and yard data (warnings only, no errors)
77
+ --no-coverage-threshold Generate coverage without hard-failing below configured thresholds
78
+
79
+ Environment:
80
+ K_CHANGELOG_STRICT=false Disable strict mode (equivalent to --no-strict flag)
81
+ K_CHANGELOG_COVERAGE_HARD=false Disable coverage threshold hard-failure
82
+ K_CHANGELOG_VERSION_FILE=path Read VERSION from this file instead of lib/**/version.rb
83
+
84
+ Data generation:
85
+ Strict mode is the default. Release plans remove stale coverage output,
86
+ run bundle exec kettle-test with JSON coverage enabled, read the resulting
87
+ coverage/coverage.json, and collect documentation stats from bin/rake yard
88
+ or bin/yard.
89
+
90
+ Strict mode fails if specs fail, coverage JSON is not produced, coverage
91
+ is below the configured project thresholds, or documentation stats cannot
92
+ be collected.
93
+
94
+ Non-strict mode does not generate missing coverage or documentation data;
95
+ it warns and leaves unavailable stats blank.
96
+
97
+ Runtime requirements:
98
+ - bundle exec kettle-test available for strict coverage generation
99
+ - bin/rake yard or bin/yard available for strict documentation stats
100
+
101
+ Use --no-strict or K_CHANGELOG_STRICT=false to allow missing data.
102
+ Use --no-coverage-threshold or K_CHANGELOG_COVERAGE_HARD=false to run fresh
103
+ coverage without hard-failing below configured thresholds.
104
+ USAGE
105
+ exit(0)
108
106
  end
109
107
 
110
108
  begin
data/exe/kettle-release CHANGED
@@ -43,7 +43,7 @@ end
43
43
  # Do not guard with __FILE__ == $PROGRAM_NAME because binstubs use Kernel.load.
44
44
  if ARGV.include?("-h") || ARGV.include?("--help")
45
45
  puts <<~USAGE
46
- Usage: kettle-release [--version VERSION] [--local-ci] [start_step=<0-19>]
46
+ Usage: kettle-release [--version VERSION] [--local-ci] [--appraisal-update] [--skip-steps STEPS] [start_step=<0-19>]
47
47
 
48
48
  Automates the release flow for a Ruby gem in the host project.
49
49
 
@@ -58,7 +58,7 @@ if ARGV.include?("-h") || ARGV.include?("--help")
58
58
  2. Detect version; RubyGems sanity check; confirm CHANGELOG/version; sync copyright years; update badges/headers
59
59
  3. Run bin/setup
60
60
  4. Run bin/rake (default task)
61
- 5. Run bin/rake appraisal:update if Appraisals present
61
+ 5. Run bin/rake appraisal:generate if Appraisals present
62
62
  6. Ensure git user configured; commit release prep
63
63
  7. Optional local CI with `act` (controlled by K_RELEASE_LOCAL_CI)
64
64
  8. Ensure trunk in sync across remotes; rebase feature as needed
@@ -76,7 +76,10 @@ if ARGV.include?("-h") || ARGV.include?("--help")
76
76
 
77
77
  Options:
78
78
  start_step=<number> # Begin at the numbered step above (e.g., 10 to resume at CI monitoring)
79
+ skip_steps=<numbers> # Comma-separated numbered steps to skip while running the rest
80
+ --skip-steps NUMBERS # Alias for skip_steps=NUMBERS (e.g., --skip-steps 10 or --skip-steps 10,18)
79
81
  --version VERSION # Use this version instead of detecting VERSION from lib/**/version.rb
82
+ --appraisal-update # Use slower appraisal:update instead of default appraisal:generate
80
83
  --local-ci # Sensitive release mode: run act locally, publish before any git push,
81
84
  # create the git tag locally, then push commits and tags after publish
82
85
 
@@ -85,6 +88,8 @@ if ARGV.include?("-h") || ARGV.include?("--help")
85
88
  GEM_CERT_USER=<user> # Select certs/<user>.pem for signing
86
89
  K_RELEASE_LOCAL_CI=ask|1|0 # Use 'act' locally before push; 'ask' prompts, '1' forces, default off
87
90
  K_RELEASE_LOCAL_CI_WORKFLOW # Name of workflow (without .yml) for local CI; defaults to locked_deps or first
91
+ KETTLE_RELEASE_APPRAISAL_TASK=appraisal:update
92
+ # Use slower appraisal:update instead of default appraisal:generate
88
93
  GITHUB_TOKEN / GH_TOKEN # Optional; enables GitHub release creation and API queries
89
94
  GITLAB_TOKEN / GL_TOKEN # Optional; enables GitLab API queries when applicable
90
95
  DEBUG=true # Print backtraces on errors
@@ -94,12 +99,13 @@ if ARGV.include?("-h") || ARGV.include?("--help")
94
99
  kettle-release --local-ci # run local act CI, publish gem, then push commits/tags
95
100
  kettle-release start_step=1 # skip pre-release checks and start numbered release steps
96
101
  kettle-release start_step=10 # resume by monitoring CI for the current branch
102
+ kettle-release skip_steps=10 # run the release but skip remote CI monitoring
97
103
  SKIP_GEM_SIGNING=true kettle-release start_step=14 # build+release without signing
98
104
  USAGE
99
105
  exit 0
100
106
  end
101
107
 
102
- # Parse start_step=<n> from ARGV
108
+ # Parse release options from ARGV
103
109
  def extract_version_arg!(argv)
104
110
  version = nil
105
111
  if (idx = argv.index("--version"))
@@ -118,13 +124,33 @@ def extract_version_arg!(argv)
118
124
  Kettle::Dev::Versioning.normalize_explicit_version(version)
119
125
  end
120
126
 
127
+ def extract_skip_steps_arg!(argv)
128
+ skip_steps = nil
129
+ if (idx = argv.index("--skip-steps"))
130
+ skip_steps = argv[idx + 1]
131
+ Kettle::Dev::ExitAdapter.abort("--skip-steps requires a comma-separated step list") if skip_steps.to_s.empty?
132
+ argv.slice!(idx, 2)
133
+ end
134
+ argv.delete_if do |arg|
135
+ if arg.start_with?("--skip-steps=", "skip_steps=")
136
+ skip_steps = arg.split("=", 2)[1]
137
+ true
138
+ else
139
+ false
140
+ end
141
+ end
142
+ skip_steps
143
+ end
144
+
121
145
  local_ci = ARGV.include?("--local-ci")
146
+ appraisal_task = ARGV.delete("--appraisal-update") ? "appraisal:update" : nil
122
147
  start_step_arg = ARGV.find { |a| a.start_with?("start_step=") }
123
148
  start_step = start_step_arg ? start_step_arg.split("=", 2)[1].to_i : 0
124
149
  version_override = extract_version_arg!(ARGV)
150
+ skip_steps = extract_skip_steps_arg!(ARGV)
125
151
 
126
152
  begin
127
- Kettle::Dev::ReleaseCLI.new(start_step: start_step, local_ci: local_ci, version: version_override).run
153
+ Kettle::Dev::ReleaseCLI.new(start_step: start_step, local_ci: local_ci, version: version_override, appraisal_task: appraisal_task, skip_steps: skip_steps).run
128
154
  rescue LoadError => e
129
155
  warn("#{script_basename}: could not load dependency: #{e.class}: #{e.message}")
130
156
  warn(Array(e.backtrace).join("\n")) if ENV["DEBUG"]
@@ -297,13 +297,13 @@ module Kettle
297
297
  end
298
298
  # Small initial delay to allow GitHub to register the newly pushed commit and enqueue workflows.
299
299
  # Configurable via K_RELEASE_CI_INITIAL_SLEEP (seconds); defaults to 3s.
300
- begin
301
- initial_sleep = begin
302
- Integer(ENV["K_RELEASE_CI_INITIAL_SLEEP"])
303
- rescue
304
- nil
305
- end
300
+
301
+ initial_sleep = begin
302
+ Integer(ENV["K_RELEASE_CI_INITIAL_SLEEP"])
303
+ rescue
304
+ nil
306
305
  end
306
+
307
307
  sleep((initial_sleep && initial_sleep >= 0) ? initial_sleep : 3)
308
308
  start_timeout = github_start_timeout
309
309
  poll_interval = github_poll_interval
@@ -6,7 +6,6 @@ require "net/http"
6
6
  require "open3"
7
7
  require "optparse"
8
8
  require "pathname"
9
- require "set"
10
9
  require "time"
11
10
  require "uri"
12
11
 
@@ -53,26 +53,24 @@ module Kettle
53
53
  # Create a new adapter rooted at the current working directory.
54
54
  # @return [void]
55
55
  def initialize
56
- begin
57
- # Allow users/CI to opt out of using the 'git' gem even when available.
58
- # Set KETTLE_DEV_DISABLE_GIT_GEM to a truthy value ("1", "true", "yes") to force CLI backend.
59
- env_val = ENV["KETTLE_DEV_DISABLE_GIT_GEM"]
60
- # Ruby 2.3 compatibility: String#match? was added in 2.4; use Regexp#=== / =~ instead
61
- disable_gem = env_val && !!(/\A(1|true|yes)\z/i =~ env_val)
62
- if disable_gem
63
- @backend = :cli
64
- else
65
- Kernel.require "git"
66
- @backend = :gem
67
- @git = ::Git.open(Dir.pwd)
68
- end
69
- rescue LoadError => e
70
- Kettle::Dev.debug_error(e, __method__, backtrace: false)
71
- # Optional dependency: fall back to CLI
56
+ # Allow users/CI to opt out of using the 'git' gem even when available.
57
+ # Set KETTLE_DEV_DISABLE_GIT_GEM to a truthy value ("1", "true", "yes") to force CLI backend.
58
+ env_val = ENV["KETTLE_DEV_DISABLE_GIT_GEM"]
59
+ # Ruby 2.3 compatibility: String#match? was added in 2.4; use Regexp#=== / =~ instead
60
+ disable_gem = env_val && !!(/\A(1|true|yes)\z/i =~ env_val)
61
+ if disable_gem
72
62
  @backend = :cli
73
- rescue => e
74
- raise Kettle::Dev::Error, "Failed to open git repository: #{e.message}"
63
+ else
64
+ Kernel.require "git"
65
+ @backend = :gem
66
+ @git = ::Git.open(Dir.pwd)
75
67
  end
68
+ rescue LoadError => e
69
+ Kettle::Dev.debug_error(e, __method__, backtrace: false)
70
+ # Optional dependency: fall back to CLI
71
+ @backend = :cli
72
+ rescue => e
73
+ raise Kettle::Dev::Error, "Failed to open git repository: #{e.message}"
76
74
  end
77
75
 
78
76
  # Push a branch to a remote.
@@ -5,7 +5,7 @@ module Kettle
5
5
  class GitCommitFooter
6
6
  # Regex to extract `name = "value"` assignments from a gemspec.
7
7
  # @return [Regexp]
8
- NAME_ASSIGNMENT_REGEX = /\bname\s*=\s*(["'])([^"']+)\1/.freeze
8
+ NAME_ASSIGNMENT_REGEX = /\bname\s*=\s*(["'])([^"']+)\1/
9
9
 
10
10
  # Whether footer appending is enabled (via GIT_HOOK_FOOTER_APPEND=true)
11
11
  # @return [Boolean]
@@ -44,14 +44,14 @@ module Kettle
44
44
 
45
45
  ypath = yaml_path(root)
46
46
  if strict
47
- yml = YAML.safe_load(File.read(ypath))
47
+ yml = YAML.safe_load_file(ypath)
48
48
  if yml.is_a?(Hash)
49
49
  handle = yml["collective"] || yml[:collective] || yml["org"] || yml[:org]
50
50
  return handle.to_s unless handle.nil? || handle.to_s.strip.empty? || handle.to_s.match?(/\{KJ\|[^}]+}/)
51
51
  end
52
52
  elsif File.file?(ypath)
53
53
  begin
54
- yml = YAML.safe_load(File.read(ypath))
54
+ yml = YAML.safe_load_file(ypath)
55
55
  if yml.is_a?(Hash)
56
56
  handle = yml["collective"] || yml[:collective] || yml["org"] || yml[:org]
57
57
  return handle.to_s unless handle.nil? || handle.to_s.strip.empty? || handle.to_s.match?(/\{KJ\|[^}]+}/)
@@ -5,7 +5,27 @@ begin
5
5
  require "appraisal/task"
6
6
 
7
7
  bundle = "bundle"
8
- appraisal_env = {"BUNDLE_GEMFILE" => "Appraisal.root.gemfile"}
8
+ quiet_env = {
9
+ "KETTLE_JEM_QUIET" => "true",
10
+ "KETTLE_JEM_DEBUG" => "false",
11
+ "KETTLE_DEV_DEBUG" => "false",
12
+ "SMORG_RB_DEBUG" => "false",
13
+ "DEBUG" => nil,
14
+ "BUNDLE_QUIET" => "true",
15
+ "BUNDLE_DEBUG" => "false",
16
+ "BUNDLER_DEBUG" => "false",
17
+ "BUNDLE_VERBOSE" => "false",
18
+ "DEBUG_RESOLVER" => nil,
19
+ "DEBUG_RESOLVER_TREE" => nil,
20
+ "BUNDLER_DEBUG_RESOLVER" => nil,
21
+ "BUNDLER_DEBUG_RESOLVER_TREE" => nil,
22
+ "DEBUG_COMPACT_INDEX" => nil,
23
+ "MOLINILLO_DEBUG" => nil,
24
+ "BUNDLE_SILENCE_DEPRECATIONS" => "true",
25
+ "BUNDLE_SILENCE_ROOT_WARNING" => "true",
26
+ "BUNDLE_SUPPRESS_INSTALL_USING_MESSAGES" => "true"
27
+ }
28
+ appraisal_env = quiet_env.merge("BUNDLE_GEMFILE" => "Appraisal.root.gemfile")
9
29
 
10
30
  run_command = lambda do |failure_message, *args|
11
31
  ok = system(*args)
@@ -18,7 +38,8 @@ begin
18
38
  "appraisal:generate failed: BUNDLE_GEMFILE=Appraisal.root.gemfile bundle install",
19
39
  appraisal_env,
20
40
  bundle,
21
- "install"
41
+ "install",
42
+ "--quiet"
22
43
  )
23
44
 
24
45
  # 2) BUNDLE_GEMFILE=Appraisal.root.gemfile bundle exec appraisal generate
@@ -60,7 +81,8 @@ begin
60
81
  "appraisal:install failed: BUNDLE_GEMFILE=Appraisal.root.gemfile bundle install",
61
82
  appraisal_env,
62
83
  bundle,
63
- "install"
84
+ "install",
85
+ "--quiet"
64
86
  )
65
87
 
66
88
  # 2) BUNDLE_GEMFILE=Appraisal.root.gemfile bundle exec appraisal generate-install
@@ -107,7 +129,8 @@ begin
107
129
  "appraisal:update failed: BUNDLE_GEMFILE=Appraisal.root.gemfile bundle install",
108
130
  appraisal_env,
109
131
  bundle,
110
- "install"
132
+ "install",
133
+ "--quiet"
111
134
  )
112
135
 
113
136
  # 2) BUNDLE_GEMFILE=Appraisal.root.gemfile bundle update --bundler
@@ -124,7 +147,8 @@ begin
124
147
  "appraisal:update failed: BUNDLE_GEMFILE=Appraisal.root.gemfile bundle install",
125
148
  appraisal_env,
126
149
  bundle,
127
- "install"
150
+ "install",
151
+ "--quiet"
128
152
  )
129
153
 
130
154
  # 4) BUNDLE_GEMFILE=Appraisal.root.gemfile bundle exec appraisal generate-update
@@ -5,7 +5,6 @@ require "yaml"
5
5
  require "json"
6
6
  require "uri"
7
7
  require "net/http"
8
- require "set"
9
8
 
10
9
  module Kettle
11
10
  module Dev
@@ -244,7 +243,7 @@ module Kettle
244
243
 
245
244
  if File.file?(OC_YML_PATH)
246
245
  begin
247
- yml = YAML.safe_load(File.read(OC_YML_PATH))
246
+ yml = YAML.safe_load_file(OC_YML_PATH)
248
247
  if yml.is_a?(Hash)
249
248
  from_yml = yml["readme-osc-tag"] || yml[:"readme-osc-tag"]
250
249
  from_yml = from_yml.to_s if from_yml
@@ -660,7 +659,7 @@ module Kettle
660
659
 
661
660
  if File.file?(OC_YML_PATH)
662
661
  begin
663
- yml = YAML.safe_load(File.read(OC_YML_PATH))
662
+ yml = YAML.safe_load_file(OC_YML_PATH)
664
663
  if yml.is_a?(Hash)
665
664
  from_yml = yml["readme-backers-commit-subject"] || yml[:"readme-backers-commit-subject"]
666
665
  from_yml = from_yml.to_s if from_yml
@@ -11,11 +11,33 @@ require "json"
11
11
  require "uri"
12
12
 
13
13
  # External gems
14
+ require "kettle/rb/compat_matrix"
14
15
  require "ruby-progressbar"
15
16
 
16
17
  module Kettle
17
18
  module Dev
18
19
  class ReleaseCLI
20
+ QUIET_ENV = {
21
+ "KETTLE_JEM_QUIET" => "true",
22
+ "KETTLE_JEM_DEBUG" => "false",
23
+ "KETTLE_DEV_DEBUG" => "false",
24
+ "SMORG_RB_DEBUG" => "false",
25
+ "DEBUG" => nil,
26
+ "BUNDLE_QUIET" => "true",
27
+ "BUNDLE_DEBUG" => "false",
28
+ "BUNDLER_DEBUG" => "false",
29
+ "BUNDLE_VERBOSE" => "false",
30
+ "DEBUG_RESOLVER" => nil,
31
+ "DEBUG_RESOLVER_TREE" => nil,
32
+ "BUNDLER_DEBUG_RESOLVER" => nil,
33
+ "BUNDLER_DEBUG_RESOLVER_TREE" => nil,
34
+ "DEBUG_COMPACT_INDEX" => nil,
35
+ "MOLINILLO_DEBUG" => nil,
36
+ "BUNDLE_SILENCE_DEPRECATIONS" => "true",
37
+ "BUNDLE_SILENCE_ROOT_WARNING" => "true",
38
+ "BUNDLE_SUPPRESS_INSTALL_USING_MESSAGES" => "true"
39
+ }.freeze
40
+ DEBUG_TRUE_VALUES = %w[1 true yes on].freeze
19
41
  class << self
20
42
  def run_cmd!(cmd)
21
43
  # For Bundler-invoked build/release, explicitly prefix SKIP_GEM_SIGNING so
@@ -26,7 +48,7 @@ module Kettle
26
48
  end
27
49
  puts "$ #{cmd}"
28
50
  # Pass a plain Hash for the environment to satisfy tests and avoid ENV object oddities
29
- env_hash = ENV.respond_to?(:to_hash) ? ENV.to_hash : ENV.to_h
51
+ env_hash = command_env
30
52
 
31
53
  # Some commands are interactive (e.g., `bundle exec rake release` prompting for RubyGems MFA).
32
54
  # Using capture3 detaches STDIN, preventing prompts from working. For such commands, use system
@@ -62,6 +84,19 @@ module Kettle
62
84
  abort("Command failed: #{cmd} (exit #{exit_code})#{diag}")
63
85
  end
64
86
  end
87
+
88
+ private
89
+
90
+ def command_env
91
+ env_hash = ENV.respond_to?(:to_hash) ? ENV.to_hash : ENV.to_h
92
+ return env_hash if debug_env_enabled?
93
+
94
+ env_hash.merge(QUIET_ENV)
95
+ end
96
+
97
+ def debug_env_enabled?
98
+ DEBUG_TRUE_VALUES.include?(ENV.fetch("KETTLE_DEV_DEBUG", "").downcase)
99
+ end
65
100
  end
66
101
 
67
102
  private
@@ -72,20 +107,22 @@ module Kettle
72
107
 
73
108
  public
74
109
 
75
- def initialize(start_step: 0, local_ci: false, version: nil)
110
+ def initialize(start_step: 0, local_ci: false, version: nil, appraisal_task: nil, skip_steps: nil)
76
111
  @root = Kettle::Dev::CIHelpers.project_root
77
112
  @git = Kettle::Dev::GitAdapter.new
78
113
  @start_step = (start_step || 0).to_i
79
114
  @start_step = 0 if @start_step < 0
115
+ @skip_steps = normalize_skip_steps(skip_steps)
80
116
  @local_ci = !!local_ci
81
117
  @version_override = Kettle::Dev::Versioning.normalize_explicit_version(version)
118
+ @appraisal_task = normalize_appraisal_task(appraisal_task || ENV["KETTLE_RELEASE_APPRAISAL_TASK"])
82
119
  end
83
120
 
84
121
  def run
85
- run_pre_release_checks! if @start_step <= 0
122
+ run_pre_release_checks! if run_step?(0)
86
123
 
87
124
  # 1. Ensure Bundler version ✓
88
- ensure_bundler_2_7_plus!
125
+ ensure_bundler_2_7_plus! if run_step?(1)
89
126
 
90
127
  version = nil
91
128
  committed = nil
@@ -93,7 +130,7 @@ module Kettle
93
130
  feature = nil
94
131
 
95
132
  # 2. Version detection and sanity checks + prompt
96
- if @start_step <= 2
133
+ if run_step?(2)
97
134
  version = detect_version
98
135
  puts "Detected version: #{version.inspect}"
99
136
 
@@ -185,19 +222,21 @@ module Kettle
185
222
  end
186
223
  end
187
224
 
225
+ prepare_rubocop_lts_local_branch! if rubocop_lts_release_preflight_needed?
226
+
188
227
  # 3. bin/setup
189
- run_cmd!("bin/setup") if @start_step <= 3
228
+ run_cmd!("bin/setup") if run_step?(3)
190
229
  # 4. bin/rake
191
- run_cmd!("bin/rake") if @start_step <= 4
230
+ run_cmd!("bin/rake") if run_step?(4)
192
231
 
193
- # 5. appraisal:update (optional) + canonical docs build
194
- if @start_step <= 5
232
+ # 5. appraisal:generate (optional) + canonical docs build
233
+ if run_step?(5)
195
234
  appraisals_path = File.join(@root, "Appraisals")
196
235
  if File.file?(appraisals_path)
197
- puts "Appraisals detected at #{Kettle::Dev.display_path(appraisals_path)}. Running: bin/rake appraisal:update"
198
- run_cmd!("bin/rake appraisal:update")
236
+ puts "Appraisals detected at #{Kettle::Dev.display_path(appraisals_path)}. Running: bin/rake #{@appraisal_task}"
237
+ run_cmd!("bin/rake #{@appraisal_task}")
199
238
  else
200
- puts "No Appraisals file found; skipping appraisal:update"
239
+ puts "No Appraisals file found; skipping #{@appraisal_task}"
201
240
  end
202
241
 
203
242
  puts "Generating docs site via canonical task: bin/rake yard"
@@ -205,47 +244,47 @@ module Kettle
205
244
  end
206
245
 
207
246
  # 6. git user + commit release prep
208
- if @start_step <= 6
247
+ if run_step?(6)
209
248
  ensure_git_user!
210
249
  version ||= detect_version
211
250
  committed = commit_release_prep!(version)
212
251
  end
213
252
 
214
253
  # 7. optional local CI via act
215
- maybe_run_local_ci_before_push!(committed, force: local_ci?) if @start_step <= 7
254
+ maybe_run_local_ci_before_push!(committed, force: local_ci?) if run_step?(7)
216
255
 
217
256
  # 8. ensure trunk synced
218
- if @start_step <= 8 && !local_ci?
257
+ if run_step?(8) && !local_ci?
219
258
  trunk = detect_trunk_branch
220
259
  feature = current_branch
221
260
  puts "Trunk branch detected: #{trunk}"
222
261
  ensure_trunk_synced_before_push!(trunk, feature)
223
- elsif @start_step <= 8
262
+ elsif run_step?(8)
224
263
  puts "Local CI release mode: skipping remote trunk sync before publishing."
225
264
  end
226
265
 
227
266
  # 9. push branches
228
- push! if @start_step <= 9 && !local_ci?
267
+ push! if run_step?(9) && !local_ci?
229
268
 
230
269
  # 10. monitor CI after push
231
- monitor_workflows_after_push! if @start_step <= 10 && !local_ci?
270
+ monitor_workflows_after_push! if run_step?(10) && !local_ci?
232
271
 
233
272
  # 11. merge feature into trunk and push
234
- if @start_step <= 11 && !local_ci?
273
+ if run_step?(11) && !local_ci?
235
274
  trunk ||= detect_trunk_branch
236
275
  feature ||= current_branch
237
276
  merge_feature_into_trunk_and_push!(trunk, feature)
238
277
  end
239
278
 
240
279
  # 12. checkout trunk and pull
241
- if @start_step <= 12 && !local_ci?
280
+ if run_step?(12) && !local_ci?
242
281
  trunk ||= detect_trunk_branch
243
282
  checkout!(trunk)
244
283
  pull!(trunk)
245
284
  end
246
285
 
247
286
  # 13. signing guidance and checks
248
- if @start_step <= 13
287
+ if run_step?(13)
249
288
  if ENV.fetch("SKIP_GEM_SIGNING", "false").casecmp("false").zero?
250
289
  puts "TIP: For local dry-runs or testing the release workflow, set SKIP_GEM_SIGNING=true to avoid PEM password prompts."
251
290
  if Kettle::Dev::InputAdapter.tty?
@@ -266,13 +305,13 @@ module Kettle
266
305
  end
267
306
 
268
307
  # 14. build
269
- if @start_step <= 14
308
+ if run_step?(14)
270
309
  puts "Running build (you may be prompted for the signing key password)..."
271
310
  run_cmd!("bundle exec rake build")
272
311
  end
273
312
 
274
313
  # 15. release and tag
275
- if @start_step <= 15
314
+ if run_step?(15)
276
315
  if local_ci?
277
316
  version ||= detect_version
278
317
  release_gem_and_tag_locally!(version)
@@ -286,7 +325,7 @@ module Kettle
286
325
  # Checksums are generated after release to avoid including checksums/ in gem package
287
326
  # Rationale: Running gem_checksums before release may commit checksums/ and cause Bundler's
288
327
  # release build to include them in the gem, thus altering the artifact, and invalidating the checksums.
289
- if @start_step <= 16
328
+ if run_step?(16)
290
329
  # Generate checksums for the just-built artifact, commit them, then validate
291
330
  run_cmd!("bin/gem_checksums")
292
331
  version ||= detect_version
@@ -294,19 +333,19 @@ module Kettle
294
333
  end
295
334
 
296
335
  # 17. push checksum commit (gem_checksums already commits)
297
- if @start_step <= 17
336
+ if run_step?(17)
298
337
  push!
299
338
  push_tags! if local_ci?
300
339
  end
301
340
 
302
341
  # 18. create GitHub release (optional)
303
- if @start_step <= 18
342
+ if run_step?(18)
304
343
  version ||= detect_version
305
344
  maybe_create_github_release!(version)
306
345
  end
307
346
 
308
347
  # 19. push tags to remotes (final step)
309
- push_tags! if @start_step <= 19 && !local_ci?
348
+ push_tags! if run_step?(19) && !local_ci?
310
349
 
311
350
  # Final success message
312
351
  begin
@@ -320,12 +359,81 @@ module Kettle
320
359
  end
321
360
  end
322
361
 
362
+ def normalize_appraisal_task(value)
363
+ task = value.to_s.strip
364
+ return "appraisal:generate" if task.empty?
365
+ return "appraisal:generate" if task == "generate" || task == "appraisal:generate"
366
+ return "appraisal:update" if task == "update" || task == "appraisal:update"
367
+
368
+ abort("Unsupported appraisal task #{value.inspect}; use appraisal:generate or appraisal:update.")
369
+ end
370
+
371
+ def normalize_skip_steps(value)
372
+ raw_steps = Array(value).flat_map { |part| part.to_s.split(",") }.map(&:strip).reject(&:empty?)
373
+ raw_steps.map do |raw|
374
+ abort("Invalid skip_steps value #{raw.inspect}; use comma-separated release step numbers from 0 to 19.") unless raw.match?(/\A\d+\z/)
375
+
376
+ step = raw.to_i
377
+ abort("Invalid skip_steps value #{raw.inspect}; release steps are numbered 0 to 19.") unless step.between?(0, 19)
378
+
379
+ step
380
+ end.uniq
381
+ end
382
+
323
383
  private
324
384
 
325
385
  def local_ci?
326
386
  @local_ci
327
387
  end
328
388
 
389
+ def run_step?(step)
390
+ @start_step <= step && !@skip_steps.include?(step)
391
+ end
392
+
393
+ def rubocop_lts_release_preflight_needed?
394
+ (3..5).any? { |step| run_step?(step) }
395
+ end
396
+
397
+ def prepare_rubocop_lts_local_branch!
398
+ local_root = rubocop_lts_local_root
399
+ return unless local_root
400
+
401
+ ruby_gem = selected_rubocop_lts_ruby_gem
402
+ return unless ruby_gem
403
+
404
+ branch = Kettle::Rb::CompatMatrix.rubocop_lts_branch_for_gem(ruby_gem)
405
+ abort("Cannot select RUBOCOP_LTS_LOCAL branch for #{ruby_gem.inspect}.") unless branch
406
+
407
+ checkout = File.join(local_root, "rubocop-lts")
408
+ current, ok = git_output(["-C", checkout, "branch", "--show-current"])
409
+ abort("Cannot inspect RUBOCOP_LTS_LOCAL checkout at #{checkout}.") unless ok
410
+ return if current == branch
411
+
412
+ puts "Switching RUBOCOP_LTS_LOCAL checkout #{checkout} to #{branch} for #{ruby_gem}."
413
+ _stdout, switched = git_output(["-C", checkout, "switch", branch])
414
+ abort("Cannot switch RUBOCOP_LTS_LOCAL checkout at #{checkout} to #{branch}. Commit or stash local changes, then retry.") unless switched
415
+ end
416
+
417
+ def rubocop_lts_local_root
418
+ value = ENV["RUBOCOP_LTS_LOCAL"].to_s.strip
419
+ return nil if value.empty? || %w[false 0 no off].include?(value.downcase)
420
+ return File.join(Dir.home, "src", "rubocop-lts") if %w[true 1 yes on].include?(value.downcase)
421
+ return value if value.start_with?("/")
422
+
423
+ File.join(Dir.home, value)
424
+ end
425
+
426
+ def selected_rubocop_lts_ruby_gem
427
+ path = File.join(@root, "gemfiles", "modular", "style_local.gemfile")
428
+ return nil unless File.file?(path)
429
+
430
+ content = File.read(path)
431
+ # This reads the generated kettle-jem style_local.gemfile declaration
432
+ # without evaluating the Gemfile during release preflight.
433
+ local_gems = content[/\blocal_gems\s*=\s*%w\[(.*?)\]/m, 1].to_s.split
434
+ local_gems.find { |gem_name| Kettle::Rb::CompatMatrix.rubocop_ruby_gem?(gem_name) }
435
+ end
436
+
329
437
  def run_pre_release_checks!
330
438
  puts "Running pre-release checks via kettle-pre-release..."
331
439
  Kettle::Dev::PreReleaseCLI.new(check_num: 1).run
@@ -405,7 +513,6 @@ module Kettle
405
513
  # This helps ensure docs are kept in sync when bumping the years.
406
514
  # Aborts with a helpful message when they differ.
407
515
  def validate_copyright_years!
408
- require "set"
409
516
  readme = File.join(@root, "README.md")
410
517
  license = File.join(@root, "LICENSE.txt")
411
518
  unless File.file?(readme) && File.file?(license)
@@ -446,7 +553,6 @@ module Kettle
446
553
  # then parses four-digit years and year ranges like "2012-2015" (hyphen or en dash).
447
554
  # Returns Set[Integer].
448
555
  def extract_years_from_file(path)
449
- require "set"
450
556
  years = Set.new
451
557
  content = File.read(path)
452
558
  # Only consider lines that look like copyright notices to reduce false positives
@@ -3,7 +3,7 @@
3
3
  module Kettle
4
4
  module Dev
5
5
  module Version
6
- VERSION = "2.2.18"
6
+ VERSION = "2.2.20"
7
7
  end
8
8
  VERSION = Version::VERSION # Traditional Constant Location
9
9
  end
data/lib/kettle/dev.rb CHANGED
@@ -177,38 +177,34 @@ module Kettle
177
177
  # Set up rubocop-lts, which cascades to rubocop-rubyX_X => rubocop_gradual)
178
178
  # @return [void]
179
179
  def linting_tasks
180
- begin
181
- # Lazy loaded because it won't be installed for Ruby < 2.7
182
- require "rubocop/lts"
183
-
184
- Rubocop::Lts.install_tasks
185
- if Kettle::Dev::IS_CI
186
- Kettle::Dev.register_default("rubocop_gradual:check")
187
- else
188
- Kettle::Dev.register_default("rubocop_gradual:autocorrect")
189
- end
190
- rescue LoadError
191
- # OK, no styles for you.
180
+ # Lazy loaded because it won't be installed for Ruby < 2.7
181
+ require "rubocop/lts"
182
+
183
+ Rubocop::Lts.install_tasks
184
+ if Kettle::Dev::IS_CI
185
+ Kettle::Dev.register_default("rubocop_gradual:check")
186
+ else
187
+ Kettle::Dev.register_default("rubocop_gradual:autocorrect")
192
188
  end
189
+ rescue LoadError
190
+ # OK, no styles for you.
193
191
  end
194
192
 
195
193
  ### TEST COVERAGE TASKS
196
194
  # Set up kettle-soup-cover
197
195
  # @return [void]
198
196
  def coverage_tasks
199
- begin
200
- # Lazy loaded because it won't be installed for Ruby < 2.7
201
- require "kettle-soup-cover"
202
-
203
- Kettle::Soup::Cover.install_tasks
204
- # NOTE: Coverage on CI is configured independent of this task.
205
- # This task is for local development, as it opens results in browser
206
- # simplecov:disable
207
- Kettle::Dev.register_default("coverage") unless Kettle::Dev::IS_CI
208
- # simplecov:enable
209
- rescue LoadError
210
- # OK, no soup for you.
211
- end
197
+ # Lazy loaded because it won't be installed for Ruby < 2.7
198
+ require "kettle-soup-cover"
199
+
200
+ Kettle::Soup::Cover.install_tasks
201
+ # NOTE: Coverage on CI is configured independent of this task.
202
+ # This task is for local development, as it opens results in browser
203
+ # simplecov:disable
204
+ Kettle::Dev.register_default("coverage") unless Kettle::Dev::IS_CI
205
+ # simplecov:enable
206
+ rescue LoadError
207
+ # OK, no soup for you.
212
208
  end
213
209
  end
214
210
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kettle-dev
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.18
4
+ version: 2.2.20
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter H. Boling
@@ -37,6 +37,26 @@ cert_chain:
37
37
  -----END CERTIFICATE-----
38
38
  date: 1980-01-02 00:00:00.000000000 Z
39
39
  dependencies:
40
+ - !ruby/object:Gem::Dependency
41
+ name: kettle-rb
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '0.1'
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: 0.1.0
50
+ type: :runtime
51
+ prerelease: false
52
+ version_requirements: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - "~>"
55
+ - !ruby/object:Gem::Version
56
+ version: '0.1'
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: 0.1.0
40
60
  - !ruby/object:Gem::Dependency
41
61
  name: kettle-test
42
62
  requirement: !ruby/object:Gem::Requirement
@@ -339,10 +359,10 @@ licenses:
339
359
  - AGPL-3.0-only
340
360
  metadata:
341
361
  homepage_uri: https://kettle-dev.galtzo.com
342
- source_code_uri: https://github.com/kettle-dev/kettle-dev/tree/v2.2.18
343
- changelog_uri: https://github.com/kettle-dev/kettle-dev/blob/v2.2.18/CHANGELOG.md
362
+ source_code_uri: https://github.com/kettle-dev/kettle-dev/tree/v2.2.20
363
+ changelog_uri: https://github.com/kettle-dev/kettle-dev/blob/v2.2.20/CHANGELOG.md
344
364
  bug_tracker_uri: https://github.com/kettle-dev/kettle-dev/issues
345
- documentation_uri: https://www.rubydoc.info/gems/kettle-dev/2.2.18
365
+ documentation_uri: https://www.rubydoc.info/gems/kettle-dev/2.2.20
346
366
  funding_uri: https://github.com/sponsors/pboling
347
367
  wiki_uri: https://github.com/kettle-dev/kettle-dev/wiki
348
368
  news_uri: https://www.railsbling.com/tags/kettle-dev
metadata.gz.sig CHANGED
Binary file