kettle-dev 2.5.19 → 2.5.21

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: a8ffb38694a14518e416b497413025d417137ce7b7cf8673dd31f68aa46c8539
4
- data.tar.gz: 71d1ff523dc11ba20f72994792ad3edd4ff43a0ceea2c8c84e46e65b77e72977
3
+ metadata.gz: 75484cde250c1d87c9c5b85180972c7eb9596874b2d04ec1901d0bf9b60313cc
4
+ data.tar.gz: f71c7e5bfcf8411b2545d3a6d0875c323a8f90f6374d8a21a839ecafa6389b5b
5
5
  SHA512:
6
- metadata.gz: a7cf27e978644578be5e2839670c4981343b9d84646d59ece70e4d83eb388404dcd52b77c3f90929164ff86f698bc6bfc93ecfa42f8bfc9a2ec342d764030aa3
7
- data.tar.gz: 59de547a4f7a50905bed8bc66c8b919eca375ff9d4d31bd079371dfee717d540bf800477bae8dad644a2efe7935d7cb44b53e059cb4554a99c54d5655d372dc2
6
+ metadata.gz: 7418829b37e194a8a248e9ea7a2a4e2e48040d55d0008b0e0f86e939815576b3c6715b364f4f2c686031c644c41a80306e24f46cbc9ced3771ab0de2e60e8f48
7
+ data.tar.gz: f6910b5d7315bd82a8cfea7cc07aa581b6cf654b994ad6463d07952bfec95cb427e2ba225fd3fce009ad6083ed7cc133c875c056a5872c15a4664ce0701a1b4e
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -30,6 +30,32 @@ Please file a bug if you notice a violation of semantic versioning.
30
30
 
31
31
  ### Security
32
32
 
33
+ ## [2.5.21] - 2026-08-07
34
+
35
+ - TAG: [v2.5.21][2.5.21t]
36
+ - COVERAGE: 91.99% -- 5469/5945 lines in 47 files
37
+ - BRANCH COVERAGE: 76.14% -- 2058/2703 branches in 47 files
38
+ - 50.77% documented
39
+
40
+ ### Fixed
41
+
42
+ - Release coverage now honors a project that disables hard coverage thresholds.
43
+
44
+ - Release-state version lookups now refresh when the cached RubyGems data predates the requested version.
45
+
46
+ ## [2.5.20] - 2026-08-07
47
+
48
+ - TAG: [v2.5.20][2.5.20t]
49
+ - COVERAGE: 91.75% -- 5440/5929 lines in 47 files
50
+ - BRANCH COVERAGE: 76.14% -- 2049/2691 branches in 47 files
51
+ - 50.77% documented
52
+
53
+ ### Fixed
54
+
55
+ - Prefer non-cancelled exact-commit GitHub Actions runs when workflow concurrency creates duplicate runs.
56
+
57
+ - Skip YARD lint when a project has no .yard-lint.yml policy.
58
+
33
59
  ## [2.5.19] - 2026-08-06
34
60
 
35
61
  - TAG: [v2.5.19][2.5.19t]
@@ -3259,7 +3285,11 @@ Please file a bug if you notice a violation of semantic versioning.
3259
3285
  - Selecting will run the selected workflow via `act`
3260
3286
  - This may move to its own gem in the future.
3261
3287
 
3262
- [Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v2.5.19...HEAD
3288
+ [Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v2.5.21...HEAD
3289
+ [2.5.21]: https://github.com/kettle-dev/kettle-dev/compare/v2.5.20...v2.5.21
3290
+ [2.5.21t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v2.5.21
3291
+ [2.5.20]: https://github.com/kettle-dev/kettle-dev/compare/v2.5.19...v2.5.20
3292
+ [2.5.20t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v2.5.20
3263
3293
  [2.5.19]: https://github.com/kettle-dev/kettle-dev/compare/v2.5.18...v2.5.19
3264
3294
  [2.5.19t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v2.5.19
3265
3295
  [2.5.18]: https://github.com/kettle-dev/kettle-dev/compare/v2.5.17...v2.5.18
data/README.md CHANGED
@@ -1007,7 +1007,7 @@ Thanks for RTFM. ☺️
1007
1007
  [📌gitmoji]: https://gitmoji.dev
1008
1008
  [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
1009
1009
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
1010
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-5.946-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1010
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-5.945-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1011
1011
  [🔐security]: https://github.com/kettle-dev/kettle-dev/blob/main/SECURITY.md
1012
1012
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
1013
1013
  [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
@@ -104,9 +104,10 @@ module Kettle
104
104
  return unless data
105
105
 
106
106
  runs = Array(data["workflow_runs"]) || []
107
- # Try to match by head_sha first; fall back to first run (branch-scoped) if none matches yet.
107
+ # Try to match by head_sha first; GitHub may return a cancelled duplicate
108
+ # before the replacement run created by workflow concurrency.
108
109
  run = if sha
109
- match = runs.find { |r| r["head_sha"] == sha }
110
+ match = preferred_head_run(runs.select { |r| r["head_sha"] == sha })
110
111
  match ||= latest_repository_workflow_run(owner: owner, repo: repo, workflow_file: workflow_file, branch: b, head_sha: sha, token: token)
111
112
  require_head ? match : (match || runs.first)
112
113
  else
@@ -134,9 +135,18 @@ module Kettle
134
135
  return unless data
135
136
 
136
137
  workflow_path = ".github/workflows/#{workflow_file}"
137
- Array(data["workflow_runs"]).find do |run|
138
- run["head_sha"] == head_sha && run["path"] == workflow_path
139
- end
138
+ preferred_head_run(
139
+ Array(data["workflow_runs"]).select do |run|
140
+ run["head_sha"] == head_sha && run["path"] == workflow_path
141
+ end
142
+ )
143
+ end
144
+
145
+ # Concurrency cancellation can leave an older run for the exact same
146
+ # commit ahead of its replacement in GitHub's API response. Prefer the
147
+ # replacement so a cancelled duplicate cannot mask a valid run.
148
+ def preferred_head_run(runs)
149
+ runs.find { |run| run["conclusion"] != "cancelled" } || runs.first
140
150
  end
141
151
 
142
152
  def github_get_json(url, token:)
@@ -219,5 +219,7 @@ begin
219
219
  end
220
220
  end
221
221
  rescue LoadError
222
+ # simplecov:disable -- Appraisal is an optional development dependency.
222
223
  warn("[kettle-dev][appraisal.rake] failed to load appraisal/tasks") if Kettle::Dev::DEBUGGING
224
+ # simplecov:enable
223
225
  end
@@ -27,10 +27,12 @@ else
27
27
  Kettle::Dev.register_default("bundle:audit:update")
28
28
  Kettle::Dev.register_default("bundle:audit")
29
29
  rescue LoadError
30
+ # simplecov:disable -- bundler-audit is an optional development dependency.
30
31
  warn("[kettle-dev][bundle_audit.rake] failed to load bundle/audit/task") if Kettle::Dev::DEBUGGING
31
32
  define_bundle_audit_stub_tasks.call(
32
33
  "(stub)",
33
34
  ->(_task_name) { "NOTE: bundler-audit isn't installed, or is disabled for #{RUBY_VERSION} in the current environment" }
34
35
  )
36
+ # simplecov:enable
35
37
  end
36
38
  end
@@ -31,9 +31,11 @@ begin
31
31
  end
32
32
  Kettle::Dev.register_default("reek:update") unless Kettle::Dev::IS_CI
33
33
  rescue LoadError
34
+ # simplecov:disable -- Reek is an optional development dependency.
34
35
  warn("[kettle-dev][reek.rake] failed to load reek/rake/task") if Kettle::Dev::DEBUGGING
35
36
  desc("(stub) reek is unavailable")
36
37
  task(:reek) do
37
38
  warn("NOTE: reek isn't installed, or is disabled for #{RUBY_VERSION} in the current environment")
38
39
  end
40
+ # simplecov:enable
39
41
  end
@@ -3,5 +3,7 @@
3
3
  begin
4
4
  require "require_bench/tasks" if Kettle::Dev::REQUIRE_BENCH
5
5
  rescue LoadError
6
+ # simplecov:disable -- require_bench is an opt-in development dependency.
6
7
  warn("[kettle-dev][require_bench.rake] failed to load require_bench/tasks") if Kettle::Dev::DEBUGGING
8
+ # simplecov:enable
7
9
  end
@@ -7,5 +7,7 @@ begin
7
7
  t.options = ["--debug"]
8
8
  end
9
9
  rescue LoadError
10
+ # simplecov:disable -- RuboCop Gradual is an optional development dependency.
10
11
  warn("[kettle-dev][rubocop_gradual.rake] failed to load rubocop/gradual/rake_task") if Kettle::Dev::DEBUGGING
12
+ # simplecov:enable
11
13
  end
@@ -24,6 +24,7 @@ begin
24
24
  Kettle::Dev.register_default("test") unless Kettle::Dev.default_registered?("coverage")
25
25
  end
26
26
  rescue LoadError
27
+ # simplecov:disable -- Rake's optional test task integration varies by runtime.
27
28
  warn("[kettle-dev][spec_test.rake] failed to load rake/testtask") if Kettle::Dev::DEBUGGING
28
29
  unless Rake::Task.task_defined?(:test)
29
30
  desc("test task stub")
@@ -31,6 +32,7 @@ rescue LoadError
31
32
  warn("NOTE: minitest isn't installed, or is disabled for #{RUBY_VERSION} in the current environment")
32
33
  end
33
34
  end
35
+ # simplecov:enable
34
36
  end
35
37
 
36
38
  setup_spec_task = ->(default:) {
@@ -14,20 +14,26 @@ begin
14
14
  begin
15
15
  require "yard/fence"
16
16
  Yard::Fence.install_rake_tasks!(:yard)
17
+ # simplecov:disable -- optional plugin availability is environment-specific.
17
18
  rescue LoadError
18
19
  # yard-fence not available - that's fine
20
+ # simplecov:enable
19
21
  end
20
22
 
21
23
  begin
22
24
  require "yard/timekeeper"
23
25
  Yard::Timekeeper.install_rake_tasks!(:yard)
26
+ # simplecov:disable -- optional plugin availability is environment-specific.
24
27
  rescue LoadError
25
28
  # yard-timekeeper not available - that's fine
29
+ # simplecov:enable
26
30
  end
27
31
 
28
32
  namespace :yard do
29
33
  desc "Lint YARD Documentation"
30
34
  task :lint do
35
+ next unless File.file?(".yard-lint.yml")
36
+
31
37
  # Keep warning-only lint runs compact in default/release flows, but rerun
32
38
  # with full output when lint fails so the blocking diagnostics are visible.
33
39
  sh("bundle", "exec", "yard-lint", "lib") unless system("bundle", "exec", "yard-lint", "--quiet", "lib")
@@ -39,10 +45,12 @@ begin
39
45
  Kettle::Dev.register_default("yard:lint")
40
46
  Kettle::Dev.register_default("yard")
41
47
  rescue LoadError
48
+ # simplecov:disable -- YARD is an optional development dependency.
42
49
  warn("[kettle-dev][yard.rake] failed to load yard") if Kettle::Dev::DEBUGGING
43
50
  desc("(stub) yard is unavailable")
44
51
  task(:yard) do # rubocop:disable Rake/DuplicateTask -- fallback when the real YARD task cannot load
45
52
  warn("NOTE: yard isn't installed, or is disabled for #{RUBY_VERSION} in the current environment")
46
53
  end
47
54
  Kettle::Dev.register_default("yard")
55
+ # simplecov:enable
48
56
  end
@@ -794,10 +794,25 @@ module Kettle
794
794
  cmd = "#{cmd} --version #{Shellwords.escape(@version_override)}" if @version_override
795
795
  cmd = "#{cmd} --yes" if @yes
796
796
  cmd = "#{cmd} --events=changelog" if @event_stream
797
- run_cmd!(cmd)
797
+ with_project_changelog_coverage_policy { run_cmd!(cmd) }
798
798
  @changelog_generated_coverage = true
799
799
  end
800
800
 
801
+ # Monorepo subprojects commonly disable their local hard coverage gate
802
+ # because their narrow test suite cannot satisfy the aggregate root
803
+ # thresholds. Preserve an explicit changelog policy, otherwise derive
804
+ # the changelog coverage policy from the project's coverage setting.
805
+ def with_project_changelog_coverage_policy
806
+ original = ENV["K_CHANGELOG_COVERAGE_HARD"]
807
+ changed = original.nil? && ENV["K_SOUP_COV_MIN_HARD"].to_s.casecmp?("false")
808
+ return yield unless changed
809
+
810
+ ENV["K_CHANGELOG_COVERAGE_HARD"] = "false"
811
+ yield
812
+ ensure
813
+ ENV["K_CHANGELOG_COVERAGE_HARD"] = original if changed
814
+ end
815
+
801
816
  def release_default_task_command
802
817
  # `kettle-changelog` generates strict coverage by running `bundle exec kettle-test`.
803
818
  # When that happened during this same release invocation, the default task can skip
@@ -23,7 +23,7 @@ module Kettle
23
23
  def fetch(gem_name, version_hint: nil, refresh: false)
24
24
  name = gem_name.to_s
25
25
  cached = cached_versions(name)
26
- cache_bust = refresh || env_refresh? || fresh_release_marker?(name, version_hint)
26
+ cache_bust = refresh || env_refresh? || fresh_release_marker?(name, version_hint) || cached_behind_version?(cached, version_hint)
27
27
  return cached if cached && !cache_bust
28
28
 
29
29
  uri = versions_uri(gem_name, cache_bust: cache_bust)
@@ -104,6 +104,22 @@ module Kettle
104
104
  false
105
105
  end
106
106
 
107
+ def cached_behind_version?(cached, version_hint)
108
+ return false unless cached && version_hint
109
+
110
+ cached_versions = cached.each_with_object([]) do |entry, versions|
111
+ value = entry["number"] if entry.is_a?(Hash)
112
+ next if value.to_s.empty? || value.to_s =~ /[a-zA-Z]/
113
+
114
+ versions << Gem::Version.new(value)
115
+ end
116
+ return false if cached_versions.empty?
117
+
118
+ cached_versions.max < Gem::Version.new(version_hint)
119
+ rescue ArgumentError
120
+ false
121
+ end
122
+
107
123
  def read_marker(path)
108
124
  return {} unless File.file?(path)
109
125
 
@@ -5,7 +5,7 @@ module Kettle
5
5
  # Version namespace for this gem.
6
6
  module Version
7
7
  # Current gem version.
8
- VERSION = "2.5.19"
8
+ VERSION = "2.5.21"
9
9
  end
10
10
  # Current gem version exposed at the traditional constant location.
11
11
  VERSION = Version::VERSION # Traditional Constant Location
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.5.19
4
+ version: 2.5.21
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter H. Boling
@@ -402,10 +402,10 @@ licenses:
402
402
  - AGPL-3.0-only
403
403
  metadata:
404
404
  homepage_uri: https://kettle-dev.galtzo.com
405
- source_code_uri: https://github.com/kettle-dev/kettle-dev/tree/v2.5.19
406
- changelog_uri: https://github.com/kettle-dev/kettle-dev/blob/v2.5.19/CHANGELOG.md
405
+ source_code_uri: https://github.com/kettle-dev/kettle-dev/tree/v2.5.21
406
+ changelog_uri: https://github.com/kettle-dev/kettle-dev/blob/v2.5.21/CHANGELOG.md
407
407
  bug_tracker_uri: https://github.com/kettle-dev/kettle-dev/issues
408
- documentation_uri: https://www.rubydoc.info/gems/kettle-dev/2.5.19
408
+ documentation_uri: https://www.rubydoc.info/gems/kettle-dev/2.5.21
409
409
  funding_uri: https://github.com/sponsors/pboling
410
410
  wiki_uri: https://github.com/kettle-dev/kettle-dev/wiki
411
411
  news_uri: https://www.railsbling.com/tags/kettle-dev
metadata.gz.sig CHANGED
Binary file