kettle-dev 3.0.18 → 3.0.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: 4dc02c70ec8eb1cdf707e6cbef542a3117258006a83a9f6ac15261388c05b147
4
- data.tar.gz: 6c4a8431553b479404d1a3d4264e633fd54e9154fbb305e7f10b80167da53220
3
+ metadata.gz: 20e87802965f21d08fce4a1bb8eaab16a950611e67268f55284610c9e7601d6a
4
+ data.tar.gz: 26d1ac30a1bba63404ec8463290e20effd4039393c179842e61cf98ed5e89760
5
5
  SHA512:
6
- metadata.gz: 0e400e4b0bcfe3019606b4954b91430818ff760f69497dbe5c18a2a9a9f2f82755a496a2773db82c830477eb4e7785344108cb93294224b70dc249c37dc10dae
7
- data.tar.gz: 8163c6e8ff99e586bc2085184968509ae28bbb6c547c0189a08c2a48780e6b8260598421a695a089a1e856dd1d82beff34d8122583f21e3762e808daac6f4114
6
+ metadata.gz: d6d0157c9bd6b22580c9c4304ed9ec0d2a87f55d8e8afe33cf4e81e14a3905f979e30397143047979bfed0c795b321acfaa9739988c9fb6f8546c1e45ceffa17
7
+ data.tar.gz: cf6a29d466ad157170224b8aca7cb9569e2de56711825487d18f8e68ef3ca5e5d546b215d2b00d34d9e9dbe49d49e2a326c37883b9eab66cc0835f97420732c0
checksums.yaml.gz.sig CHANGED
@@ -1,5 +1 @@
1
- /��i�|��,(۪[�r9�n�N-ƨs�$S�*x-�M��ssK⏭#f�x�����T�8
2
- i��$7�(^�a��YM�o
3
- ;�6���x����2ĕ��{-�mM��df��S���x% nSt���ݓ�%�=f�O5l�=�w\D�THw%�����
4
-  �k�$7�sЛϸ���wjʞu���8���,��4��T �G��5�m���L��ëV�4?�3.V���0��}ב��_�Y��rM�v]��<�%��%�§:q/��^�)����<��@̎�ڧ�Nټu���� ���� D�s��侊B���Mo������zĉ=$���ט��)F%@��g� j
5
- s}`Z{�J��
1
+ ,8����ۆ����n�tр���aV�8�^ �*¼zo�:t�`�m$'���c@
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
+ ## [3.0.20] - 2026-08-30
34
+
35
+ - TAG: [v3.0.20][3.0.20t]
36
+ - COVERAGE: 91.44% -- 5875/6425 lines in 47 files
37
+ - BRANCH COVERAGE: 76.07% -- 2248/2955 branches in 47 files
38
+ - 50.47% documented
39
+
40
+ ### Fixed
41
+
42
+ - Preserve configured monorepo member-path lockfiles during release while rejecting unapproved local paths.
43
+
44
+ ## [3.0.19] - 2026-08-30
45
+
46
+ - TAG: [v3.0.19][3.0.19t]
47
+ - COVERAGE: 91.50% -- 5855/6399 lines in 47 files
48
+ - BRANCH COVERAGE: 76.21% -- 2249/2951 branches in 47 files
49
+ - 50.97% documented
50
+
51
+ ### Fixed
52
+
53
+ - Run changelog coverage with the disposable release lockfile so host platform reconciliation cannot dirty a release.
54
+
55
+ - Normalize release lockfiles before changelog coverage runs.
56
+
57
+ - Isolate changelog coverage with the selected coverage Gemfile lockfile during release.
58
+
33
59
  ## [3.0.18] - 2026-08-30
34
60
 
35
61
  - TAG: [v3.0.18][3.0.18t]
@@ -3651,7 +3677,11 @@ Please file a bug if you notice a violation of semantic versioning.
3651
3677
  - Selecting will run the selected workflow via `act`
3652
3678
  - This may move to its own gem in the future.
3653
3679
 
3654
- [Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.18...HEAD
3680
+ [Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.20...HEAD
3681
+ [3.0.20]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.19...v3.0.20
3682
+ [3.0.20t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v3.0.20
3683
+ [3.0.19]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.18...v3.0.19
3684
+ [3.0.19t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v3.0.19
3655
3685
  [3.0.18]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.17...v3.0.18
3656
3686
  [3.0.18t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v3.0.18
3657
3687
  [3.0.17]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.16...v3.0.17
data/README.md CHANGED
@@ -508,7 +508,7 @@ What it does:
508
508
  | Role | Lockfile | Used by |
509
509
  | --- | --- | --- |
510
510
  | Family runner | The family/orchestrator bundle | May resolve local sibling gems to run `kettle-family`; it never becomes the target project's lockfile. |
511
- | Canonical release state | Tracked `Gemfile.lock` and, when present, `Appraisal.root.gemfile.lock` | Step 1 Bundler update, steps 3-6 setup/checks/appraisals/docs/prep commit, and step 16 checksums. These commands disable local `*_DEV`/`*_LOCAL` switches. |
511
+ | Canonical release state | Tracked `Gemfile.lock` and, when present, `Appraisal.root.gemfile.lock` | Step 1 Bundler update, steps 3-6 setup/checks/appraisals/docs/prep commit, and step 16 checksums. These commands disable local `*_DEV`/`*_LOCAL` switches, except a narrow member-root policy supplied by `kettle-family` for an explicit monorepo. |
512
512
  | Release task state | `tmp/kettle-release/lockfiles/Gemfile-<pid>.lock` | Steps 14-15 build and publish only. It begins as a copy of canonical `Gemfile.lock` and is deleted at process exit. |
513
513
  | Tool state | A tool-owned Gemfile such as `kettle-changelog/gemfiles/release.gemfile` | The tool's own dependencies. The command still disables local dependency switches before it can trigger target-project work. |
514
514
  | Git-hook state | Canonical release environment | Every release-created commit and amend. Hooks remain enabled, but cannot inherit the family runner's local sibling graph. |
@@ -518,6 +518,14 @@ What it does:
518
518
  a release phase. `ReleaseCLI#release_child_command` owns canonical/tool
519
519
  command construction; `ReleaseCLI#release_project_command` selects the
520
520
  disposable task lock only for build and publish.
521
+
522
+ The monorepo exception is intentionally narrow. `kettle-family` derives
523
+ it only from `family.mode: monorepo` and its configured members root, then
524
+ passes the allowed root and activating environment name to
525
+ `kettle-release`. A sibling Kettle Dev checkout is not covered: normal
526
+ releases must use the released `kettle-family`, `kettle-changelog`, and
527
+ other Kettle dependencies. Local Kettle Dev integration is an explicit
528
+ development opt-in, never a canonical release-lock default.
521
529
  - Tips:
522
530
  - The commit message helper `exe/kettle-commit-msg` prefers project-local `.git-hooks` (then falls back to `~/.git-hooks`).
523
531
  - The goalie file `commit-subjects-goalie.txt` controls when a footer is appended; customize `footer-template.erb.txt` as you like.
@@ -1048,7 +1056,7 @@ Thanks for RTFM. ☺️
1048
1056
  [📌gitmoji]: https://gitmoji.dev
1049
1057
  [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
1050
1058
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
1051
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-6.390-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1059
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-6.425-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1052
1060
  [🔐security]: https://github.com/kettle-dev/kettle-dev/blob/main/SECURITY.md
1053
1061
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
1054
1062
  [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
@@ -21,6 +21,8 @@ module Kettle
21
21
  "GALTZO_FLOSS_DEV" => "false",
22
22
  "UR_BRAIN_DEV" => "false"
23
23
  }.freeze
24
+ ALLOWED_LOCAL_PATH_ROOTS_ENV = "KETTLE_RELEASE_ALLOWED_LOCAL_PATH_ROOTS"
25
+ ALLOWED_LOCAL_PATH_ENVS_ENV = "KETTLE_RELEASE_ALLOWED_LOCAL_PATH_ENVS"
24
26
  RELEASE_LOCKFILES_TARGET = "release-lockfiles"
25
27
  SUPPORTED_TARGETS = ["Gemfile.lock", "Appraisal.root.gemfile.lock", RELEASE_LOCKFILES_TARGET].freeze
26
28
  UNBUNDLED_ENV_KEYS = (BundlerEnvGuard::RESET_ENV_KEYS + %w[
@@ -110,12 +112,18 @@ module Kettle
110
112
  @root = root
111
113
  @command_runner = command_runner
112
114
  @release_platforms = {}
115
+ @allowed_local_path_roots = configured_allowed_local_path_roots
116
+ @allowed_local_path_env_names = configured_allowed_local_path_env_names
113
117
  end
114
118
 
115
119
  def reset(target, skip_changelog_dependency: false)
116
120
  BundlerEnvGuard.warn_unexpected_env!
117
121
  paths = lockfile_paths_for(target)
118
- force_full_update = release_lockfiles_target?(target)
122
+ # A monorepo lockfile may deliberately use paths rooted in the
123
+ # repository's members directory. Keep that valid development graph;
124
+ # only rebuild when an unapproved path or other diagnostic remains.
125
+ force_full_update = release_lockfiles_target?(target) &&
126
+ (allowed_local_path_roots.empty? || paths.any? { |path| normalization_needed?(path) })
119
127
  platforms = release_platforms_for(paths) if force_full_update
120
128
  uninstall_unreleased_local_gems(paths) if force_full_update
121
129
  paths.each do |path|
@@ -251,7 +259,7 @@ module Kettle
251
259
 
252
260
  def diagnostics(path)
253
261
  diagnostics = []
254
- local_path_remote_lines(path).each do |line_number|
262
+ disallowed_local_path_remote_lines(path).each do |line_number|
255
263
  diagnostics << "#{display_path(path)} has local path remote at line #{line_number}"
256
264
  end
257
265
  empty_registry_checksums(path).each do |name, version, line_number|
@@ -308,13 +316,16 @@ module Kettle
308
316
  end
309
317
 
310
318
  def normalization_env
311
- DEFAULT_DISABLED_ENV.merge(dynamic_local_path_env)
319
+ DEFAULT_DISABLED_ENV
320
+ .reject { |name, _| allowed_local_path_env_names.include?(name) }
321
+ .merge(dynamic_local_path_env)
312
322
  end
313
323
 
314
324
  def dynamic_local_path_env
315
325
  ENV.each_with_object({}) do |(key, value), env|
316
326
  next unless key.end_with?("_DEV", "_LOCAL")
317
327
  next unless local_path_env_value?(value)
328
+ next if allowed_local_path_env_names.include?(key)
318
329
 
319
330
  env[key] = "false"
320
331
  end
@@ -329,13 +340,49 @@ module Kettle
329
340
  end
330
341
 
331
342
  def has_local_path_remote?(path)
332
- !local_path_remote_lines(path).empty?
343
+ !disallowed_local_path_remote_lines(path).empty?
333
344
  end
334
345
 
335
346
  def local_path_remote_lines(path)
336
347
  self.class.local_path_remote_lines_from_source(File.read(path))
337
348
  end
338
349
 
350
+ attr_reader :allowed_local_path_roots, :allowed_local_path_env_names
351
+
352
+ def disallowed_local_path_remote_lines(path)
353
+ local_path_remote_lines(path).reject do |line_number|
354
+ allowed_local_path?(local_path_remote_at(path, line_number))
355
+ end
356
+ end
357
+
358
+ def configured_allowed_local_path_roots
359
+ ENV.fetch(ALLOWED_LOCAL_PATH_ROOTS_ENV, "").split(File::PATH_SEPARATOR).filter_map do |value|
360
+ next if value.strip.empty?
361
+
362
+ canonical_path(value)
363
+ end.uniq
364
+ end
365
+
366
+ def configured_allowed_local_path_env_names
367
+ ENV.fetch(ALLOWED_LOCAL_PATH_ENVS_ENV, "").split(",").map(&:strip).reject(&:empty?).uniq
368
+ end
369
+
370
+ def local_path_remote_at(path, line_number)
371
+ File.readlines(path)[line_number - 1].to_s.split("remote:", 2).last.to_s.strip
372
+ end
373
+
374
+ def allowed_local_path?(path)
375
+ remote = canonical_path(path)
376
+ allowed_local_path_roots.any? { |root| remote == root || remote.start_with?("#{root}/") }
377
+ end
378
+
379
+ def canonical_path(path)
380
+ expanded = File.expand_path(path, root)
381
+ File.realpath(expanded)
382
+ rescue Errno::ENOENT
383
+ expanded
384
+ end
385
+
339
386
  def empty_registry_checksums(path)
340
387
  non_registry_gems = non_registry_source_gems(path) | path_dependency_gems(path)
341
388
  in_checksums = false
@@ -218,7 +218,7 @@ module Kettle
218
218
  @started_at = nil
219
219
  @finished_report = nil
220
220
  @changelog_generated_coverage = false
221
- @release_task_lockfile_path = nil
221
+ @release_task_lockfile_paths = {}
222
222
  end
223
223
 
224
224
  def run
@@ -251,6 +251,11 @@ module Kettle
251
251
  attr_reader :finished_report
252
252
 
253
253
  def run_with_release_environment
254
+ # Changelog generation at step 0 runs the target project's test bundle
255
+ # to collect coverage. Normalize its canonical release lockfile before
256
+ # that subprocess starts; otherwise a local development PATH lock can
257
+ # force Bundler to resolve an invalid mixed local/released graph.
258
+ prepare_release_lockfiles_for_release_tasks! if release_lockfile_preflight_needed?
254
259
  run_pre_release_checks! if run_step?(0)
255
260
 
256
261
  # 1. Ensure Bundler version and record its current release in the
@@ -357,7 +362,6 @@ module Kettle
357
362
  end
358
363
 
359
364
  prepare_rubocop_lts_local_branch! if rubocop_lts_release_preflight_needed?
360
- prepare_release_lockfiles_for_release_tasks! if release_lockfile_preflight_needed?
361
365
 
362
366
  # 3. bin/setup
363
367
  run_cmd!(release_setup_command) if run_step?(3)
@@ -602,7 +606,10 @@ module Kettle
602
606
  end
603
607
 
604
608
  def release_lockfile_preflight_needed?
605
- (3..5).any? { |step| run_step?(step) }
609
+ # Step 0 invokes kettle-changelog, which runs `bundle exec kettle-test`
610
+ # for fresh coverage. It therefore needs the same registry-backed
611
+ # release lockfile as later setup, task, and documentation steps.
612
+ run_step?(0) || (3..5).any? { |step| run_step?(step) }
606
613
  end
607
614
 
608
615
  def prepare_rubocop_lts_local_branch!
@@ -927,6 +934,14 @@ module Kettle
927
934
  return release_child_command("bundle exec kettle-changelog") unless gemfile
928
935
 
929
936
  environment = {"BUNDLE_GEMFILE" => gemfile}
937
+ coverage_gemfile = changelog_coverage_gemfile
938
+ environment["K_CHANGELOG_COVERAGE_GEMFILE"] = coverage_gemfile if coverage_gemfile
939
+ # Changelog coverage runs the target project's bundle. Give that nested
940
+ # invocation a disposable lockfile for its selected coverage Gemfile so
941
+ # Bundler's host-platform reconciliation cannot dirty the prep commit.
942
+ if (lockfile = release_task_lockfile_path(gemfile: coverage_gemfile || File.join(@root, "Gemfile")))
943
+ environment["KETTLE_CHANGELOG_COVERAGE_LOCKFILE"] = lockfile
944
+ end
930
945
  if (local_root = release_changelog_local_root)
931
946
  environment["KETTLE_CHANGELOG_DEV_ROOT"] = local_root
932
947
  end
@@ -960,6 +975,18 @@ module Kettle
960
975
  File.expand_path(local_root)
961
976
  end
962
977
 
978
+ # A generated coverage appraisal is intentionally smaller than the root
979
+ # development bundle and therefore avoids release-only tool dependency
980
+ # conflicts. Let kettle-changelog retain the root-Gemfile fallback when
981
+ # a project has not generated this optional bundle.
982
+ def changelog_coverage_gemfile
983
+ configured = ENV["K_CHANGELOG_COVERAGE_GEMFILE"].to_s.strip
984
+ return File.expand_path(configured, @root) unless configured.empty?
985
+
986
+ generated = File.join(@root, "gemfiles", "coverage.gemfile")
987
+ generated if File.file?(generated)
988
+ end
989
+
963
990
  # Monorepo subprojects commonly disable their local hard coverage gate
964
991
  # because their narrow test suite cannot satisfy the aggregate root
965
992
  # thresholds. Preserve an explicit changelog policy, otherwise derive
@@ -1036,26 +1063,26 @@ module Kettle
1036
1063
  # bundler/gem_tasks' release:guard_clean check. Keep that reconciliation
1037
1064
  # in a disposable lockfile so the committed, normalized lockfile remains
1038
1065
  # unchanged throughout build and publication.
1039
- def release_task_lockfile_path
1040
- return @release_task_lockfile_path if @release_task_lockfile_path
1066
+ def release_task_lockfile_path(gemfile: File.join(@root, "Gemfile"))
1067
+ return @release_task_lockfile_paths[gemfile] if @release_task_lockfile_paths.key?(gemfile)
1041
1068
 
1042
- source = File.join(@root, "Gemfile.lock")
1069
+ source = "#{gemfile}.lock"
1043
1070
  return unless File.file?(source)
1044
1071
 
1045
1072
  directory = File.join(@root, "tmp", "kettle-release", "lockfiles")
1046
1073
  FileUtils.mkdir_p(directory)
1047
- @release_task_lockfile_path = File.join(directory, "Gemfile-#{$$}.lock")
1048
- FileUtils.cp(source, @release_task_lockfile_path)
1049
- @release_task_lockfile_path
1074
+ path = File.join(directory, "#{File.basename(gemfile)}-#{$$}.lock")
1075
+ FileUtils.cp(source, path)
1076
+ @release_task_lockfile_paths[gemfile] = path
1050
1077
  rescue SystemCallError => error
1051
1078
  abort("Unable to isolate the release task lockfile: #{error.message}")
1052
1079
  end
1053
1080
 
1054
1081
  def cleanup_release_task_lockfile!
1055
- return unless @release_task_lockfile_path
1082
+ return if @release_task_lockfile_paths.empty?
1056
1083
 
1057
- FileUtils.rm_f(@release_task_lockfile_path)
1058
- @release_task_lockfile_path = nil
1084
+ @release_task_lockfile_paths.each_value { |path| FileUtils.rm_f(path) }
1085
+ @release_task_lockfile_paths.clear
1059
1086
  end
1060
1087
 
1061
1088
  def confirm_yes!(message, prompt, abort_message)
@@ -5,7 +5,7 @@ module Kettle
5
5
  # Version namespace for this gem.
6
6
  module Version
7
7
  # Current gem version.
8
- VERSION = "3.0.18"
8
+ VERSION = "3.0.20"
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: 3.0.18
4
+ version: 3.0.20
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter H. Boling
@@ -400,10 +400,10 @@ licenses:
400
400
  - AGPL-3.0-only
401
401
  metadata:
402
402
  homepage_uri: https://kettle-dev.galtzo.com
403
- source_code_uri: https://github.com/kettle-dev/kettle-dev/tree/v3.0.18
404
- changelog_uri: https://github.com/kettle-dev/kettle-dev/blob/v3.0.18/CHANGELOG.md
403
+ source_code_uri: https://github.com/kettle-dev/kettle-dev/tree/v3.0.20
404
+ changelog_uri: https://github.com/kettle-dev/kettle-dev/blob/v3.0.20/CHANGELOG.md
405
405
  bug_tracker_uri: https://github.com/kettle-dev/kettle-dev/issues
406
- documentation_uri: https://www.rubydoc.info/gems/kettle-dev/3.0.18
406
+ documentation_uri: https://www.rubydoc.info/gems/kettle-dev/3.0.20
407
407
  funding_uri: https://github.com/sponsors/pboling
408
408
  wiki_uri: https://github.com/kettle-dev/kettle-dev/wiki
409
409
  news_uri: https://www.railsbling.com/tags/kettle-dev
metadata.gz.sig CHANGED
Binary file