kettle-dev 2.0.6 → 2.0.8

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.
@@ -53,7 +53,7 @@ module Kettle
53
53
  if gemspec_path && File.file?(gemspec_path)
54
54
  begin
55
55
  spec = Gem::Specification.load(gemspec_path)
56
- rescue StandardError => e
56
+ rescue => e
57
57
  Kettle::Dev.debug_error(e, __method__)
58
58
  spec = nil
59
59
  end
@@ -62,7 +62,7 @@ module Kettle
62
62
  gemspec_source = if gemspec_path && File.file?(gemspec_path)
63
63
  begin
64
64
  File.read(gemspec_path)
65
- rescue StandardError => e
65
+ rescue => e
66
66
  Kettle::Dev.debug_error(e, __method__)
67
67
  ""
68
68
  end
@@ -91,7 +91,7 @@ module Kettle
91
91
  puts "WARNING: Minimum Ruby not detected"
92
92
  DEFAULT_MINIMUM_RUBY
93
93
  end
94
- rescue StandardError => e
94
+ rescue => e
95
95
  puts "WARNING: Minimum Ruby detection failed:"
96
96
  Kettle::Dev.debug_error(e, __method__)
97
97
  # Default to a minimum of Ruby 1.8
@@ -117,7 +117,7 @@ module Kettle
117
117
  entrypoint_require = derive_entrypoint_require(
118
118
  root: root,
119
119
  gem_name: gem_name,
120
- gemspec_source: gemspec_source,
120
+ gemspec_source: gemspec_source
121
121
  )
122
122
  namespace_source = entrypoint_require.to_s.empty? ? gem_name.to_s.tr("-", "/") : entrypoint_require.to_s
123
123
  namespace = namespace_source.split("/").reject(&:empty?).map { |seg| camel.call(seg) }.join("::")
@@ -153,7 +153,7 @@ module Kettle
153
153
  end
154
154
  end
155
155
  end
156
- rescue StandardError => error
156
+ rescue => error
157
157
  Kettle::Dev.debug_error(error, __method__)
158
158
  # In an unexpected exception path, escalate to a domain error to aid callers/specs
159
159
  raise Kettle::Dev::Error, "Unable to determine funding org: #{error.message}"
@@ -182,7 +182,7 @@ module Kettle
182
182
  required_ruby_version: spec&.required_ruby_version, # Gem::Requirement instance
183
183
  require_paths: Array(spec&.require_paths),
184
184
  bindir: (spec&.bindir || "").to_s,
185
- executables: Array(spec&.executables),
185
+ executables: Array(spec&.executables)
186
186
  }
187
187
 
188
188
  CACHE.mutex.synchronize do
@@ -223,7 +223,7 @@ module Kettle
223
223
  forge_info[:forge_org] = m[1]
224
224
  forge_info[:origin_repo] = m[2].to_s.sub(/\.git\z/, "")
225
225
  end
226
- rescue StandardError => error
226
+ rescue => error
227
227
  Kettle::Dev.debug_error(error, __method__)
228
228
  # be lenient here; actual error raising will occur in caller if required
229
229
  end
@@ -255,7 +255,7 @@ module Kettle
255
255
  content = source.to_s
256
256
  patterns = [
257
257
  %r{require_relative\s+["']lib/([^"']+)/version["']},
258
- %r{Kernel\.load\(\s*["'][#][{]__dir__[}]/lib/([^"']+)/version\.rb["']},
258
+ %r{Kernel\.load\(\s*["']\#[{]__dir__[}]/lib/([^"']+)/version\.rb["']}
259
259
  ]
260
260
 
261
261
  patterns.each do |pattern|
@@ -23,7 +23,7 @@ module Kettle
23
23
  status = @git.status
24
24
  # git gem's Status responds to changed, added, deleted, untracked, etc.
25
25
  status.changed.empty? && status.added.empty? && status.deleted.empty? && status.untracked.empty?
26
- rescue StandardError => e
26
+ rescue => e
27
27
  Kettle::Dev.debug_error(e, __method__)
28
28
  false
29
29
  end
@@ -31,7 +31,7 @@ module Kettle
31
31
  out, st = Open3.capture2("git", "status", "--porcelain")
32
32
  st.success? && out.strip.empty?
33
33
  end
34
- rescue StandardError => e
34
+ rescue => e
35
35
  Kettle::Dev.debug_error(e, __method__)
36
36
  false
37
37
  end
@@ -45,7 +45,7 @@ module Kettle
45
45
  def capture(args)
46
46
  out, status = Open3.capture2("git", *args)
47
47
  [out.strip, status.success?]
48
- rescue StandardError => e
48
+ rescue => e
49
49
  Kettle::Dev.debug_error(e, __method__)
50
50
  ["", false]
51
51
  end
@@ -70,7 +70,7 @@ module Kettle
70
70
  Kettle::Dev.debug_error(e, __method__, backtrace: false)
71
71
  # Optional dependency: fall back to CLI
72
72
  @backend = :cli
73
- rescue StandardError => e
73
+ rescue => e
74
74
  raise Kettle::Dev::Error, "Failed to open git repository: #{e.message}"
75
75
  end
76
76
  end
@@ -90,7 +90,7 @@ module Kettle
90
90
  @git.push(nil, branch, force: force)
91
91
  end
92
92
  true
93
- rescue StandardError => e
93
+ rescue => e
94
94
  Kettle::Dev.debug_error(e, __method__)
95
95
  false
96
96
  end
@@ -129,7 +129,7 @@ module Kettle
129
129
  else
130
130
  system("git", "push", "--tags")
131
131
  end
132
- rescue StandardError => e
132
+ rescue => e
133
133
  Kettle::Dev.debug_error(e, __method__)
134
134
  false
135
135
  end
@@ -142,7 +142,7 @@ module Kettle
142
142
  out, status = Open3.capture2("git", "rev-parse", "--abbrev-ref", "HEAD")
143
143
  status.success? ? out.strip : nil
144
144
  end
145
- rescue StandardError => e
145
+ rescue => e
146
146
  Kettle::Dev.debug_error(e, __method__)
147
147
  nil
148
148
  end
@@ -154,7 +154,7 @@ module Kettle
154
154
  if @backend == :gem
155
155
  begin
156
156
  @git.ls_files.keys
157
- rescue StandardError => e
157
+ rescue => e
158
158
  Kettle::Dev.debug_error(e, __method__)
159
159
  []
160
160
  end
@@ -162,7 +162,7 @@ module Kettle
162
162
  out, status = Open3.capture2("git", "ls-files")
163
163
  status.success? ? out.split(/\r?\n/).reject(&:empty?) : []
164
164
  end
165
- rescue StandardError => e
165
+ rescue => e
166
166
  Kettle::Dev.debug_error(e, __method__)
167
167
  []
168
168
  end
@@ -178,7 +178,7 @@ module Kettle
178
178
  def blame_porcelain(path)
179
179
  out, status = Open3.capture2("git", "blame", "--porcelain", path.to_s)
180
180
  status.success? ? out : ""
181
- rescue StandardError => e
181
+ rescue => e
182
182
  Kettle::Dev.debug_error(e, __method__)
183
183
  ""
184
184
  end
@@ -191,7 +191,7 @@ module Kettle
191
191
  out, status = Open3.capture2("git", "remote")
192
192
  status.success? ? out.split(/\r?\n/).map(&:strip).reject(&:empty?) : []
193
193
  end
194
- rescue StandardError => e
194
+ rescue => e
195
195
  Kettle::Dev.debug_error(e, __method__)
196
196
  []
197
197
  end
@@ -202,7 +202,7 @@ module Kettle
202
202
  @git.remotes.each_with_object({}) do |r, h|
203
203
  begin
204
204
  h[r.name] = r.url
205
- rescue StandardError => e
205
+ rescue => e
206
206
  Kettle::Dev.debug_error(e, __method__)
207
207
  # ignore
208
208
  end
@@ -220,7 +220,7 @@ module Kettle
220
220
  end
221
221
  urls
222
222
  end
223
- rescue StandardError => e
223
+ rescue => e
224
224
  Kettle::Dev.debug_error(e, __method__)
225
225
  {}
226
226
  end
@@ -235,7 +235,7 @@ module Kettle
235
235
  out, status = Open3.capture2("git", "config", "--get", "remote.#{name}.url")
236
236
  status.success? ? out.strip : nil
237
237
  end
238
- rescue StandardError => e
238
+ rescue => e
239
239
  Kettle::Dev.debug_error(e, __method__)
240
240
  nil
241
241
  end
@@ -250,7 +250,7 @@ module Kettle
250
250
  else
251
251
  system("git", "checkout", branch.to_s)
252
252
  end
253
- rescue StandardError => e
253
+ rescue => e
254
254
  Kettle::Dev.debug_error(e, __method__)
255
255
  false
256
256
  end
@@ -266,7 +266,7 @@ module Kettle
266
266
  else
267
267
  system("git", "pull", remote.to_s, branch.to_s)
268
268
  end
269
- rescue StandardError => e
269
+ rescue => e
270
270
  Kettle::Dev.debug_error(e, __method__)
271
271
  false
272
272
  end
@@ -288,7 +288,7 @@ module Kettle
288
288
  else
289
289
  system("git", "fetch", remote.to_s)
290
290
  end
291
- rescue StandardError => e
291
+ rescue => e
292
292
  Kettle::Dev.debug_error(e, __method__)
293
293
  false
294
294
  end
@@ -20,9 +20,9 @@ module Kettle
20
20
  def git_toplevel
21
21
  toplevel = nil
22
22
  begin
23
- out = %x(git rev-parse --show-toplevel 2>/dev/null)
23
+ out = `git rev-parse --show-toplevel 2>/dev/null`
24
24
  toplevel = out.strip unless out.nil? || out.empty?
25
- rescue StandardError => e
25
+ rescue => e
26
26
  Kettle::Dev.debug_error(e, __method__)
27
27
  nil
28
28
  end
@@ -114,7 +114,7 @@ module Kettle
114
114
  if @name_index
115
115
  return $2
116
116
  end
117
- rescue StandardError => e
117
+ rescue => e
118
118
  Kettle::Dev.debug_error(e, __method__)
119
119
  end
120
120
  nil
@@ -56,7 +56,7 @@ module Kettle
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\|[^}]+}/)
58
58
  end
59
- rescue StandardError => e
59
+ rescue => e
60
60
  Kettle::Dev.debug_error(e, __method__) if Kettle::Dev.respond_to?(:debug_error)
61
61
  # fall through to required check
62
62
  end
@@ -102,7 +102,7 @@ module Kettle
102
102
  urls = []
103
103
 
104
104
  # Inline image syntax
105
- text.scan(/!\[[^\]]*\]\(([^\s)]+)(?:\s+\"[^\"]*\")?\)/) { |m| urls << m[0] }
105
+ text.scan(/!\[[^\]]*\]\(([^\s)]+)(?:\s+"[^"]*")?\)/) { |m| urls << m[0] }
106
106
 
107
107
  # Reference definitions
108
108
  ref_defs = {}
@@ -116,8 +116,8 @@ module Kettle
116
116
  end
117
117
 
118
118
  # HTML <img src="...">
119
- text.scan(/<img\b[^>]*\bsrc\s*=\s*\"([^\"]+)\"[^>]*>/i) { |m| urls << m[0] }
120
- text.scan(/<img\b[^>]*\bsrc\s*=\s*\'([^\']+)\'[^>]*>/i) { |m| urls << m[0] }
119
+ text.scan(/<img\b[^>]*\bsrc\s*=\s*"([^"]+)"[^>]*>/i) { |m| urls << m[0] }
120
+ text.scan(/<img\b[^>]*\bsrc\s*=\s*'([^']+)'[^>]*>/i) { |m| urls << m[0] }
121
121
 
122
122
  urls.reject! { |u| u.nil? || u.strip.empty? }
123
123
  urls.select! { |u| u =~ %r{^https?://}i }
@@ -132,7 +132,7 @@ module Kettle
132
132
  urls = files.flat_map do |f|
133
133
  begin
134
134
  extract_image_urls_from_text(File.read(f))
135
- rescue StandardError => e
135
+ rescue => e
136
136
  warn("[kettle-pre-release] Could not read #{Kettle::Dev.display_path(f)}: #{e.class}: #{e.message}")
137
137
  []
138
138
  end
@@ -178,7 +178,7 @@ module Kettle
178
178
  files.each do |file|
179
179
  begin
180
180
  original = File.read(file)
181
- rescue StandardError => e
181
+ rescue => e
182
182
  warn("[kettle-pre-release] Could not read #{Kettle::Dev.display_path(file)}: #{e.class}: #{e.message}")
183
183
  next
184
184
  end
@@ -206,7 +206,7 @@ module Kettle
206
206
  begin
207
207
  File.write(file, updated)
208
208
  changed << file
209
- rescue StandardError => e
209
+ rescue => e
210
210
  warn("[kettle-pre-release] Could not write #{Kettle::Dev.display_path(file)}: #{e.class}: #{e.message}")
211
211
  end
212
212
  end
@@ -222,7 +222,7 @@ module Kettle
222
222
  puts "[kettle-pre-release] Check 2: Validate Markdown image links (HTTP HEAD)"
223
223
  urls = [
224
224
  Markdown.extract_image_urls_from_files("**/*.md"),
225
- Markdown.extract_image_urls_from_files("**/*.md.example"),
225
+ Markdown.extract_image_urls_from_files("**/*.md.example")
226
226
  ].flatten.uniq
227
227
  puts "[kettle-pre-release] Found #{urls.size} unique image URL(s)."
228
228
  failures = []
@@ -61,19 +61,23 @@ begin
61
61
  run_in_unbundled = proc do
62
62
  env = {"BUNDLE_GEMFILE" => "Appraisal.root.gemfile"}
63
63
 
64
- # 1) BUNDLE_GEMFILE=Appraisal.root.gemfile bundle update --bundler
64
+ # 1) BUNDLE_GEMFILE=Appraisal.root.gemfile bundle install
65
+ ok = system(env, bundle, "install")
66
+ abort("appraisal:update failed: BUNDLE_GEMFILE=Appraisal.root.gemfile bundle install") unless ok
67
+
68
+ # 2) BUNDLE_GEMFILE=Appraisal.root.gemfile bundle update --bundler
65
69
  ok = system(env, bundle, "update", "--bundler")
66
70
  abort("appraisal:update failed: BUNDLE_GEMFILE=Appraisal.root.gemfile bundle update --bundler") unless ok
67
71
 
68
- # 2) BUNDLE_GEMFILE=Appraisal.root.gemfile bundle install
72
+ # 3) BUNDLE_GEMFILE=Appraisal.root.gemfile bundle install
69
73
  ok = system(env, bundle, "install")
70
74
  abort("appraisal:update failed: BUNDLE_GEMFILE=Appraisal.root.gemfile bundle install") unless ok
71
75
 
72
- # 3) BUNDLE_GEMFILE=Appraisal.root.gemfile bundle exec appraisal update
76
+ # 4) BUNDLE_GEMFILE=Appraisal.root.gemfile bundle exec appraisal update
73
77
  ok = system(env, bundle, "exec", "appraisal", "update")
74
78
  abort("appraisal:update failed: BUNDLE_GEMFILE=Appraisal.root.gemfile bundle exec appraisal update") unless ok
75
79
 
76
- # 4) bundle exec rake rubocop_gradual:autocorrect
80
+ # 5) bundle exec rake rubocop_gradual:autocorrect
77
81
  ok = system(bundle, "exec", "rake", "rubocop_gradual:autocorrect")
78
82
  abort("appraisal:update failed: rubocop_gradual:autocorrect") unless ok
79
83
  end
@@ -101,7 +105,7 @@ begin
101
105
  File.delete(f)
102
106
  rescue Errno::ENOENT
103
107
  # Ignore if already gone
104
- rescue StandardError => e
108
+ rescue => e
105
109
  failures << [f, e]
106
110
  end
107
111
  end
@@ -76,10 +76,10 @@ module Kettle
76
76
  else
77
77
  "https://github.com/organizations/YOUR_ORG/settings/secrets/actions"
78
78
  end
79
- $stderr.puts "ERROR: README_UPDATER_TOKEN is not set."
80
- $stderr.puts "Please create an organization-level Actions secret named README_UPDATER_TOKEN at:"
81
- $stderr.puts " #{org_url}"
82
- $stderr.puts "Then update the workflow to reference it, or provide README_UPDATER_TOKEN in the environment."
79
+ warn "ERROR: README_UPDATER_TOKEN is not set."
80
+ warn "Please create an organization-level Actions secret named README_UPDATER_TOKEN at:"
81
+ warn " #{org_url}"
82
+ warn "Then update the workflow to reference it, or provide README_UPDATER_TOKEN in the environment."
83
83
  raise 'Missing ENV["README_UPDATER_TOKEN"]'
84
84
  end
85
85
  nil
@@ -250,7 +250,7 @@ module Kettle
250
250
  from_yml = from_yml.to_s if from_yml
251
251
  return from_yml unless from_yml.nil? || from_yml.strip.empty?
252
252
  end
253
- rescue StandardError => e
253
+ rescue => e
254
254
  Kettle::Dev.debug_error(e, __method__)
255
255
  end
256
256
  end
@@ -265,7 +265,7 @@ module Kettle
265
265
  individuals_start: "<!-- #{base}-INDIVIDUALS:START -->",
266
266
  individuals_end: "<!-- #{base}-INDIVIDUALS:END -->",
267
267
  orgs_start: "<!-- #{base}-ORGANIZATIONS:START -->",
268
- orgs_end: "<!-- #{base}-ORGANIZATIONS:END -->",
268
+ orgs_end: "<!-- #{base}-ORGANIZATIONS:END -->"
269
269
  }
270
270
  end
271
271
 
@@ -301,7 +301,7 @@ module Kettle
301
301
  warn("Error parsing #{api_path} JSON: #{e.message}")
302
302
  debug_log("Body that failed to parse (truncated 500): #{response&.body.to_s[0, 500]}")
303
303
  []
304
- rescue StandardError => e
304
+ rescue => e
305
305
  warn("Error fetching #{api_path}: #{e.class}: #{e.message}")
306
306
  debug_log(e.backtrace.join("\n"))
307
307
  []
@@ -378,7 +378,7 @@ module Kettle
378
378
  website: (h["website"].to_s.strip.empty? ? nil : h["website"]),
379
379
  profile: (h["profile"].to_s.strip.empty? ? nil : h["profile"]),
380
380
  oc_type: oc_type,
381
- oc_index: oc_index,
381
+ oc_index: oc_index
382
382
  )
383
383
  end
384
384
  end
@@ -427,7 +427,7 @@ module Kettle
427
427
  name: m.name,
428
428
  image: m.image,
429
429
  website: m.website,
430
- profile: m.profile,
430
+ profile: m.profile
431
431
  )
432
432
  end
433
433
  # Build a single, well-formed block per tier with deterministic spacing:
@@ -437,7 +437,7 @@ module Kettle
437
437
  block = [
438
438
  "### Open Collective for #{tier}",
439
439
  "",
440
- generate_markdown(members_plain, empty_message: "", default_name: tier),
440
+ generate_markdown(members_plain, empty_message: "", default_name: tier)
441
441
  ].join("\n")
442
442
  blocks << block
443
443
  end
@@ -497,17 +497,17 @@ module Kettle
497
497
  block = content[(start_index + start_tag.length)...end_index]
498
498
  identities = Set.new
499
499
  # 1) Image-style link wrappers: [![ALT](IMG)](HREF)
500
- block.to_s.scan(/\[!\[[^\]]*\]\([^\)]*\)\]\(([^\)]+)\)/) do |m|
500
+ block.to_s.scan(/\[!\[[^\]]*\]\([^)]*\)\]\(([^)]+)\)/) do |m|
501
501
  href = (m[0] || "").strip
502
502
  identities << href.downcase unless href.empty?
503
503
  end
504
504
  # 2) Capture ALT text from image-style wrappers for name identity
505
- block.to_s.scan(/\[!\[([^\]]*)\]\([^\)]*\)\]\([^\)]*\)/) do |m|
505
+ block.to_s.scan(/\[!\[([^\]]*)\]\([^)]*\)\]\([^)]*\)/) do |m|
506
506
  alt = (m[0] || "").strip
507
507
  identities << alt.downcase unless alt.empty?
508
508
  end
509
509
  # 3) Plain markdown links: [TEXT](HREF)
510
- block.to_s.scan(/\[([^!][^\]]*)\]\(([^\)]+)\)/) do |m|
510
+ block.to_s.scan(/\[([^!][^\]]*)\]\(([^)]+)\)/) do |m|
511
511
  text = (m[0] || "").strip
512
512
  href = (m[1] || "").strip
513
513
  identities << href.downcase unless href.empty?
@@ -610,8 +610,7 @@ module Kettle
610
610
  handle = github_handle_from_urls(m.profile, m.website)
611
611
  return "@#{handle}" if handle
612
612
 
613
- name = (m.name && !m.name.strip.empty?) ? m.name.strip : default_name
614
- name
613
+ (m.name && !m.name.strip.empty?) ? m.name.strip : default_name
615
614
  end
616
615
 
617
616
  def github_handle_from_urls(*urls)
@@ -667,7 +666,7 @@ module Kettle
667
666
  from_yml = from_yml.to_s if from_yml
668
667
  return from_yml unless from_yml.nil? || from_yml.strip.empty?
669
668
  end
670
- rescue StandardError => e
669
+ rescue => e
671
670
  Kettle::Dev.debug_error(e, __method__)
672
671
  end
673
672
  end
@@ -96,7 +96,7 @@ module Kettle
96
96
  begin
97
97
  gem_name = detect_gem_name
98
98
  latest_overall, latest_for_series = latest_released_versions(gem_name, version)
99
- rescue StandardError => e
99
+ rescue => e
100
100
  warn("[kettle-release] gem.coop release check failed: #{e.class}: #{e.message}")
101
101
  warn(e.backtrace.first(3).map { |l| " " + l }.join("\n")) if ENV["KETTLE_DEV_DEBUG"]
102
102
  warn("Proceeding without gem.coop latest version info.")
@@ -167,14 +167,14 @@ module Kettle
167
167
  # Ensure README KLOC badge reflects current CHANGELOG coverage denominator
168
168
  begin
169
169
  update_readme_kloc_badge!
170
- rescue StandardError => e
170
+ rescue => e
171
171
  warn("Failed to update KLOC badge in README: #{e.class}: #{e.message}")
172
172
  end
173
173
 
174
174
  # Update Rakefile.example header banner with current version and date
175
175
  begin
176
176
  update_rakefile_example_header!(version)
177
- rescue StandardError => e
177
+ rescue => e
178
178
  warn("Failed to update Rakefile.example header: #{e.class}: #{e.message}")
179
179
  end
180
180
  end
@@ -297,7 +297,7 @@ module Kettle
297
297
  version ||= detect_version
298
298
  gem_name = detect_gem_name
299
299
  puts "\n🚀 Release #{gem_name} v#{version} Complete 🚀"
300
- rescue StandardError => e
300
+ rescue => e
301
301
  Kettle::Dev.debug_error(e, __method__)
302
302
  # Fallback if detection fails for any reason
303
303
  puts "\n🚀 Release v#{version || "unknown"} Complete 🚀"
@@ -414,7 +414,7 @@ module Kettle
414
414
  next unless /copyright/i.match?(line)
415
415
 
416
416
  # Expand ranges first (supports hyphen-minus and en dash)
417
- line.scan(/\b(19\d{2}|20\d{2})\s*[\-–]\s*(19\d{2}|20\d{2})\b/).each do |a, b|
417
+ line.scan(/\b(19\d{2}|20\d{2})\s*[-–]\s*(19\d{2}|20\d{2})\b/).each do |a, b|
418
418
  s = a.to_i
419
419
  e = b.to_i
420
420
  if e < s
@@ -466,7 +466,7 @@ module Kettle
466
466
  next line
467
467
  end
468
468
 
469
- m = line.match(/\A(?<pre>.*?copyright[^0-9]*)(?<years>(?:\b(?:19|20)\d{2}\b(?:\s*[\-–]\s*\b(?:19|20)\d{2}\b)?)(?:\s*,\s*\b(?:19|20)\d{2}\b(?:\s*[\-–]\s*\b(?:19|20)\d{2}\b)?)*)(?<post>.*)\z/i)
469
+ m = line.match(/\A(?<pre>.*?copyright[^0-9]*)(?<years>(?:\b(?:19|20)\d{2}\b(?:\s*[-–]\s*\b(?:19|20)\d{2}\b)?)(?:\s*,\s*\b(?:19|20)\d{2}\b(?:\s*[-–]\s*\b(?:19|20)\d{2}\b)?)*)(?<post>.*)\z/i)
470
470
  unless m
471
471
  next line
472
472
  end
@@ -491,7 +491,7 @@ module Kettle
491
491
  end
492
492
 
493
493
  # Capture three parts: prefix up to first year, the year blob, and the rest
494
- m = line.match(/\A(?<pre>.*?copyright[^0-9]*)(?<years>(?:\b(?:19|20)\d{2}\b(?:\s*[\-–]\s*\b(?:19|20)\d{2}\b)?)(?:\s*,\s*\b(?:19|20)\d{2}\b(?:\s*[\-–]\s*\b(?:19|20)\d{2}\b)?)*)(?<post>.*)\z/i)
494
+ m = line.match(/\A(?<pre>.*?copyright[^0-9]*)(?<years>(?:\b(?:19|20)\d{2}\b(?:\s*[-–]\s*\b(?:19|20)\d{2}\b)?)(?:\s*,\s*\b(?:19|20)\d{2}\b(?:\s*[-–]\s*\b(?:19|20)\d{2}\b)?)*)(?<post>.*)\z/i)
495
495
  unless m
496
496
  # No parsable year sequence on this line; leave as-is
497
497
  next line
@@ -500,7 +500,7 @@ module Kettle
500
500
  years_blob = m[:years]
501
501
  # Reuse extraction logic on just the years blob
502
502
  years = []
503
- years_blob.scan(/\b(19\d{2}|20\d{2})\s*[\-–]\s*(19\d{2}|20\d{2})\b/).each do |a, b|
503
+ years_blob.scan(/\b(19\d{2}|20\d{2})\s*[-–]\s*(19\d{2}|20\d{2})\b/).each do |a, b|
504
504
  s = a.to_i
505
505
  e = b.to_i
506
506
  s, e = e, s if e < s
@@ -567,7 +567,7 @@ module Kettle
567
567
 
568
568
  act_ok = begin
569
569
  system("act", "--version", out: File::NULL, err: File::NULL)
570
- rescue StandardError => e
570
+ rescue => e
571
571
  Kettle::Dev.debug_error(e, __method__)
572
572
  false
573
573
  end
@@ -648,7 +648,7 @@ module Kettle
648
648
  series_versions = gversions.select { |gv| gv.segments[0, 2] == series }
649
649
  latest_series = series_versions.last&.to_s
650
650
  [latest_overall, latest_series]
651
- rescue StandardError => e
651
+ rescue => e
652
652
  Kettle::Dev.debug_error(e, __method__)
653
653
  [nil, nil]
654
654
  end
@@ -957,7 +957,7 @@ module Kettle
957
957
  pkg = File.join(@root, "pkg")
958
958
  pattern = File.join(pkg, "*.gem")
959
959
  gems = Dir[pattern].select { |p| File.basename(p).include?("-#{version}.gem") }
960
- gems.sort.last
960
+ gems.max
961
961
  end
962
962
 
963
963
  def compute_sha256(path)
@@ -1042,7 +1042,7 @@ module Kettle
1042
1042
  compare_ref = compare_ref&.end_with?("\n") ? compare_ref : (compare_ref && compare_ref + "\n")
1043
1043
  tag_ref = tag_ref&.end_with?("\n") ? tag_ref : (tag_ref && tag_ref + "\n")
1044
1044
  [section, compare_ref, tag_ref]
1045
- rescue StandardError => e
1045
+ rescue => e
1046
1046
  warn("Failed to parse CHANGELOG.md: #{e.class}: #{e.message}")
1047
1047
  [nil, nil, nil]
1048
1048
  end
@@ -1063,7 +1063,7 @@ module Kettle
1063
1063
  # Normalize: trim trailing whitespace but keep internal formatting
1064
1064
  block = block.lstrip # drop leading newline/space
1065
1065
  block.rstrip
1066
- rescue StandardError => e
1066
+ rescue => e
1067
1067
  warn("[kettle-release] Failed to extract release notes footer from FUNDING.md: #{e.class}: #{e.message}")
1068
1068
  nil
1069
1069
  end
@@ -1081,7 +1081,7 @@ module Kettle
1081
1081
  name: title,
1082
1082
  body: body,
1083
1083
  draft: false,
1084
- prerelease: false,
1084
+ prerelease: false
1085
1085
  })
1086
1086
 
1087
1087
  res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
@@ -1099,7 +1099,7 @@ module Kettle
1099
1099
  [false, "HTTP #{res.code}: #{res.body}"]
1100
1100
  end
1101
1101
  end
1102
- rescue StandardError => e
1102
+ rescue => e
1103
1103
  [false, "#{e.class}: #{e.message}"]
1104
1104
  end
1105
1105
  end
@@ -84,7 +84,7 @@ module Kettle
84
84
  else
85
85
  puts "GHA status: request failed (#{res.code})"
86
86
  end
87
- rescue StandardError => e
87
+ rescue => e
88
88
  puts "GHA status: error #{e.class}: #{e.message}"
89
89
  end
90
90
  end
@@ -130,7 +130,7 @@ module Kettle
130
130
  else
131
131
  puts "Latest GL (#{branch}) pipeline: none"
132
132
  end
133
- rescue StandardError => e
133
+ rescue => e
134
134
  puts "GL status: error #{e.class}: #{e.message}"
135
135
  end
136
136
  end
@@ -174,7 +174,6 @@ module Kettle
174
174
  end
175
175
 
176
176
  # Interactive menu
177
- require "thread"
178
177
  tty = $stdout.tty?
179
178
  options = mapping.to_a + dynamic_files.map { |f| [f, f] }
180
179
  quit_code = "q"
@@ -190,14 +189,14 @@ module Kettle
190
189
  upstream = begin
191
190
  out, status = Open3.capture2("git", "rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}")
192
191
  status.success? ? out.strip : nil
193
- rescue StandardError => e
192
+ rescue => e
194
193
  Kettle::Dev.debug_error(e, __method__)
195
194
  nil
196
195
  end
197
196
  sha = begin
198
197
  out, status = Open3.capture2("git", "rev-parse", "--short", "HEAD")
199
198
  status.success? ? out.strip : nil
200
- rescue StandardError => e
199
+ rescue => e
201
200
  Kettle::Dev.debug_error(e, __method__)
202
201
  nil
203
202
  end
@@ -235,7 +234,7 @@ module Kettle
235
234
  end
236
235
  end
237
236
  end
238
- rescue StandardError => e
237
+ rescue => e
239
238
  Kettle::Dev.debug_error(e, __method__)
240
239
  end
241
240
 
@@ -263,18 +262,20 @@ module Kettle
263
262
  sleep(0.2)
264
263
 
265
264
  selected = nil
266
- # Create input thread always so specs that assert its cleanup/exception behavior can exercise it,
267
- # but guard against non-interactive stdin by rescuing 'bad tty' and similar errors immediately.
268
- input_thread = Thread.new do # rubocop:disable ThreadSafety/NewThread
265
+ input_thread = nil
266
+ read_input = proc do
269
267
  begin
270
268
  selected = Kettle::Dev::InputAdapter.gets&.strip
271
269
  rescue StandardError, SystemExit, Interrupt => error
272
- # Catch exceptions in background thread, including SystemExit
273
- # NOTE: look into refactoring to minimize potential SystemExit.
274
- puts "Error in background thread: #{error.class}: #{error.message}" if Kettle::Dev::DEBUGGING
270
+ puts "Error reading input: #{error.class}: #{error.message}" if Kettle::Dev::DEBUGGING
275
271
  selected = :input_error
276
272
  end
277
273
  end
274
+ if tty
275
+ input_thread = Thread.new(&read_input) # rubocop:disable ThreadSafety/NewThread
276
+ else
277
+ read_input.call
278
+ end
278
279
 
279
280
  status_q = Queue.new
280
281
  workers = []
@@ -381,12 +382,12 @@ module Kettle
381
382
 
382
383
  begin
383
384
  workers.each { |t| t.kill if t&.alive? }
384
- rescue StandardError => e
385
+ rescue => e
385
386
  Kettle::Dev.debug_error(e, __method__)
386
387
  end
387
388
  begin
388
389
  input_thread.kill if input_thread&.alive?
389
- rescue StandardError => e
390
+ rescue => e
390
391
  Kettle::Dev.debug_error(e, __method__)
391
392
  end
392
393