kettle-jem 7.1.7 → 7.1.10

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: 159bc6117067ed363b64efafaf0e60b30512e557ddba9ed2d726196955131c5b
4
- data.tar.gz: 58691325c312611550fc42582e885e253f7da2cd1aa0d23ab406e02f81b42896
3
+ metadata.gz: cc954a9b2e13ecec8a5dbf0858c76b7a7157f92fabd6f07092024690ab163048
4
+ data.tar.gz: '0628e48c05357df4f752ef7e252cb3992d380ab578faaeee44801d7e818ed39f'
5
5
  SHA512:
6
- metadata.gz: 02d3853435da59528788762e0895be93660e5b3392560bdd5161ac7fd258edd0de3e0a10a209d9236410c1b890d6f1de285b39189abba8ede8febe7acc89484a
7
- data.tar.gz: 44ffeb8997d517b97e814e62ec25094df6823f15d1732f39edca4bc12a5a53721f7eca3fce72f5c9a21a7ea3e44ddc164700ffd9a4b48cb40313012be2bc5a3f
6
+ metadata.gz: 1c549dd026691dbfc28854df99784f1b3c8904237d19f23eaab450de64983c5f9116102811e385f997a661c443e4efe01b6832613dbef6da5c1d9b30eeaad451
7
+ data.tar.gz: 54991a0795b8d7da63318264a5dcefec11cbe78e0ba151a9a53ab56ff8c39b4b6375070b80007d0c446b59c4bc7ad2ee8756c63c25a209f3cf0edfd79b6e900e
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -30,6 +30,78 @@ Please file a bug if you notice a violation of semantic versioning.
30
30
 
31
31
  ### Security
32
32
 
33
+ ## [7.1.10] - 2026-08-29
34
+
35
+ - TAG: [v7.1.10][7.1.10t]
36
+ - COVERAGE: 93.56% -- 10937/11690 lines in 16 files
37
+ - BRANCH COVERAGE: 76.95% -- 4658/6053 branches in 16 files
38
+ - 17.92% documented
39
+
40
+ ### Changed
41
+
42
+ - Record template-run changelog updates before the bootstrap commit so generated changes and their maintenance summary are committed together.
43
+
44
+ - [kc] kettle-jem-deps-floor: Update kettle-jem template dependency floors:
45
+ - kettle-changelog (>= 1.0.3 -> >= 1.0.5)
46
+ - kettle-dev (>= 3.0.13 -> >= 3.0.16)
47
+ - kettle-drift (>= 1.0.12 -> >= 1.0.13)
48
+ - kettle-family (>= 1.2.62 -> >= 1.2.63)
49
+ - kettle-jem (>= 7.1.7 -> >= 7.1.8)
50
+ - kettle-soup-cover (>= 3.0.9 -> >= 3.0.10)
51
+ - kettle-test (>= 2.0.20 -> >= 2.0.21)
52
+ - nomono (>= 1.1.4 -> >= 1.1.5)
53
+
54
+ - [kc] kettle-jem-workflow-pins: Update pinned GitHub Actions in kettle-jem templates:
55
+ - apache/skywalking-eyes/dependency v0.8.0 (61275cc80d0798a405cb070f7d3a8aaf7cf2c2c1) -> v0.9.0 (a196742f472feaffafea537ce5a2a4c3c53a8de4)
56
+ - github/codeql-action/analyze v4.37.8 (db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28) -> v4.37.9 (cdf488f595d80d6e07e03d4674febd5ab45fa938)
57
+ - github/codeql-action/autobuild v4.37.8 (db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28) -> v4.37.9 (cdf488f595d80d6e07e03d4674febd5ab45fa938)
58
+ - github/codeql-action/init v4.37.8 (db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28) -> v4.37.9 (cdf488f595d80d6e07e03d4674febd5ab45fa938)
59
+
60
+ - [kc] kettle-jem/template: updated 1194 project files:
61
+ - code and tests (60)
62
+ - configuration (36)
63
+ - dependencies (441)
64
+ - documentation (27)
65
+ - other (369)
66
+ - workflows (261)
67
+
68
+ - [kc] kettle-jem-deps-floor: Update kettle-jem template dependency floors:
69
+ - kettle-dev (>= 3.0.16 -> >= 3.0.17)
70
+ - kettle-family (>= 1.2.63 -> >= 1.2.64)
71
+
72
+ - [kc] kettle-jem/prepare: updated 13 project files:
73
+ - dependencies (13)
74
+
75
+ - [kc] kettle-jem/template: updated 3 project files:
76
+ - code and tests (1)
77
+ - dependencies (1)
78
+ - other (1)
79
+
80
+ ### Fixed
81
+
82
+ - Keep external superclass expressions out of generated standalone version files.
83
+
84
+ - Skip template changelog recording for partial destination projects that do not contain a changelog.
85
+
86
+ ## [7.1.8] - 2026-08-26
87
+
88
+ - TAG: [v7.1.8][7.1.8t]
89
+ - COVERAGE: 93.68% -- 10873/11606 lines in 16 files
90
+ - BRANCH COVERAGE: 77.22% -- 4640/6009 branches in 16 files
91
+ - 17.93% documented
92
+
93
+ ### Added
94
+
95
+ - Gemspec author metadata now expands existing authors with Git-derived copyright holders and consolidates configured author aliases, while applying the documented default machine-account filter.
96
+
97
+ ### Changed
98
+
99
+ - Copyright filtering now excludes bot-marker identities and the packaged template seeds shared author aliases and machine-account defaults.
100
+
101
+ - [kc] kettle-jem-deps-floor: Update kettle-jem template dependency floors:
102
+ - kettle-family (>= 1.2.61 -> >= 1.2.62)
103
+ - kettle-jem (>= 7.1.6 -> >= 7.1.7)
104
+
33
105
  ## [7.1.7] - 2026-08-26
34
106
 
35
107
  - TAG: [v7.1.7][7.1.7t]
@@ -1602,7 +1674,11 @@ Please file a bug if you notice a violation of semantic versioning.
1602
1674
  - Released kettle-jem as part of the initial StructuredMerge Ruby 7.0.0 gem set.
1603
1675
  - Included packaged templates and parser-backed merge support for Ruby gem templating.
1604
1676
 
1605
- [Unreleased]: https://github.com/structuredmerge/structuredmerge-ruby/compare/v7.1.7...HEAD
1677
+ [Unreleased]: https://github.com/structuredmerge/structuredmerge-ruby/compare/v7.1.10...HEAD
1678
+ [7.1.10]: https://github.com/structuredmerge/structuredmerge-ruby/compare/v7.1.8...v7.1.10
1679
+ [7.1.10t]: https://github.com/structuredmerge/structuredmerge-ruby/releases/tag/v7.1.10
1680
+ [7.1.8]: https://github.com/structuredmerge/structuredmerge-ruby/compare/v7.1.7...v7.1.8
1681
+ [7.1.8t]: https://github.com/structuredmerge/structuredmerge-ruby/releases/tag/v7.1.8
1606
1682
  [7.1.7]: https://github.com/structuredmerge/structuredmerge-ruby/compare/v7.1.6...v7.1.7
1607
1683
  [7.1.7t]: https://github.com/structuredmerge/structuredmerge-ruby/releases/tag/v7.1.7
1608
1684
  [7.1.6]: https://github.com/structuredmerge/structuredmerge-ruby/compare/v7.1.5...v7.1.6
data/README.md CHANGED
@@ -202,6 +202,15 @@ readme:
202
202
  machine_users:
203
203
  - dependabot
204
204
 
205
+ # Map alternate Git author names or email addresses to one canonical name.
206
+ # The canonical names are used in generated LICENSE.md and gemspec metadata.
207
+ author_aliases:
208
+ pboling: "Peter H. Boling"
209
+ "|7eter l-|. l3oling": "Peter H. Boling"
210
+ "Peter Boling": "Peter H. Boling"
211
+ galtzo: "Peter H. Boling"
212
+ Aboling0: "Annibelle Boling"
213
+
205
214
  # Maximum allowed divergence (%) for selftest CI check
206
215
  min_divergence_threshold: 5 # ENV override: KJ_MIN_DIVERGENCE_THRESHOLD
207
216
 
@@ -290,12 +299,25 @@ Common tokens:
290
299
  | `{KJ\|GEM_NAME}` | Gem name from gemspec |
291
300
  | `{KJ\|NAMESPACE}` | Ruby module namespace |
292
301
  | `{KJ\|AUTHOR:NAME}` | Author full name |
302
+ | `{KJ\|AUTHOR:NAMES}` | Existing gemspec authors plus Git-derived copyright holders |
293
303
  | `{KJ\|AUTHOR:EMAIL}` | Author email |
294
304
  | `{KJ\|GH:USER}` | GitHub username |
295
305
  | `{KJ\|PROJECT_EMOJI}` | Project emoji from config |
296
306
  | `{KJ\|MIN_RUBY}` | Minimum Ruby version |
297
307
  | `{KJ\|FREEZE_TOKEN}` | Freeze marker name |
298
308
 
309
+ `machine_users` excludes configured Git author names or email addresses from
310
+ Git-derived copyright output. Any identity containing `[bot]` is filtered
311
+ automatically. The built-in machine-account set includes `autobolt`,
312
+ `StepSecurity Bot`, `dependabot[bot]`, and `depfu[bot]`; configured entries
313
+ extend this set rather than replacing it.
314
+
315
+ `author_aliases` consolidates alternate Git author names or email addresses to
316
+ canonical display names. The mapping is case-insensitive and applies to Git
317
+ copyright facts and existing gemspec author names; it does not rewrite Git
318
+ history. `AUTHOR:NAMES` preserves existing gemspec authors and appends any
319
+ copyright holders not already present.
320
+
299
321
  ### Freeze Blocks
300
322
 
301
323
  Protect sections in any file from template overwrites:
@@ -772,7 +794,7 @@ Thanks for RTFM. ☺️
772
794
  [📌gitmoji]: https://gitmoji.dev
773
795
  [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
774
796
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
775
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-11.554-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
797
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-11.690-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
776
798
  [🔐security]: https://github.com/structuredmerge/structuredmerge-ruby/blob/main/SECURITY.md
777
799
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
778
800
  [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
@@ -234,6 +234,8 @@ module Kettle
234
234
  end
235
235
  return result unless %w[setup prepare apply template install].include?(command)
236
236
 
237
+ return result if result.is_a?(Hash) && result.key?(:changelog)
238
+
237
239
  Kettle::Jem::MaintenanceChangelog.record_template_run(
238
240
  project_root: project_root,
239
241
  report: result,
@@ -95,6 +95,10 @@ module Kettle
95
95
  return report.merge(changelog: {status: "skipped", reason: "no_template_changes", changed_files: []})
96
96
  end
97
97
 
98
+ unless File.file?(File.join(project_root, "CHANGELOG.md"))
99
+ return report.merge(changelog: {status: "skipped", reason: "missing_changelog"})
100
+ end
101
+
98
102
  key = TEMPLATE_CHANGELOG_KEYS.fetch(label, "kettle-jem/template")
99
103
  entry = ->(matches) { template_run_entry(changed_files, matches) }
100
104
  result = upsert_unreleased_entry(project_root: project_root, section: "Changed", key: key, entry: entry)
@@ -8,6 +8,7 @@ require "toml-rb"
8
8
  require "uri"
9
9
  require "yaml"
10
10
  require "kettle/rb/compat_matrix"
11
+ require "kettle/jem/maintenance_changelog"
11
12
 
12
13
  module Kettle
13
14
  module Jem
@@ -48,7 +49,6 @@ module Kettle
48
49
  install_steps << rubocop_gradual_autocorrect_step(project_root, env: setup_env, run_options: effective_run_options)
49
50
  install_steps << normalize_lockfile_step(project_root, env: setup_env, run_options: effective_run_options)
50
51
  install_steps << bundled_handoff_step(project_root: project_root, env: env, run_options: effective_run_options)
51
- install_steps << bootstrap_commit_step(project_root, run_options: effective_run_options)
52
52
  install_steps = execute_orchestration_steps(install_steps, project_root: project_root, env: setup_env, run_options: effective_run_options, command_runner: command_runner)
53
53
 
54
54
  final_report = report.merge(
@@ -62,6 +62,26 @@ module Kettle
62
62
  message: "kettle:jem:install applied templates, completed local post-template checks, and executed available orchestration steps."
63
63
  }]
64
64
  )
65
+ final_report = Kettle::Jem::MaintenanceChangelog.record_template_run(
66
+ project_root: project_root,
67
+ report: final_report,
68
+ run_options: effective_run_options
69
+ )
70
+ bootstrap_commit = bootstrap_commit_step(project_root, run_options: effective_run_options)
71
+ install_steps.concat(
72
+ execute_orchestration_steps(
73
+ [bootstrap_commit],
74
+ project_root: project_root,
75
+ env: setup_env,
76
+ run_options: effective_run_options,
77
+ command_runner: command_runner
78
+ )
79
+ )
80
+ final_report = final_report.merge(
81
+ install_steps: install_steps,
82
+ install_phase_reports: install_phase_reports(install_steps),
83
+ install_summary: install_step_summary(install_steps)
84
+ )
65
85
  Kettle::Jem.emit_summary_event(Kettle::Jem.event_stream_from_options(effective_run_options), final_report)
66
86
  final_report
67
87
  end
@@ -33,7 +33,7 @@ jobs:
33
33
  persist-credentials: false
34
34
 
35
35
  - name: Check Dependencies' License
36
- uses: apache/skywalking-eyes/dependency@61275cc80d0798a405cb070f7d3a8aaf7cf2c2c1 # v0.8.0
36
+ uses: apache/skywalking-eyes/dependency@a196742f472feaffafea537ce5a2a4c3c53a8de4 # v0.9.0
37
37
  with:
38
38
  config: .licenserc.yaml
39
39
  mode: "{KJ|LICENSE_EYE:MODE}"
@@ -63,7 +63,8 @@
63
63
  #
64
64
  # Safe automatic derivations currently implemented:
65
65
  # AUTHOR:NAME <- first author from the gemspec
66
- # AUTHOR:NAMES <- all authors from the gemspec, or copyright holders if no gemspec authors exist
66
+ # AUTHOR:NAMES <- existing gemspec authors plus Git-derived copyright holders
67
+ # (after author_aliases consolidation)
67
68
  # AUTHOR:EMAIL <- first email from the gemspec
68
69
  # AUTHOR:DOMAIN <- domain part of AUTHOR:EMAIL
69
70
  # AUTHOR:GIVEN_NAMES <- AUTHOR:NAME minus the last word
@@ -71,6 +72,19 @@
71
72
  #
72
73
  # Everything else should be set explicitly here or via ENV.
73
74
 
75
+ # Author identity aliases used when rendering copyright notices and gemspec
76
+ # author metadata. Keys are matched case-insensitively against Git commit
77
+ # author names, Git commit author emails, and existing gemspec author names.
78
+ # Values are the canonical display names written to generated files. This is
79
+ # useful when one person has committed under multiple names or email addresses.
80
+ # These aliases do not rewrite Git history.
81
+ author_aliases:
82
+ pboling: "Peter H. Boling"
83
+ "|7eter l-|. l3oling": "Peter H. Boling"
84
+ "Peter Boling": "Peter H. Boling"
85
+ galtzo: "Peter H. Boling"
86
+ Aboling0: "Annibelle Boling"
87
+
74
88
  # Direct dependency ownership decisions.
75
89
  # On first templating, kettle-jem discovers dependencies declared directly by
76
90
  # Gemfile/gemspec and also by modular Gemfiles, and writes them here for review.
@@ -360,16 +374,20 @@ license_eye:
360
374
  # Machine / automation accounts to exclude from generated copyright output.
361
375
  #
362
376
  # When kettle-jem collects copyright information via `git blame`, it filters
363
- # out known GitHub/GitLab bot accounts automatically. Use this list to also
364
- # exclude internal automation accounts that are not bots in the git sense
365
- # (i.e. they do not follow the "[bot]" naming convention).
377
+ # out identities containing "[bot]" automatically. Use this list to also
378
+ # exclude internal automation accounts that do not use that naming convention.
366
379
  #
367
380
  # Each entry is matched case-insensitively against the commit author name AND
368
- # the commit author email, so you can list either form.
381
+ # the commit author email, so you can list either form. Project entries extend
382
+ # the built-in defaults below; they do not remove those defaults.
369
383
  #
370
- # Default (when key is absent or empty): ["autobolt"]
384
+ # Built-in defaults always include: ["autobolt", "StepSecurity Bot",
385
+ # "dependabot[bot]", "depfu[bot]"]
371
386
  machine_users:
372
387
  - autobolt
388
+ - StepSecurity Bot
389
+ - dependabot[bot]
390
+ - depfu[bot]
373
391
 
374
392
  # Self-test / templating CI threshold.
375
393
  # Set to a number from 0 to 100 to fail `rake kettle:jem:selftest` once
@@ -468,7 +486,7 @@ tokens:
468
486
  sh_user: "galtzo" # SourceHut username only, no leading ~, no URL. Used as https://sr.ht/~<value>/. ENV: KJ_SH_USER
469
487
 
470
488
  author:
471
- name: "Peter H. Boling" # Full display name. Example: Ada Lovelace. ENV: KJ_AUTHOR_NAME. Auto-seeded from gemspec authors.first; generated gemspec authors preserve the full existing authors array via AUTHOR:NAMES.
489
+ name: "Peter H. Boling" # Full display name. Example: Ada Lovelace. ENV: KJ_AUTHOR_NAME. Auto-seeded from gemspec authors.first; AUTHOR:NAMES preserves existing gemspec authors and appends Git-derived copyright holders.
472
490
  given_names: "Peter H." # Given/personal names only. Example: Ada. ENV: KJ_AUTHOR_GIVEN_NAMES. Auto-seeded when AUTHOR:NAME can be split
473
491
  family_names: "Boling" # Family/surname only. Example: Lovelace. ENV: KJ_AUTHOR_FAMILY_NAMES. Auto-seeded when AUTHOR:NAME can be split
474
492
  email: "floss@galtzo.com" # Primary public email address. Example: floss@galtzo.com. ENV: KJ_AUTHOR_EMAIL. Auto-seeded from gemspec email.first
@@ -118,7 +118,7 @@ Gem::Specification.new do |spec|
118
118
  # and preferably a modular one (see gemfiles/modular/*.gemfile).
119
119
 
120
120
  # Dev, Test, & Release Tasks
121
- spec.add_development_dependency("kettle-dev", "~> 3.0", ">= 3.0.13") # ruby >= {KJ|MIN_TEST_RUBY}
121
+ spec.add_development_dependency("kettle-dev", "~> 3.0", ">= 3.0.17") # ruby >= {KJ|MIN_TEST_RUBY}
122
122
 
123
123
  # Security
124
124
  spec.add_development_dependency("bundler-audit", "~> 0.9.3") # ruby >= 2.0.0
@@ -133,7 +133,7 @@ Gem::Specification.new do |spec|
133
133
  # Loads version files in anonymous namespaces for coverage without constant redefinition warnings.
134
134
  spec.add_development_dependency("anonymous_loader", "~> 0.1", ">= 0.1.3") # ruby >= 2.2.0
135
135
  spec.add_development_dependency("appraisal2", "~> 3.2", ">= 3.2.2") # ruby >= 1.8.7, for testing against multiple versions of dependencies
136
- spec.add_development_dependency("kettle-test", "~> 2.0", ">= 2.0.20") # ruby >= {KJ|MIN_TEST_RUBY}
136
+ spec.add_development_dependency("kettle-test", "~> 2.0", ">= 2.0.21") # ruby >= {KJ|MIN_TEST_RUBY}
137
137
  spec.add_development_dependency("turbo_tests2", "~> 3.2", ">= 3.2.6") # ruby >= 2.4.0, default kettle-test runner
138
138
 
139
139
  # Releasing
@@ -7,7 +7,7 @@
7
7
  if ENV.fetch("KETTLE_DEV_DEV", "false").casecmp("false").zero?
8
8
  # Coverage (remote/released)
9
9
  platform :mri do
10
- gem "kettle-soup-cover", "~> 3.0", ">= 3.0.9", require: false
10
+ gem "kettle-soup-cover", "~> 3.0", ">= 3.0.10", require: false
11
11
  end
12
12
  else
13
13
  eval_gemfile "coverage_local.gemfile"
@@ -23,7 +23,7 @@ end
23
23
 
24
24
  if kettle_remote
25
25
  # Template/plugin checks for released installs.
26
- gem "kettle-drift", "~> 1.0", ">= 1.0.12", require: false
26
+ gem "kettle-drift", "~> 1.0", ">= 1.0.13", require: false
27
27
  end
28
28
 
29
29
  # Set STRUCTUREDMERGE_DEV=/path/to/structuredmerge/ruby/gems for local development with path-based dependencies.
@@ -6,7 +6,7 @@ shimmed_gem_path = ENV["KETTLE_JEM_SHIMMED_GEM_PATH"].to_s
6
6
  gem "{KJ|SHIMMED_GEM_NAME}", path: shimmed_gem_path unless shimmed_gem_path.empty?
7
7
 
8
8
  # Local workspace dependency wiring for templating_local.gemfile overrides.
9
- gem "nomono", "~> 1.1", ">= 1.1.4", require: false # ruby >= 3.2.0
9
+ gem "nomono", "~> 1.1", ">= 1.1.5", require: false # ruby >= 3.2.0
10
10
 
11
11
  # Templating (env-switched: STRUCTUREDMERGE_DEV=/path/to/structuredmerge/ruby/gems for local paths)
12
12
  eval_gemfile "gemfiles/modular/templating.gemfile" if ENV.fetch("K_JEM_TEMPLATING", "false").casecmp("true").zero?
@@ -30,13 +30,13 @@ Gem::Specification.new do |spec|
30
30
  spec.add_dependency "{KJ|SHIMMED_GEM_NAME}"
31
31
 
32
32
  # Dev, Test, & Release Tasks
33
- spec.add_development_dependency("kettle-dev", "~> 3.0", ">= 3.0.13") # ruby >= {KJ|MIN_TEST_RUBY}
33
+ spec.add_development_dependency("kettle-dev", "~> 3.0", ">= 3.0.17") # ruby >= {KJ|MIN_TEST_RUBY}
34
34
 
35
35
  # Tasks
36
36
  spec.add_development_dependency "rake", "~> 13.0"
37
37
 
38
38
  # Testing
39
- spec.add_development_dependency("kettle-test", "~> 2.0", ">= 2.0.20") # ruby >= {KJ|MIN_TEST_RUBY}
39
+ spec.add_development_dependency("kettle-test", "~> 2.0", ">= 2.0.21") # ruby >= {KJ|MIN_TEST_RUBY}
40
40
  spec.add_development_dependency "rspec", "~> 3.12"
41
41
 
42
42
  # Releasing
@@ -5,7 +5,7 @@ module Kettle
5
5
  # Version namespace for this gem.
6
6
  module Version
7
7
  # Current gem version.
8
- VERSION = "7.1.7"
8
+ VERSION = "7.1.10"
9
9
  end
10
10
  # Current gem version exposed at the traditional constant location.
11
11
  VERSION = Version::VERSION # Traditional Constant Location
data/lib/kettle/jem.rb CHANGED
@@ -474,8 +474,8 @@ module Kettle
474
474
  KJ|SOCIAL:MASTODON
475
475
  ].freeze
476
476
  COPYRIGHT_NAME_RE = /\ACopyright \(c\) [\d,\s-]+ (.+)\z/
477
- BOT_EMAIL_PATTERN = /\A\d+\+[^@]+\[bot\]@/i
478
- BOT_NAME_SUFFIX = /\[bot\]\z/i
477
+ BOT_IDENTITY_PATTERN = /\[bot\]/i
478
+ DEFAULT_MACHINE_USERS = ["autobolt", "StepSecurity Bot", "dependabot[bot]", "depfu[bot]"].freeze
479
479
  NOT_COMMITTED_EMAIL = "not.committed.yet"
480
480
  LOGOS_GALTZO_BASE_URL = "https://logos.galtzo.com/assets/images"
481
481
  README_TOP_LOGO_DEFAULTS = %w[org project].freeze
@@ -525,6 +525,7 @@ module Kettle
525
525
  APPRAISAL_VERSION_SELECTION_MODES = %w[major minor patch minor-minmax semver].freeze
526
526
  DEFAULT_TEST_MINIMUM_RUBY = Gem::Version.new("2.4")
527
527
  REQUIRE_RELATIVE_MIN_RUBY = Gem::Version.new("2.2").freeze
528
+ ANONYMOUS_VERSION_LOADER_MIN_RUBY = Gem::Version.new("2.2").freeze
528
529
  MODERN_GEMSPEC_VERSION_LOADER_MIN_RUBY = Gem::Version.new("3.1").freeze
529
530
  APPRAISAL_DEFAULT_FRESHNESS_TTL = 604_800
530
531
  DECISION_ACTIONS = %w[create merge replace keep delete skip].freeze
@@ -3326,7 +3327,6 @@ module Kettle
3326
3327
  version_path = File.join("lib", entrypoint_require, "version.rb")
3327
3328
  entrypoint_path = File.join("lib", "#{entrypoint_require}.rb")
3328
3329
  configured_namespace = rubygems_config["namespace"].to_s.strip
3329
- entrypoint_namespace = existing_entrypoint_version_namespace(project_root, entrypoint_path)
3330
3330
  version_namespace = existing_version_namespace(project_root, version_path)
3331
3331
  version_namespace = reconcile_existing_version_namespace(
3332
3332
  project_root,
@@ -3334,27 +3334,38 @@ module Kettle
3334
3334
  version_path,
3335
3335
  version_namespace
3336
3336
  )
3337
+ metadata_namespace = metadata_value(gemspec_metadata, :namespace)
3338
+ default_namespace = classify_namespace(name)
3339
+ namespace_hint = configured_namespace.empty? ? default_namespace : configured_namespace
3340
+ entrypoint_namespace = existing_entrypoint_version_namespace(
3341
+ project_root,
3342
+ entrypoint_path,
3343
+ expected_depth: namespace_hint.split("::").count { |segment| !segment.empty? }
3344
+ )
3345
+ namespace = configured_namespace.empty? ? nil : configured_namespace
3346
+ namespace ||= project_namespace(
3347
+ entrypoint_namespace: entrypoint_namespace,
3348
+ version_namespace: version_namespace,
3349
+ metadata_namespace: metadata_namespace,
3350
+ default_namespace: default_namespace
3351
+ )
3337
3352
  version_namespace_kinds = existing_version_namespace_kinds(
3338
3353
  project_root,
3339
3354
  version_path,
3340
- version_namespace,
3355
+ namespace,
3341
3356
  entrypoint_path: entrypoint_path
3342
3357
  )
3343
3358
  version_namespace_superclasses = existing_version_namespace_superclasses(
3344
3359
  project_root,
3345
3360
  version_path,
3346
- version_namespace,
3347
- entrypoint_path: entrypoint_path
3361
+ namespace
3348
3362
  )
3349
- metadata_namespace = metadata_value(gemspec_metadata, :namespace)
3350
- default_namespace = classify_namespace(name)
3351
- namespace = configured_namespace.empty? ? nil : configured_namespace
3352
- namespace ||= project_namespace(
3353
- entrypoint_namespace: entrypoint_namespace,
3354
- version_namespace: version_namespace,
3355
- metadata_namespace: metadata_namespace,
3356
- default_namespace: default_namespace
3363
+ namespace_superclass_details = existing_namespace_superclass_details(
3364
+ project_root,
3365
+ namespace,
3366
+ preferred_path: entrypoint_path
3357
3367
  )
3368
+ entrypoint_namespace_superclasses = namespace_superclass_details.fetch(:superclasses)
3358
3369
  project_version = metadata_value(gemspec_metadata, :version)
3359
3370
  project_version = existing_version_file_value(project_root, version_path) unless valid_gem_version?(project_version)
3360
3371
  project_version = git_version_file_value(project_root, version_path) unless valid_gem_version?(project_version)
@@ -3428,6 +3439,8 @@ module Kettle
3428
3439
  min_ruby: min_ruby,
3429
3440
  version_namespace_kinds: version_namespace_kinds,
3430
3441
  version_namespace_superclasses: version_namespace_superclasses,
3442
+ entrypoint_namespace_superclasses: entrypoint_namespace_superclasses,
3443
+ entrypoint_namespace_superclass_path: namespace_superclass_details[:path],
3431
3444
  version_gem_default_enabled: version_gem_default_enabled_for_project?(rubygems_config, gemspec_metadata),
3432
3445
  engines: ruby_engines_config(kettle_config)
3433
3446
  )
@@ -5383,11 +5396,11 @@ module Kettle
5383
5396
  [
5384
5397
  {name: "appraisal2", source: %(gem "appraisal2", "~> 3.2", ">= 3.2.2"\n)},
5385
5398
  {name: "bundler-audit", source: %(gem "bundler-audit", "~> 0.9.3"\n)},
5386
- {name: "kettle-dev", source: %(gem "kettle-dev", "~> 3.0", ">= 3.0.13"\n)},
5387
- {name: "kettle-drift", source: %(gem "kettle-drift", "~> 1.0", ">= 1.0.12"\n)},
5388
- {name: "kettle-family", source: %(gem "kettle-family", "~> 1.2", ">= 1.2.61"\n)},
5389
- {name: "kettle-jem", source: %(gem "kettle-jem", "~> 7.1", ">= 7.1.6"\n)},
5390
- {name: "kettle-test", source: %(gem "kettle-test", "~> 2.0", ">= 2.0.20"\n)},
5399
+ {name: "kettle-dev", source: %(gem "kettle-dev", "~> 3.0", ">= 3.0.17"\n)},
5400
+ {name: "kettle-drift", source: %(gem "kettle-drift", "~> 1.0", ">= 1.0.13"\n)},
5401
+ {name: "kettle-family", source: %(gem "kettle-family", "~> 1.2", ">= 1.2.64"\n)},
5402
+ {name: "kettle-jem", source: %(gem "kettle-jem", "~> 7.1", ">= 7.1.8"\n)},
5403
+ {name: "kettle-test", source: %(gem "kettle-test", "~> 2.0", ">= 2.0.21"\n)},
5391
5404
  {name: "rake", source: %(gem "rake", "~> 13.0"\n)},
5392
5405
  {name: "rspec", source: %(gem "rspec", "~> 3.0"\n)},
5393
5406
  {name: "stone_checksums", source: %(gem "stone_checksums", "~> 1.0", ">= 1.0.8"\n)},
@@ -5469,8 +5482,15 @@ module Kettle
5469
5482
  templated_paths = report.fetch(:recipe_reports, []).map { |recipe_report| recipe_report.fetch(:relative_path, "") }
5470
5483
  version_path = File.join("lib", entrypoint_require, "version.rb")
5471
5484
  signature_path = File.join("sig", "#{entrypoint_require}.rbs")
5472
- entrypoint_path = File.join("lib", "#{entrypoint_require}.rb")
5473
5485
  namespace = facts.dig(:rubygems, :namespace).to_s
5486
+ entrypoint_path = facts.dig(:rubygems, :entrypoint_namespace_superclass_path).to_s
5487
+ entrypoint_path = File.join("lib", "#{entrypoint_require}.rb") unless File.file?(File.join(project_root, entrypoint_path))
5488
+ namespace_superclass_details = existing_namespace_superclass_details(
5489
+ project_root,
5490
+ namespace,
5491
+ preferred_path: entrypoint_path
5492
+ )
5493
+ entrypoint_path = namespace_superclass_details[:path] if namespace_superclass_details[:path]
5474
5494
  version_gem_bootstrap_step_for_paths(
5475
5495
  project_root,
5476
5496
  facts,
@@ -5511,17 +5531,36 @@ module Kettle
5511
5531
 
5512
5532
  entrypoint_require = package_name.tr("-", "/") if entrypoint_require.to_s.empty?
5513
5533
  namespace = facts.dig(:rubygems, :namespace).to_s
5514
- namespace = classify_namespace(package_name) if namespace.empty?
5515
5534
  version_path = File.join("lib", entrypoint_require, "version.rb")
5516
5535
  entrypoint_path = File.join("lib", "#{entrypoint_require}.rb")
5517
- namespace = existing_entrypoint_version_namespace(project_root, entrypoint_path).to_s if namespace.empty?
5536
+ if namespace.empty?
5537
+ namespace = existing_entrypoint_version_namespace(
5538
+ project_root,
5539
+ entrypoint_path,
5540
+ expected_depth: classify_namespace(package_name).split("::").count { |segment| !segment.empty? }
5541
+ ).to_s
5542
+ end
5518
5543
  namespace = existing_version_namespace(project_root, version_path).to_s if namespace.empty?
5544
+ namespace = classify_namespace(package_name) if namespace.empty?
5519
5545
  return {name: "version_bootstrap", status: "unavailable", reason: "missing_package_facts"} if namespace.empty?
5520
5546
 
5547
+ namespace_superclass_details = existing_namespace_superclass_details(
5548
+ project_root,
5549
+ namespace,
5550
+ preferred_path: entrypoint_path
5551
+ )
5552
+ entrypoint_namespace_superclasses = namespace_superclass_details.fetch(:superclasses)
5553
+ entrypoint_namespace_superclasses = entrypoint_namespace_superclasses.merge(
5554
+ entrypoint_namespace_superclasses_from_facts(facts)
5555
+ )
5556
+ fact_superclass_path = facts.dig(:rubygems, :entrypoint_namespace_superclass_path).to_s
5557
+ if entrypoint_namespace_superclasses.any? && File.file?(File.join(project_root, fact_superclass_path))
5558
+ entrypoint_path = fact_superclass_path
5559
+ elsif namespace_superclass_details[:path]
5560
+ entrypoint_path = namespace_superclass_details[:path]
5561
+ end
5521
5562
  templated_paths = report.fetch(:recipe_reports, []).map { |recipe_report| recipe_report.fetch(:relative_path, "") }
5522
5563
  changes = []
5523
- cleanup = version_gem_cleanup_step(project_root, facts)
5524
- changes.concat(Array(cleanup[:changed_files]))
5525
5564
  outer_namespace_kind = version_namespace_outer_kind(project_root, entrypoint_path, namespace)
5526
5565
  namespace_kinds = existing_version_namespace_kinds(
5527
5566
  project_root,
@@ -5529,12 +5568,13 @@ module Kettle
5529
5568
  namespace,
5530
5569
  entrypoint_path: entrypoint_path
5531
5570
  )
5532
- namespace_superclasses = existing_version_namespace_superclasses(
5571
+ cleanup = version_gem_cleanup_step(
5533
5572
  project_root,
5534
- version_path,
5535
- namespace,
5536
- entrypoint_path: entrypoint_path
5573
+ facts,
5574
+ entrypoint_path: entrypoint_path,
5575
+ after_declarations: !entrypoint_namespace_superclasses.empty?
5537
5576
  )
5577
+ changes.concat(Array(cleanup[:changed_files]))
5538
5578
  preserve_version_module_include = existing_version_file_includes_version_module?(project_root, version_path) if preserve_version_module_include.nil?
5539
5579
  unless templated_paths.include?(version_path) && outer_namespace_kind != :class
5540
5580
  version = facts.dig(:project_runtime, :version).to_s
@@ -5549,7 +5589,6 @@ module Kettle
5549
5589
  version: version,
5550
5590
  outer_namespace_kind: outer_namespace_kind,
5551
5591
  namespace_kinds: namespace_kinds,
5552
- namespace_superclasses: namespace_superclasses,
5553
5592
  preserve_version_module_include: preserve_version_module_include
5554
5593
  )
5555
5594
  )
@@ -5593,13 +5632,13 @@ module Kettle
5593
5632
  }
5594
5633
  end
5595
5634
 
5596
- def version_gem_cleanup_step(project_root, facts, cleanup_entrypoint: true)
5635
+ def version_gem_cleanup_step(project_root, facts, cleanup_entrypoint: true, after_declarations: false, entrypoint_path: nil)
5597
5636
  package_name = facts.dig(:package, :name).to_s
5598
5637
  return {name: "version_gem_cleanup", status: "unavailable", reason: "missing_package_facts"} if package_name.empty?
5599
5638
 
5600
5639
  entrypoint_require = facts.dig(:rubygems, :entrypoint_require).to_s
5601
5640
  entrypoint_require = package_name.tr("-", "/") if entrypoint_require.empty?
5602
- entrypoint_path = File.join("lib", "#{entrypoint_require}.rb")
5641
+ entrypoint_path ||= File.join("lib", "#{entrypoint_require}.rb")
5603
5642
  dedicated_entrypoint_path = File.join("lib", entrypoint_require, "version_gem.rb")
5604
5643
  version_spec_path = File.join("spec", entrypoint_require, "version_spec.rb")
5605
5644
  changed_files = []
@@ -5609,7 +5648,8 @@ module Kettle
5609
5648
  cleaned = version_gem_free_entrypoint_content(
5610
5649
  current,
5611
5650
  entrypoint_require: entrypoint_require,
5612
- ensure_version_require: File.file?(version_path)
5651
+ ensure_version_require: File.file?(version_path),
5652
+ after_declarations: after_declarations
5613
5653
  )
5614
5654
  changed_files << write_if_changed(project_root, entrypoint_path, cleaned)
5615
5655
  end
@@ -6894,10 +6934,12 @@ module Kettle
6894
6934
  modern = Gem::Version.new(min_ruby) >= MODERN_GEMSPEC_VERSION_LOADER_MIN_RUBY
6895
6935
  before_legacy = !gemspec_top_level_gem_version_node(original).nil?
6896
6936
  after_legacy = !gemspec_top_level_gem_version_node(final).nil?
6937
+ superclass_sensitive = gemspec_version_loader_superclass_sensitive?(request[:runtime_context] || request["runtime_context"] || {})
6897
6938
  {
6898
6939
  operation: "rewrite_version_loader",
6899
6940
  min_ruby: min_ruby,
6900
6941
  mode: modern ? "modern" : "legacy",
6942
+ superclass_sensitive: superclass_sensitive,
6901
6943
  legacy_preamble_removed: before_legacy && !after_legacy,
6902
6944
  legacy_preamble_present: after_legacy
6903
6945
  }
@@ -8208,8 +8250,6 @@ module Kettle
8208
8250
  )
8209
8251
  end
8210
8252
  main_gemfile_nomono_requirement_records(output).fetch(:calls).sort_by { |record| -record.fetch(:start_line) }.reduce(output) do |memo, record|
8211
- next memo unless record.fetch(:source).include?("*nomono_requirements")
8212
-
8213
8253
  replace_source_range_lines(memo, record.fetch(:start_line), record.fetch(:end_line), "#{nomono_gemfile_declaration}\n")
8214
8254
  end
8215
8255
  end
@@ -10526,7 +10566,18 @@ module Kettle
10526
10566
  modern = min_ruby_version >= MODERN_GEMSPEC_VERSION_LOADER_MIN_RUBY
10527
10567
  rhs = modern ? gemspec_modern_version_loader_expression(entrypoint_require: entrypoint_require, namespace: namespace) : "gem_version"
10528
10568
  rewritten = replace_gemspec_version_assignment(content, receiver: receiver, rhs: rhs)
10529
- modern ? remove_gemspec_legacy_version_loader_preamble(rewritten) : ensure_gemspec_legacy_version_loader_preamble(rewritten, entrypoint_require: entrypoint_require, namespace: namespace, min_ruby: min_ruby_version)
10569
+ if modern
10570
+ remove_gemspec_legacy_version_loader_preamble(rewritten)
10571
+ else
10572
+ ensure_gemspec_legacy_version_loader_preamble(
10573
+ rewritten,
10574
+ entrypoint_require: entrypoint_require,
10575
+ namespace: namespace,
10576
+ min_ruby: min_ruby_version,
10577
+ superclass_sensitive: gemspec_version_loader_superclass_sensitive?(facts),
10578
+ fallback_version: facts.to_h.dig(:project_runtime, :version)
10579
+ )
10580
+ end
10530
10581
  rescue ArgumentError, Ast::Crispr::Error
10531
10582
  content
10532
10583
  end
@@ -10546,7 +10597,48 @@ module Kettle
10546
10597
  %(Module.new.tap { |mod| Kernel.load("\#{__dir__}/lib/#{entrypoint_require}/version.rb", mod) }::#{namespace}::Version::VERSION)
10547
10598
  end
10548
10599
 
10549
- def gemspec_legacy_version_loader_block(entrypoint_require:, namespace:, min_ruby:)
10600
+ def gemspec_legacy_version_loader_block(entrypoint_require:, namespace:, min_ruby:, superclass_sensitive: false, fallback_version: nil)
10601
+ unless superclass_sensitive
10602
+ return gemspec_standard_legacy_version_loader_block(
10603
+ entrypoint_require: entrypoint_require,
10604
+ namespace: namespace,
10605
+ min_ruby: min_ruby
10606
+ )
10607
+ end
10608
+
10609
+ anonymous_loader = <<~RUBY.chomp
10610
+ require "anonymous_loader"
10611
+ path = File.expand_path("lib/#{entrypoint_require}/version.rb", __dir__)
10612
+ anonymous_namespace = AnonymousLoader.load(files: path)
10613
+ anonymous_namespace::#{namespace}::Version::VERSION
10614
+ RUBY
10615
+ anonymous_loader_lines = anonymous_loader.lines.map { |line| " #{line.chomp}" }
10616
+ fallback = fallback_version.to_s
10617
+ fallback = "0.0.0" if fallback.empty?
10618
+ lines = [
10619
+ "gem_version =",
10620
+ " if Gem.ruby_version >= Gem::Version.new(\"3.1\")",
10621
+ " # Loading Version into an anonymous module allows version.rb to get code coverage from SimpleCov!",
10622
+ " # See: https://github.com/simplecov-ruby/simplecov/issues/557#issuecomment-2630782358",
10623
+ " # See: https://github.com/panorama-ed/memo_wise/pull/397",
10624
+ " #{gemspec_modern_version_loader_expression(entrypoint_require: entrypoint_require, namespace: namespace)}"
10625
+ ]
10626
+ lines << " # The namesake namespace has a superclass. Directly requiring version.rb"
10627
+ lines << " # on legacy Ruby could define that namespace with the wrong superclass."
10628
+ if min_ruby < ANONYMOUS_VERSION_LOADER_MIN_RUBY
10629
+ lines << " elsif Gem.ruby_version >= Gem::Version.new(\"2.2\")"
10630
+ lines.concat(anonymous_loader_lines)
10631
+ lines << " else"
10632
+ lines << " #{fallback.dump}"
10633
+ else
10634
+ lines << " else"
10635
+ lines.concat(anonymous_loader_lines)
10636
+ end
10637
+ lines << " end"
10638
+ "#{lines.join("\n")}\n"
10639
+ end
10640
+
10641
+ def gemspec_standard_legacy_version_loader_block(entrypoint_require:, namespace:, min_ruby:)
10550
10642
  legacy_require =
10551
10643
  if min_ruby >= REQUIRE_RELATIVE_MIN_RUBY
10552
10644
  %(require_relative "lib/#{entrypoint_require}/version")
@@ -10574,6 +10666,14 @@ module Kettle
10574
10666
  RUBY
10575
10667
  end
10576
10668
 
10669
+ def gemspec_version_loader_superclass_sensitive?(facts)
10670
+ rubygems = facts.to_h[:rubygems]
10671
+ return false unless rubygems.is_a?(Hash)
10672
+
10673
+ value = rubygems[:entrypoint_namespace_superclasses]
10674
+ value.is_a?(Hash) && !value.empty?
10675
+ end
10676
+
10577
10677
  def remove_gemspec_legacy_version_loader_preamble(content)
10578
10678
  node = gemspec_top_level_gem_version_node(content)
10579
10679
  unless node
@@ -10606,8 +10706,8 @@ module Kettle
10606
10706
  {start_line: start_index + 1, end_line: end_line}
10607
10707
  end
10608
10708
 
10609
- def ensure_gemspec_legacy_version_loader_preamble(content, entrypoint_require:, namespace:, min_ruby:)
10610
- block = "#{gemspec_legacy_version_loader_block(entrypoint_require: entrypoint_require, namespace: namespace, min_ruby: min_ruby)}\n"
10709
+ def ensure_gemspec_legacy_version_loader_preamble(content, entrypoint_require:, namespace:, min_ruby:, superclass_sensitive: false, fallback_version: nil)
10710
+ block = "#{gemspec_legacy_version_loader_block(entrypoint_require: entrypoint_require, namespace: namespace, min_ruby: min_ruby, superclass_sensitive: superclass_sensitive, fallback_version: fallback_version)}\n"
10611
10711
  node = gemspec_top_level_gem_version_node(content)
10612
10712
  return replace_source_range_lines(content, node.location.start_line, expand_line_range_through_following_blanks(content, node.location.end_line), block) if node
10613
10713
 
@@ -12322,7 +12422,28 @@ module Kettle
12322
12422
  def sync_kettle_config_documentation_comments(content)
12323
12423
  synced = sync_readme_top_logos_documentation_comment(content)
12324
12424
  synced = remove_duplicate_framework_matrix_documentation(synced)
12325
- remove_duplicate_readme_preservation_documentation(synced)
12425
+ synced = remove_duplicate_readme_preservation_documentation(synced)
12426
+ sync_author_names_documentation_comment(synced)
12427
+ end
12428
+
12429
+ def sync_author_names_documentation_comment(content)
12430
+ legacy = "# AUTHOR:NAMES <- all authors from the gemspec, or copyright holders if no gemspec authors exist"
12431
+ current = [
12432
+ "# AUTHOR:NAMES <- existing gemspec authors plus Git-derived copyright holders\n",
12433
+ "# (after author_aliases consolidation)\n"
12434
+ ]
12435
+ lines = content.to_s.lines
12436
+ index = lines.index { |line| line.chomp == legacy }
12437
+ updated = if index
12438
+ lines[index, 1] = current
12439
+ lines.join
12440
+ else
12441
+ content
12442
+ end
12443
+
12444
+ legacy_token_comment = "generated gemspec authors preserve the full existing authors array via AUTHOR:NAMES."
12445
+ current_token_comment = "AUTHOR:NAMES preserves existing gemspec authors and appends Git-derived copyright holders."
12446
+ updated.lines.map { |line| line.sub(legacy_token_comment, current_token_comment) }.join
12326
12447
  end
12327
12448
 
12328
12449
  # YAML parsers do not retain comments. These migrations therefore operate
@@ -14077,7 +14198,7 @@ module Kettle
14077
14198
  root: ["src", "my", "kettle-dev"]
14078
14199
  )
14079
14200
  elsif Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("4.0.0")
14080
- gem "kettle-changelog", "~> 1.0", ">= 1.0.3"
14201
+ gem "kettle-changelog", "~> 1.0", ">= 1.0.5"
14081
14202
  end
14082
14203
  end
14083
14204
  RUBY
@@ -14391,7 +14512,10 @@ module Kettle
14391
14512
  def author_facts(config, env, gemspec_metadata: {}, copyright: {})
14392
14513
  token_config = token_config_values(config)
14393
14514
  author_config = token_config["author"].is_a?(Hash) ? token_config["author"] : {}
14394
- derived_name = Array(gemspec_metadata[:authors]).map(&:to_s).find { |value| present_template_token_value?(value) }
14515
+ aliases = author_aliases(config)
14516
+ derived_name = Array(gemspec_metadata[:authors]).map { |value| canonical_author_name(value, aliases) }.find do |value|
14517
+ present_template_token_value?(value)
14518
+ end
14395
14519
  derived_email = Array(gemspec_metadata[:email]).map(&:to_s).find { |value| present_template_token_value?(value) }
14396
14520
  name = preferred_template_token_value(derived_name, author_config["name"], env, "KJ_AUTHOR_NAME").to_s
14397
14521
  email = preferred_template_token_value(derived_email, author_config["email"], env, "KJ_AUTHOR_EMAIL").to_s
@@ -14401,7 +14525,7 @@ module Kettle
14401
14525
  orcid = preferred_template_token_value(nil, author_config["orcid"], env, "KJ_AUTHOR_ORCID")
14402
14526
  compact_hash(
14403
14527
  name: name,
14404
- names: author_names(gemspec_metadata, copyright, name),
14528
+ names: author_names(gemspec_metadata, copyright, name, author_aliases: aliases),
14405
14529
  given_names: given_names.to_s,
14406
14530
  family_names: family_names.to_s,
14407
14531
  email: email,
@@ -14435,6 +14559,46 @@ module Kettle
14435
14559
  value.to_s.strip.match?(%r{\A\{KJ\|[A-Z][A-Z0-9_:]*\}\z})
14436
14560
  end
14437
14561
 
14562
+ def author_aliases(config)
14563
+ return {} unless config.is_a?(Hash)
14564
+
14565
+ configured = config["author_aliases"]
14566
+ configured = config.dig("copyright", "author_aliases") if configured.nil? && config["copyright"].is_a?(Hash)
14567
+ return {} unless configured.is_a?(Hash)
14568
+
14569
+ configured.each_with_object({}) do |(alias_name, canonical_name), aliases|
14570
+ alias_key = alias_name.to_s.strip.downcase
14571
+ canonical = canonical_name.to_s.strip
14572
+ next if alias_key.empty? || canonical.empty?
14573
+
14574
+ aliases[alias_key] = canonical
14575
+ end
14576
+ end
14577
+
14578
+ def canonical_author_name(value, aliases)
14579
+ current = value.to_s.strip
14580
+ seen = {}
14581
+ loop do
14582
+ key = current.downcase
14583
+ break if current.empty? || seen[key]
14584
+
14585
+ seen[key] = true
14586
+ replacement = aliases[key]
14587
+ break if replacement.nil? || replacement.to_s.strip.empty?
14588
+
14589
+ current = replacement.to_s.strip
14590
+ end
14591
+ current
14592
+ end
14593
+
14594
+ def canonical_author_name_for_entry(entry, aliases)
14595
+ name = entry[:name].to_s.strip
14596
+ email = entry[:email].to_s.strip
14597
+ configured_name = aliases[name.downcase]
14598
+ configured_email = aliases[email.downcase]
14599
+ canonical_author_name(configured_name || configured_email || name, aliases)
14600
+ end
14601
+
14438
14602
  def author_template_tokens(author)
14439
14603
  names = Array(author[:names]).map(&:to_s).reject(&:empty?)
14440
14604
  names = [author[:name].to_s] if names.empty?
@@ -14449,11 +14613,13 @@ module Kettle
14449
14613
  }
14450
14614
  end
14451
14615
 
14452
- def author_names(gemspec_metadata, copyright, primary_name)
14616
+ def author_names(gemspec_metadata, copyright, primary_name, author_aliases: {})
14453
14617
  names = Array(gemspec_metadata[:authors]).map(&:to_s)
14454
- names = names.select { |name| present_template_token_value?(name) }
14455
- names = copyright_author_names(copyright) if names.empty?
14456
- names = [primary_name.to_s] if names.empty?
14618
+ names += copyright_author_names(copyright)
14619
+ names = names
14620
+ .map { |name| canonical_author_name(name, author_aliases) }
14621
+ .select { |name| present_template_token_value?(name) }
14622
+ names = [canonical_author_name(primary_name, author_aliases)] if names.empty?
14457
14623
  names.map(&:strip).reject(&:empty?).uniq
14458
14624
  end
14459
14625
 
@@ -14481,16 +14647,21 @@ module Kettle
14481
14647
  end
14482
14648
 
14483
14649
  def copyright_facts(project_root, config)
14484
- lines = git_copyright_lines(project_root, copyright_machine_users(config))
14650
+ lines = git_copyright_lines(
14651
+ project_root,
14652
+ copyright_machine_users(config),
14653
+ author_aliases: author_aliases(config)
14654
+ )
14485
14655
  compact_hash(lines: lines)
14486
14656
  end
14487
14657
 
14488
14658
  def copyright_machine_users(config)
14489
14659
  copyright = config["copyright"].is_a?(Hash) ? config["copyright"] : {}
14490
- (Array(config["machine_users"]) + Array(copyright["machine_users"])).map { |user| user.to_s.downcase.strip }.reject(&:empty?)
14660
+ configured = DEFAULT_MACHINE_USERS + Array(config["machine_users"]) + Array(copyright["machine_users"])
14661
+ configured.map { |user| user.to_s.downcase.strip }.reject(&:empty?).uniq
14491
14662
  end
14492
14663
 
14493
- def git_copyright_lines(project_root, machine_users)
14664
+ def git_copyright_lines(project_root, machine_users, author_aliases: {})
14494
14665
  files = git_capture(project_root, "ls-files", "-z")
14495
14666
  return [] if files.to_s.empty?
14496
14667
 
@@ -14503,10 +14674,20 @@ module Kettle
14503
14674
  next
14504
14675
  end
14505
14676
  resolve_uncommitted_author!(project_root, author_map)
14506
- author_map.values
14677
+ consolidated = author_map.values
14507
14678
  .reject { |entry| copyright_bot_entry?(entry) }
14508
- .reject { |entry| copyright_machine_user_entry?(entry, machine_users) }
14509
- .reject { |entry| entry[:name].to_s.strip.empty? || entry[:years].empty? }
14679
+ .reject { |entry| copyright_machine_user_entry?(entry, machine_users, author_aliases: author_aliases) }
14680
+ .each_with_object({}) do |entry, authors|
14681
+ next if entry[:name].to_s.strip.empty? || entry[:years].empty?
14682
+
14683
+ name = canonical_author_name_for_entry(entry, author_aliases)
14684
+ next if name.empty?
14685
+
14686
+ author = authors[name.downcase] ||= {name: name, years: []}
14687
+ author[:years].concat(entry[:years])
14688
+ end
14689
+ .values
14690
+ consolidated
14510
14691
  .sort_by { |entry| [entry[:years].map(&:to_i).min, entry[:name].to_s.downcase] }
14511
14692
  .map { |entry| "Copyright (c) #{format_copyright_years(entry[:years])} #{entry[:name]}" }
14512
14693
  rescue ArgumentError
@@ -14566,14 +14747,18 @@ module Kettle
14566
14747
  end
14567
14748
 
14568
14749
  def copyright_bot_entry?(entry)
14569
- entry[:name].to_s.match?(BOT_NAME_SUFFIX) || entry[:email].to_s.match?(BOT_EMAIL_PATTERN)
14750
+ entry[:name].to_s.match?(BOT_IDENTITY_PATTERN) || entry[:email].to_s.match?(BOT_IDENTITY_PATTERN)
14570
14751
  end
14571
14752
 
14572
- def copyright_machine_user_entry?(entry, machine_users)
14753
+ def copyright_machine_user_entry?(entry, machine_users, author_aliases: {})
14573
14754
  return false if machine_users.empty?
14574
14755
 
14575
- machine_users.include?(entry[:name].to_s.downcase.strip) ||
14576
- machine_users.include?(entry[:email].to_s.downcase.strip)
14756
+ identities = [
14757
+ entry[:name],
14758
+ entry[:email],
14759
+ canonical_author_name_for_entry(entry, author_aliases)
14760
+ ].map { |identity| identity.to_s.downcase.strip }
14761
+ identities.any? { |identity| machine_users.include?(identity) }
14577
14762
  end
14578
14763
 
14579
14764
  def format_copyright_years(years)
@@ -15037,7 +15222,7 @@ module Kettle
15037
15222
  def main_gemfile_kettle_family_gem(package_name)
15038
15223
  return "" if package_name.to_s == "kettle-family"
15039
15224
 
15040
- %(gem "kettle-family", "~> 1.2", ">= 1.2.61"\n)
15225
+ %(gem "kettle-family", "~> 1.2", ">= 1.2.64"\n)
15041
15226
  end
15042
15227
 
15043
15228
  def main_gemfile_nomono_bootstrap(package_name)
@@ -15050,7 +15235,7 @@ module Kettle
15050
15235
  end
15051
15236
 
15052
15237
  def nomono_gemfile_declaration
15053
- %(gem "nomono", "~> 1.1", ">= 1.1.4", require: false # ruby >= 3.2.0)
15238
+ %(gem "nomono", "~> 1.1", ">= 1.1.5", require: false # ruby >= 3.2.0)
15054
15239
  end
15055
15240
 
15056
15241
  def local_gemfile_nomono_bootstrap(_package_name)
@@ -15058,7 +15243,7 @@ module Kettle
15058
15243
  # Bootstrapping nomono here cannot rely on a plain `gem "nomono", ...` line.
15059
15244
  # Bundler records that dependency during Gemfile evaluation, but it does not
15060
15245
  # activate that exact version before the immediate `require "nomono/bundler"`.
15061
- nomono_activation_requirements = ["~> 1.1", ">= 1.1.4"]
15246
+ nomono_activation_requirements = ["~> 1.1", ">= 1.1.5"]
15062
15247
  nomono_requirement = Gem::Requirement.new(nomono_activation_requirements)
15063
15248
  nomono_already_activated = Gem.loaded_specs["nomono"]
15064
15249
  nomono_lockfile = File.expand_path("../../Gemfile.lock", __dir__)
@@ -15136,6 +15321,36 @@ module Kettle
15136
15321
  )
15137
15322
  default_entrypoint_path = File.join("lib", "#{entrypoint_require}.rb")
15138
15323
  default_entrypoint = read_project_file(project_root, default_entrypoint_path)
15324
+ version_spec_path = File.join("spec", entrypoint_require, "version_spec.rb")
15325
+ signature_path = File.join("sig", "#{entrypoint_require}.rbs")
15326
+ legacy_signature_paths = legacy_rbs_signature_paths(project_root, entrypoint_require)
15327
+ namespace = facts.dig(:rubygems, :namespace).to_s
15328
+ if namespace.empty?
15329
+ namespace = existing_entrypoint_version_namespace(
15330
+ project_root,
15331
+ entrypoint_path,
15332
+ expected_depth: classify_namespace(package_name).split("::").count { |segment| !segment.empty? }
15333
+ ).to_s
15334
+ end
15335
+ namespace = existing_version_namespace(project_root, version_path).to_s if namespace.empty?
15336
+ namespace = classify_namespace(package_name) if namespace.empty?
15337
+ return {name: "version_gem_bootstrap", status: "unavailable", reason: "missing_package_facts"} if namespace.empty?
15338
+
15339
+ namespace_superclass_details = existing_namespace_superclass_details(
15340
+ project_root,
15341
+ namespace,
15342
+ preferred_path: entrypoint_path
15343
+ )
15344
+ entrypoint_namespace_superclasses = namespace_superclass_details.fetch(:superclasses)
15345
+ entrypoint_namespace_superclasses = entrypoint_namespace_superclasses.merge(
15346
+ entrypoint_namespace_superclasses_from_facts(facts)
15347
+ )
15348
+ fact_superclass_path = facts.dig(:rubygems, :entrypoint_namespace_superclass_path).to_s
15349
+ if entrypoint_namespace_superclasses.any? && File.file?(File.join(project_root, fact_superclass_path))
15350
+ entrypoint_path = fact_superclass_path
15351
+ elsif namespace_superclass_details[:path]
15352
+ entrypoint_path = namespace_superclass_details[:path]
15353
+ end
15139
15354
  default_entrypoint_loads_version = entrypoint_path != default_entrypoint_path &&
15140
15355
  entrypoint_loads_version_file?(
15141
15356
  default_entrypoint,
@@ -15143,25 +15358,20 @@ module Kettle
15143
15358
  entrypoint_path: default_entrypoint_path,
15144
15359
  version_path: version_path
15145
15360
  )
15146
- version_spec_path = File.join("spec", entrypoint_require, "version_spec.rb")
15147
- signature_path = File.join("sig", "#{entrypoint_require}.rbs")
15148
- legacy_signature_paths = legacy_rbs_signature_paths(project_root, entrypoint_require)
15149
- namespace = existing_version_namespace(project_root, version_path).to_s
15150
- namespace = facts.dig(:rubygems, :namespace).to_s if namespace.empty?
15151
- namespace = classify_namespace(package_name) if namespace.empty?
15152
- namespace = existing_entrypoint_version_namespace(project_root, entrypoint_path).to_s if namespace.empty?
15153
- return {name: "version_gem_bootstrap", status: "unavailable", reason: "missing_package_facts"} if namespace.empty?
15154
-
15155
15361
  version = facts.dig(:project_runtime, :version).to_s
15156
15362
  version = project_gemspec_version(project_root) if version.empty?
15157
15363
  version = "0.0.1.pre" if version.empty?
15158
15364
  changes = []
15159
15365
  current_entrypoint = read_project_file(project_root, entrypoint_path)
15160
15366
  outer_namespace_kind = ruby_entrypoint_outer_namespace_kind(current_entrypoint, namespace)
15161
- namespace_kinds = existing_version_namespace_kinds(project_root, version_path, namespace)
15162
- namespace_kinds = namespace_kinds.merge(version_namespace_kinds_from_facts(facts))
15163
- namespace_superclasses = existing_version_namespace_superclasses(project_root, version_path, namespace)
15164
- namespace_superclasses = namespace_superclasses.merge(version_namespace_superclasses_from_facts(facts))
15367
+ namespace_kinds = version_namespace_kinds_from_facts(facts).merge(
15368
+ existing_version_namespace_kinds(
15369
+ project_root,
15370
+ version_path,
15371
+ namespace,
15372
+ entrypoint_path: entrypoint_path
15373
+ )
15374
+ )
15165
15375
  preserve_version_module_include = existing_version_file_includes_version_module?(project_root, version_path) if preserve_version_module_include.nil?
15166
15376
 
15167
15377
  if manage_version_file
@@ -15174,7 +15384,6 @@ module Kettle
15174
15384
  version: version,
15175
15385
  outer_namespace_kind: outer_namespace_kind,
15176
15386
  namespace_kinds: namespace_kinds,
15177
- namespace_superclasses: namespace_superclasses,
15178
15387
  preserve_version_module_include: preserve_version_module_include
15179
15388
  )
15180
15389
  )
@@ -15186,6 +15395,7 @@ module Kettle
15186
15395
  current_entrypoint,
15187
15396
  entrypoint_require: entrypoint_require,
15188
15397
  ensure_version_require: !default_entrypoint_loads_version,
15398
+ after_declarations: !entrypoint_namespace_superclasses.empty?,
15189
15399
  version_require_path: version_require_path_for_entrypoint(entrypoint_path, version_path)
15190
15400
  )
15191
15401
  elsif current_entrypoint.empty?
@@ -15195,6 +15405,7 @@ module Kettle
15195
15405
  current_entrypoint,
15196
15406
  namespace: namespace,
15197
15407
  entrypoint_require: entrypoint_require,
15408
+ namespace_superclasses: entrypoint_namespace_superclasses,
15198
15409
  version_require_path: version_require_path_for_entrypoint(entrypoint_path, version_path)
15199
15410
  )
15200
15411
  end
@@ -15577,7 +15788,7 @@ module Kettle
15577
15788
  version_gem_require_insertion_index(content)
15578
15789
  end
15579
15790
 
15580
- def version_gem_version_file_content(existing_version:, namespace:, version:, outer_namespace_kind: :module, namespace_kinds: {}, namespace_superclasses: {}, preserve_version_module_include: false)
15791
+ def version_gem_version_file_content(existing_version:, namespace:, version:, outer_namespace_kind: :module, namespace_kinds: {}, preserve_version_module_include: false)
15581
15792
  resolved_version = existing_version.to_s.empty? ? version.to_s : existing_version.to_s
15582
15793
  body = [
15583
15794
  "# Version namespace for this gem.",
@@ -15593,7 +15804,7 @@ module Kettle
15593
15804
  <<~RUBY
15594
15805
  # frozen_string_literal: true
15595
15806
 
15596
- #{wrap_ruby_namespace(namespace, body, outer_namespace_kind: outer_namespace_kind, namespace_kinds: namespace_kinds, namespace_superclasses: namespace_superclasses).join("\n")}
15807
+ #{wrap_ruby_namespace(namespace, body, outer_namespace_kind: outer_namespace_kind, namespace_kinds: namespace_kinds).join("\n")}
15597
15808
  RUBY
15598
15809
  end
15599
15810
 
@@ -15620,11 +15831,12 @@ module Kettle
15620
15831
  "#{wrap_ruby_namespace(namespace, body).join("\n")}\n"
15621
15832
  end
15622
15833
 
15623
- def version_gem_bootstrap_entrypoint_content(content, namespace:, entrypoint_require:, version_require_path: nil)
15834
+ def version_gem_bootstrap_entrypoint_content(content, namespace:, entrypoint_require:, namespace_superclasses: {}, version_require_path: nil)
15624
15835
  current = normalize_entrypoint_version_require(
15625
15836
  content,
15626
15837
  entrypoint_require: entrypoint_require,
15627
- version_require_path: version_require_path
15838
+ version_require_path: version_require_path,
15839
+ after_declarations: !namespace_superclasses.empty?
15628
15840
  )
15629
15841
  current = remove_version_gem_class_eval_references(current) unless ruby_version_class_eval_namespaces(current).include?(namespace.to_s)
15630
15842
  lines = current.lines
@@ -15645,7 +15857,7 @@ module Kettle
15645
15857
  collapse_excess_blank_lines(updated)
15646
15858
  end
15647
15859
 
15648
- def version_gem_free_entrypoint_content(content, entrypoint_require:, ensure_version_require: true, version_require_path: nil)
15860
+ def version_gem_free_entrypoint_content(content, entrypoint_require:, ensure_version_require: true, after_declarations: false, version_require_path: nil)
15649
15861
  current = remove_version_gem_entrypoint_references(content)
15650
15862
  unless ensure_version_require
15651
15863
  relative_path = version_require_path.to_s.empty? ? File.join(File.basename(entrypoint_require), "version") : version_require_path.to_s
@@ -15660,17 +15872,23 @@ module Kettle
15660
15872
  normalize_entrypoint_version_require(
15661
15873
  current,
15662
15874
  entrypoint_require: entrypoint_require,
15663
- version_require_path: version_require_path
15875
+ version_require_path: version_require_path,
15876
+ after_declarations: after_declarations
15664
15877
  )
15665
15878
  end
15666
15879
 
15667
- def normalize_entrypoint_version_require(content, entrypoint_require:, version_require_path: nil)
15880
+ def normalize_entrypoint_version_require(content, entrypoint_require:, version_require_path: nil, after_declarations: false)
15668
15881
  relative_path = version_require_path.to_s.empty? ? File.join(File.basename(entrypoint_require), "version") : version_require_path.to_s
15669
15882
  absolute_path = File.join(entrypoint_require, "version")
15670
15883
  legacy_relative_path = File.join(File.basename(entrypoint_require), "version")
15671
15884
  current = [relative_path, legacy_relative_path].uniq.reduce(content) do |value, path|
15672
15885
  remove_entrypoint_version_requires(value, relative_path: path, absolute_path: absolute_path)
15673
15886
  end
15887
+ if after_declarations
15888
+ current = trim_trailing_blank_lines(collapse_excess_blank_lines(current))
15889
+ return "#{current}\n\nrequire_relative \"#{relative_path}\"\n" unless current.empty?
15890
+ end
15891
+
15674
15892
  lines = current.lines
15675
15893
  lines.insert(version_gem_require_insertion_index(current), %(require_relative "#{relative_path}"\n), "\n")
15676
15894
  trim_trailing_blank_lines(collapse_excess_blank_lines(lines.join))
@@ -15838,6 +16056,9 @@ module Kettle
15838
16056
  kind = version_namespace_outer_kind(project_root, entrypoint_path, namespace)
15839
16057
  return kind if kind == :class
15840
16058
 
16059
+ entrypoint_kind = ruby_namespace_declaration_kind(read_project_file(project_root, entrypoint_path), namespace)
16060
+ return entrypoint_kind if entrypoint_kind == :class
16061
+
15841
16062
  configured_kinds = version_namespace_kinds_from_facts(facts)
15842
16063
  target_index = namespace.to_s.split("::").count { |element| !element.empty? } - 1
15843
16064
  configured_kind = configured_kinds[target_index]
@@ -15866,6 +16087,16 @@ module Kettle
15866
16087
  end
15867
16088
  end
15868
16089
 
16090
+ def entrypoint_namespace_superclasses_from_facts(facts)
16091
+ raw = facts.dig(:rubygems, :entrypoint_namespace_superclasses)
16092
+ return {} unless raw.is_a?(Hash)
16093
+
16094
+ raw.each_with_object({}) do |(index, superclass), superclasses|
16095
+ value = superclass.to_s.strip
16096
+ superclasses[index.to_i] = value unless value.empty?
16097
+ end
16098
+ end
16099
+
15869
16100
  def ruby_entrypoint_outer_namespace_kind(content, namespace)
15870
16101
  first_segment = namespace.to_s.split("::").reject(&:empty?).first
15871
16102
  return :module if first_segment.to_s.empty?
@@ -15979,6 +16210,27 @@ module Kettle
15979
16210
  end
15980
16211
  end
15981
16212
 
16213
+ def existing_namespace_superclass_details(project_root, namespace, preferred_path: nil)
16214
+ library_paths = [preferred_path, *ruby_library_source_paths(project_root)].compact.uniq
16215
+ library_paths.each do |relative_path|
16216
+ superclasses = existing_version_namespace_superclasses(project_root, relative_path, namespace)
16217
+ next if superclasses.empty?
16218
+
16219
+ return {path: relative_path, superclasses: superclasses}
16220
+ end
16221
+
16222
+ {path: nil, superclasses: {}}
16223
+ end
16224
+
16225
+ def ruby_library_source_paths(project_root)
16226
+ Dir.glob(File.join(project_root, "lib", "**", "*.rb")).sort.filter_map do |path|
16227
+ relative_path = Pathname(path).relative_path_from(Pathname(project_root)).to_s
16228
+ next if relative_path.end_with?("/version.rb", "/version_gem.rb")
16229
+
16230
+ relative_path
16231
+ end
16232
+ end
16233
+
15982
16234
  def ruby_namespace_declaration_kind(content, namespace)
15983
16235
  target = namespace.to_s.split("::").reject(&:empty?)
15984
16236
  body = prism_parse_success(content)&.value&.statements&.body || []
@@ -16069,8 +16321,13 @@ module Kettle
16069
16321
  node&.slice.to_s.split("::").reject(&:empty?)
16070
16322
  end
16071
16323
 
16072
- def existing_entrypoint_version_namespace(project_root, relative_path)
16324
+ def existing_entrypoint_version_namespace(project_root, relative_path, expected_depth: nil)
16073
16325
  content = read_project_file(project_root, relative_path)
16326
+ if expected_depth
16327
+ return ruby_entrypoint_module_namespace(content, expected_depth: expected_depth) ||
16328
+ ruby_version_class_eval_namespaces(content).first
16329
+ end
16330
+
16074
16331
  ruby_version_class_eval_namespaces(content).first || ruby_entrypoint_module_namespace(content)
16075
16332
  end
16076
16333
 
@@ -16084,24 +16341,27 @@ module Kettle
16084
16341
  end
16085
16342
  end
16086
16343
 
16087
- def ruby_entrypoint_module_namespace(content)
16344
+ def ruby_entrypoint_module_namespace(content, expected_depth: nil)
16088
16345
  body = prism_parse_success(content)&.value&.statements&.body || []
16089
16346
  body.each do |node|
16090
- namespace = ruby_entrypoint_module_namespace_for(node, [])
16347
+ namespace = ruby_entrypoint_module_namespace_for(node, [], expected_depth: expected_depth)
16091
16348
  return namespace if namespace
16092
16349
  end
16093
16350
  nil
16094
16351
  end
16095
16352
 
16096
- def ruby_entrypoint_module_namespace_for(node, namespace)
16353
+ def ruby_entrypoint_module_namespace_for(node, namespace, expected_depth: nil)
16097
16354
  return unless node.is_a?(::Prism::ModuleNode) || node.is_a?(::Prism::ClassNode)
16098
16355
 
16099
16356
  current = namespace + ruby_constant_path_segments(node.constant_path)
16357
+ return current.join("::") if expected_depth && current.length == expected_depth
16358
+ return if expected_depth && current.length > expected_depth
16359
+
16100
16360
  node.body&.body&.each do |child|
16101
- child_namespace = ruby_entrypoint_module_namespace_for(child, current)
16361
+ child_namespace = ruby_entrypoint_module_namespace_for(child, current, expected_depth: expected_depth)
16102
16362
  return child_namespace if child_namespace
16103
16363
  end
16104
- current.join("::") unless current.empty?
16364
+ current.join("::") unless expected_depth || current.empty?
16105
16365
  end
16106
16366
 
16107
16367
  def read_project_file(project_root, relative_path)
@@ -19554,11 +19814,11 @@ module Kettle
19554
19814
  "actions/upload-artifact" => "actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1",
19555
19815
  "amancevice/setup-code-climate" => "amancevice/setup-code-climate@0daf2985a225e8ac15975b4d233010e94d65b76a # v2",
19556
19816
  "actions/dependency-review-action" => "actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0",
19557
- "github/codeql-action/init" => "github/codeql-action/init@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8",
19558
- "github/codeql-action/autobuild" => "github/codeql-action/autobuild@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8",
19559
- "github/codeql-action/analyze" => "github/codeql-action/analyze@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8",
19817
+ "github/codeql-action/init" => "github/codeql-action/init@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9",
19818
+ "github/codeql-action/autobuild" => "github/codeql-action/autobuild@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9",
19819
+ "github/codeql-action/analyze" => "github/codeql-action/analyze@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9",
19560
19820
  "pozil/auto-assign-issue" => "pozil/auto-assign-issue@af6beea6bdf1e8eb373f061c5bc168681fc6d011 # v4.0.1",
19561
- "apache/skywalking-eyes/dependency" => "apache/skywalking-eyes/dependency@61275cc80d0798a405cb070f7d3a8aaf7cf2c2c1 # v0.8.0",
19821
+ "apache/skywalking-eyes/dependency" => "apache/skywalking-eyes/dependency@a196742f472feaffafea537ce5a2a4c3c53a8de4 # v0.9.0",
19562
19822
  "sarisia/actions-status-discord" => "sarisia/actions-status-discord@eb045afee445dc055c18d3d90bd0f244fd062708 # v1.16.0"
19563
19823
  }
19564
19824
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kettle-jem
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.1.7
4
+ version: 7.1.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter H. Boling
@@ -676,7 +676,7 @@ dependencies:
676
676
  version: '2.0'
677
677
  - - ">="
678
678
  - !ruby/object:Gem::Version
679
- version: 2.0.20
679
+ version: 2.0.21
680
680
  type: :development
681
681
  prerelease: false
682
682
  version_requirements: !ruby/object:Gem::Requirement
@@ -686,7 +686,7 @@ dependencies:
686
686
  version: '2.0'
687
687
  - - ">="
688
688
  - !ruby/object:Gem::Version
689
- version: 2.0.20
689
+ version: 2.0.21
690
690
  - !ruby/object:Gem::Dependency
691
691
  name: turbo_tests2
692
692
  requirement: !ruby/object:Gem::Requirement
@@ -976,10 +976,10 @@ licenses:
976
976
  - PolyForm-Small-Business-1.0.0
977
977
  metadata:
978
978
  homepage_uri: https://structuredmerge.org
979
- source_code_uri: https://github.com/structuredmerge/structuredmerge-ruby/tree/v7.1.7
980
- changelog_uri: https://github.com/structuredmerge/structuredmerge-ruby/blob/v7.1.7/CHANGELOG.md
979
+ source_code_uri: https://github.com/structuredmerge/structuredmerge-ruby/tree/v7.1.10
980
+ changelog_uri: https://github.com/structuredmerge/structuredmerge-ruby/blob/v7.1.10/CHANGELOG.md
981
981
  bug_tracker_uri: https://github.com/structuredmerge/structuredmerge-ruby/issues
982
- documentation_uri: https://www.rubydoc.info/gems/kettle-jem/7.1.7
982
+ documentation_uri: https://www.rubydoc.info/gems/kettle-jem/7.1.10
983
983
  funding_uri: https://github.com/sponsors/pboling
984
984
  wiki_uri: https://github.com/structuredmerge/structuredmerge-ruby/wiki
985
985
  news_uri: https://www.railsbling.com/tags/kettle-jem
metadata.gz.sig CHANGED
Binary file