kettle-jem 7.0.0 → 7.1.3
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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +1505 -0
- data/LICENSE.md +13 -0
- data/README.md +794 -0
- data/exe/kettle-jem +20 -0
- data/lib/kettle/jem/cli.rb +334 -0
- data/lib/kettle/jem/license_txt_migrator.rb +33 -0
- data/lib/kettle/jem/rakelib/install.rake +10 -0
- data/lib/kettle/jem/rakelib/prepare.rake +10 -0
- data/lib/kettle/jem/rakelib/selftest.rake +10 -0
- data/lib/kettle/jem/rakelib/template.rake +10 -0
- data/lib/kettle/jem/tasks/install_task.rb +2178 -0
- data/lib/kettle/jem/tasks/prepare_task.rb +274 -0
- data/lib/kettle/jem/tasks/self_test_task.rb +256 -0
- data/lib/kettle/jem/tasks/template_task.rb +124 -0
- data/lib/kettle/jem/tasks.rb +6 -0
- data/lib/kettle/jem/templates/.aiignore.example +19 -0
- data/lib/kettle/jem/templates/.config/mise/env.sh +26 -0
- data/lib/kettle/jem/templates/.devcontainer/apt-install/devcontainer-feature.json.example +9 -0
- data/lib/kettle/jem/templates/.devcontainer/apt-install/install.sh.example +19 -0
- data/lib/kettle/jem/templates/.devcontainer/devcontainer.json.example +27 -0
- data/lib/kettle/jem/templates/.devcontainer/scripts/setup-tree-sitter.sh.example +210 -0
- data/lib/kettle/jem/templates/.env.local.example +67 -0
- data/lib/kettle/jem/templates/.envrc.example +4 -0
- data/lib/kettle/jem/templates/.envrc.no-osc.example +4 -0
- data/lib/kettle/jem/templates/.gemrc.example +1 -0
- data/lib/kettle/jem/templates/.git-hooks/commit-msg.example +60 -0
- data/lib/kettle/jem/templates/.git-hooks/commit-subjects-goalie.txt.example +8 -0
- data/lib/kettle/jem/templates/.git-hooks/footer-template.erb.txt.example +16 -0
- data/lib/kettle/jem/templates/.git-hooks/prepare-commit-msg.example +9 -0
- data/lib/kettle/jem/templates/.github/.codecov.yml.example +14 -0
- data/lib/kettle/jem/templates/.github/FUNDING.yml.example +10 -0
- data/lib/kettle/jem/templates/.github/FUNDING.yml.no-osc.example +10 -0
- data/lib/kettle/jem/templates/.github/copilot_instructions.md.example +1 -0
- data/lib/kettle/jem/templates/.github/dependabot.yml.example +13 -0
- data/lib/kettle/jem/templates/.github/workflows/auto-assign.yml.example +21 -0
- data/lib/kettle/jem/templates/.github/workflows/coverage.yml.example +102 -0
- data/lib/kettle/jem/templates/.github/workflows/current.yml.example +86 -0
- data/lib/kettle/jem/templates/.github/workflows/dep-heads.yml.example +249 -0
- data/lib/kettle/jem/templates/.github/workflows/dependency-review.yml.example +22 -0
- data/lib/kettle/jem/templates/.github/workflows/discord-notifier.yml.example +39 -0
- data/lib/kettle/jem/templates/.github/workflows/framework-ci.yml.example +81 -0
- data/lib/kettle/jem/templates/.github/workflows/heads.yml.example +212 -0
- data/lib/kettle/jem/templates/.github/workflows/jruby-10.0.yml.example +91 -0
- data/lib/kettle/jem/templates/.github/workflows/jruby-9.1.yml.example +90 -0
- data/lib/kettle/jem/templates/.github/workflows/jruby-9.2.yml.example +95 -0
- data/lib/kettle/jem/templates/.github/workflows/jruby-9.3.yml.example +95 -0
- data/lib/kettle/jem/templates/.github/workflows/jruby-9.4.yml.example +95 -0
- data/lib/kettle/jem/templates/.github/workflows/jruby.yml.example +91 -0
- data/lib/kettle/jem/templates/.github/workflows/license-eye.yml.example +43 -0
- data/lib/kettle/jem/templates/.github/workflows/locked_deps.yml.example +89 -0
- data/lib/kettle/jem/templates/.github/workflows/opencollective.yml.example +44 -0
- data/lib/kettle/jem/templates/.github/workflows/ruby-2.3.yml.example +80 -0
- data/lib/kettle/jem/templates/.github/workflows/ruby-2.4.yml.example +84 -0
- data/lib/kettle/jem/templates/.github/workflows/ruby-2.5.yml.example +84 -0
- data/lib/kettle/jem/templates/.github/workflows/ruby-2.6.yml.example +84 -0
- data/lib/kettle/jem/templates/.github/workflows/ruby-2.7.yml.example +84 -0
- data/lib/kettle/jem/templates/.github/workflows/ruby-3.0.yml.example +85 -0
- data/lib/kettle/jem/templates/.github/workflows/ruby-3.1.yml.example +83 -0
- data/lib/kettle/jem/templates/.github/workflows/ruby-3.2.yml.example +80 -0
- data/lib/kettle/jem/templates/.github/workflows/ruby-3.3.yml.example +80 -0
- data/lib/kettle/jem/templates/.github/workflows/ruby-3.4.yml.example +80 -0
- data/lib/kettle/jem/templates/.github/workflows/style.yml.example +78 -0
- data/lib/kettle/jem/templates/.github/workflows/templating.yml.example +86 -0
- data/lib/kettle/jem/templates/.github/workflows/truffle.yml.example +91 -0
- data/lib/kettle/jem/templates/.github/workflows/truffleruby-22.3.yml.example +92 -0
- data/lib/kettle/jem/templates/.github/workflows/truffleruby-23.0.yml.example +92 -0
- data/lib/kettle/jem/templates/.github/workflows/truffleruby-23.1.yml.example +78 -0
- data/lib/kettle/jem/templates/.github/workflows/truffleruby-24.2.yml.example +91 -0
- data/lib/kettle/jem/templates/.github/workflows/truffleruby-25.0.yml.example +96 -0
- data/lib/kettle/jem/templates/.github/workflows/truffleruby-33.0.yml.example +91 -0
- data/lib/kettle/jem/templates/.github/workflows/unlocked_deps.yml.example +93 -0
- data/lib/kettle/jem/templates/.gitignore.example +53 -0
- data/lib/kettle/jem/templates/.gitlab-ci.yml.example +134 -0
- data/lib/kettle/jem/templates/.idea/.gitignore.example +44 -0
- data/lib/kettle/jem/templates/.licenserc.yaml.example +8 -0
- data/lib/kettle/jem/templates/.opencollective.yml.example +3 -0
- data/lib/kettle/jem/templates/.qlty/qlty.toml.example +79 -0
- data/lib/kettle/jem/templates/.rspec.example +10 -0
- data/lib/kettle/jem/templates/.rubocop.example +1 -0
- data/lib/kettle/jem/templates/.rubocop.yml.example +47 -0
- data/lib/kettle/jem/templates/.rubocop_rspec.yml.example +55 -0
- data/lib/kettle/jem/templates/.simplecov.example +18 -0
- data/lib/kettle/jem/templates/.structuredmerge/git-drivers.toml.example +86 -0
- data/lib/kettle/jem/templates/.structuredmerge/kettle-jem.yml.example +519 -0
- data/lib/kettle/jem/templates/.yard-lint.yml.example +54 -0
- data/lib/kettle/jem/templates/.yardignore.example +13 -0
- data/lib/kettle/jem/templates/.yardopts.example +14 -0
- data/lib/kettle/jem/templates/AGENTS.md.example +283 -0
- data/lib/kettle/jem/templates/AGPL-3.0-only.md.example +235 -0
- data/lib/kettle/jem/templates/Appraisal.root.gemfile.example +26 -0
- data/lib/kettle/jem/templates/Appraisals.example +150 -0
- data/lib/kettle/jem/templates/Big-Time-Public-License.md.example +99 -0
- data/lib/kettle/jem/templates/CHANGELOG.md.example +33 -0
- data/lib/kettle/jem/templates/CHANGELOG.transfer.md +109 -0
- data/lib/kettle/jem/templates/CITATION.cff.example +20 -0
- data/lib/kettle/jem/templates/CODE_OF_CONDUCT.md.example +134 -0
- data/lib/kettle/jem/templates/CONTRIBUTING.md.example +292 -0
- data/lib/kettle/jem/templates/FUNDING.md.example +74 -0
- data/lib/kettle/jem/templates/FUNDING.md.no-osc.example +63 -0
- data/lib/kettle/jem/templates/Gemfile.example +52 -0
- data/lib/kettle/jem/templates/IRP.md.example +34 -0
- data/lib/kettle/jem/templates/LICENSE.md.example +3 -0
- data/lib/kettle/jem/templates/MIT.md.example +21 -0
- data/lib/kettle/jem/templates/PolyForm-Noncommercial-1.0.0.md.example +131 -0
- data/lib/kettle/jem/templates/PolyForm-Small-Business-1.0.0.md.example +121 -0
- data/lib/kettle/jem/templates/README.md.example +544 -0
- data/lib/kettle/jem/templates/REEK +0 -0
- data/lib/kettle/jem/templates/RUBOCOP.md.example +78 -0
- data/lib/kettle/jem/templates/Rakefile.example +163 -0
- data/lib/kettle/jem/templates/SECURITY.md.example +21 -0
- data/lib/kettle/jem/templates/bin/setup.example +36 -0
- data/lib/kettle/jem/templates/certs/pboling.pem.example +27 -0
- data/lib/kettle/jem/templates/gem.gemspec.example +161 -0
- data/lib/kettle/jem/templates/gemfiles/modular/benchmark/r4/v0.5.gemfile.example +2 -0
- data/lib/kettle/jem/templates/gemfiles/modular/benchmark/vHEAD.gemfile.example +2 -0
- data/lib/kettle/jem/templates/gemfiles/modular/cgi/r4/v0.5.gemfile.example +1 -0
- data/lib/kettle/jem/templates/gemfiles/modular/cgi/vHEAD.gemfile.example +1 -0
- data/lib/kettle/jem/templates/gemfiles/modular/changelog.gemfile.example +6 -0
- data/lib/kettle/jem/templates/gemfiles/modular/coverage.gemfile.example +14 -0
- data/lib/kettle/jem/templates/gemfiles/modular/coverage_local.gemfile.example +34 -0
- data/lib/kettle/jem/templates/gemfiles/modular/debug.gemfile.example +22 -0
- data/lib/kettle/jem/templates/gemfiles/modular/documentation.gemfile.example +24 -0
- data/lib/kettle/jem/templates/gemfiles/modular/documentation_local.gemfile.example +20 -0
- data/lib/kettle/jem/templates/gemfiles/modular/erb/r2/v3.0.gemfile.example +1 -0
- data/lib/kettle/jem/templates/gemfiles/modular/erb/r2.3/default.gemfile.example +6 -0
- data/lib/kettle/jem/templates/gemfiles/modular/erb/r2.6/v2.2.gemfile.example +3 -0
- data/lib/kettle/jem/templates/gemfiles/modular/erb/r3/v5.0.gemfile.example +1 -0
- data/lib/kettle/jem/templates/gemfiles/modular/erb/r3.1/v4.0.gemfile.example +2 -0
- data/lib/kettle/jem/templates/gemfiles/modular/erb/r4/v5.0.gemfile.example +1 -0
- data/lib/kettle/jem/templates/gemfiles/modular/erb/vHEAD.gemfile.example +2 -0
- data/lib/kettle/jem/templates/gemfiles/modular/json/truffleruby_22_3.gemfile.example +6 -0
- data/lib/kettle/jem/templates/gemfiles/modular/json/truffleruby_23_0.gemfile.example +6 -0
- data/lib/kettle/jem/templates/gemfiles/modular/json/truffleruby_23_1.gemfile.example +6 -0
- data/lib/kettle/jem/templates/gemfiles/modular/mutex_m/r2/v0.3.gemfile.example +2 -0
- data/lib/kettle/jem/templates/gemfiles/modular/mutex_m/r2.4/v0.1.gemfile.example +3 -0
- data/lib/kettle/jem/templates/gemfiles/modular/mutex_m/r3/v0.3.gemfile.example +2 -0
- data/lib/kettle/jem/templates/gemfiles/modular/mutex_m/r4/v0.3.gemfile.example +2 -0
- data/lib/kettle/jem/templates/gemfiles/modular/mutex_m/vHEAD.gemfile.example +2 -0
- data/lib/kettle/jem/templates/gemfiles/modular/optional.gemfile.example +16 -0
- data/lib/kettle/jem/templates/gemfiles/modular/recording/r2.3/recording.gemfile.example +16 -0
- data/lib/kettle/jem/templates/gemfiles/modular/recording/r2.4/recording.gemfile.example +18 -0
- data/lib/kettle/jem/templates/gemfiles/modular/recording/r2.5/recording.gemfile.example +16 -0
- data/lib/kettle/jem/templates/gemfiles/modular/recording/r3/recording.gemfile.example +16 -0
- data/lib/kettle/jem/templates/gemfiles/modular/recording/r4/recording.gemfile.example +16 -0
- data/lib/kettle/jem/templates/gemfiles/modular/recording/vHEAD.gemfile.example +2 -0
- data/lib/kettle/jem/templates/gemfiles/modular/rspec.gemfile.example +4 -0
- data/lib/kettle/jem/templates/gemfiles/modular/runtime_heads.gemfile.example +14 -0
- data/lib/kettle/jem/templates/gemfiles/modular/shunted.gemfile.example +21 -0
- data/lib/kettle/jem/templates/gemfiles/modular/stringio/r2/v3.0.gemfile.example +5 -0
- data/lib/kettle/jem/templates/gemfiles/modular/stringio/r2.4/v0.0.2.gemfile.example +4 -0
- data/lib/kettle/jem/templates/gemfiles/modular/stringio/r3/v3.0.gemfile.example +5 -0
- data/lib/kettle/jem/templates/gemfiles/modular/stringio/r4/v3.0.gemfile.example +5 -0
- data/lib/kettle/jem/templates/gemfiles/modular/stringio/vHEAD.gemfile.example +2 -0
- data/lib/kettle/jem/templates/gemfiles/modular/style.gemfile.example +33 -0
- data/lib/kettle/jem/templates/gemfiles/modular/style_local.gemfile.example +26 -0
- data/lib/kettle/jem/templates/gemfiles/modular/templating.gemfile.example +34 -0
- data/lib/kettle/jem/templates/gemfiles/modular/templating_local.gemfile.example +73 -0
- data/lib/kettle/jem/templates/gemfiles/modular/webrick/r4/v1.9.gemfile.example +1 -0
- data/lib/kettle/jem/templates/gemfiles/modular/webrick/vHEAD.gemfile.example +1 -0
- data/lib/kettle/jem/templates/gemfiles/modular/x_std_libs/r2/libs.gemfile.example +3 -0
- data/lib/kettle/jem/templates/gemfiles/modular/x_std_libs/r2.3/libs.gemfile.example +3 -0
- data/lib/kettle/jem/templates/gemfiles/modular/x_std_libs/r2.4/libs.gemfile.example +3 -0
- data/lib/kettle/jem/templates/gemfiles/modular/x_std_libs/r2.6/libs.gemfile.example +3 -0
- data/lib/kettle/jem/templates/gemfiles/modular/x_std_libs/r3/libs.gemfile.example +3 -0
- data/lib/kettle/jem/templates/gemfiles/modular/x_std_libs/r3.1/libs.gemfile.example +5 -0
- data/lib/kettle/jem/templates/gemfiles/modular/x_std_libs/r4/libs.gemfile.example +6 -0
- data/lib/kettle/jem/templates/gemfiles/modular/x_std_libs/vHEAD.gemfile.example +6 -0
- data/lib/kettle/jem/templates/gemfiles/modular/x_std_libs.gemfile.example +12 -0
- data/lib/kettle/jem/templates/lib/gem/version.rb.example +1 -0
- data/lib/kettle/jem/templates/lib/gem/version_gem.rb.example +1 -0
- data/lib/kettle/jem/templates/mise.toml.example +25 -0
- data/lib/kettle/jem/templates/mise.toml.no-osc.example +25 -0
- data/lib/kettle/jem/templates/parsers.toml.example +19 -0
- data/lib/kettle/jem/templates/readme/partials/basic_usage.md.example +28 -0
- data/lib/kettle/jem/templates/readme/partials/configuration.md.example +112 -0
- data/lib/kettle/jem/templates/readme/partials/synopsis.md.example +3 -0
- data/lib/kettle/jem/templates/shim/.github/workflows/current.yml.example +40 -0
- data/lib/kettle/jem/templates/shim/.rspec.example +5 -0
- data/lib/kettle/jem/templates/shim/.structuredmerge/kettle-jem.yml.example +28 -0
- data/lib/kettle/jem/templates/shim/CHANGELOG.md.example +9 -0
- data/lib/kettle/jem/templates/shim/Gemfile.example +14 -0
- data/lib/kettle/jem/templates/shim/README.md.example +25 -0
- data/lib/kettle/jem/templates/shim/Rakefile.example +8 -0
- data/lib/kettle/jem/templates/shim/gem.gemspec.example +45 -0
- data/lib/kettle/jem/templates/shim/lib/compat_require.rb.example +3 -0
- data/lib/kettle/jem/templates/shim/lib/entrypoint.rb.example +3 -0
- data/lib/kettle/jem/templates/shim/lib/version.rb.example +1 -0
- data/lib/kettle/jem/templates/shim/spec/shim_spec.rb.example +15 -0
- data/lib/kettle/jem/templates/shim/spec/spec_helper.rb.example +23 -0
- data/lib/kettle/jem/templates/sig/gem.rbs.example +1 -0
- data/lib/kettle/jem/templates/spec/README.md.example +28 -0
- data/lib/kettle/jem/templates/spec/spec_helper.rb.example +39 -0
- data/lib/kettle/jem/version.rb +5 -3
- data/lib/kettle/jem/version_gem.rb +8 -0
- data/lib/kettle/jem.rb +18540 -1517
- data/lib/kettle-jem.rb +2 -1
- data/sig/kettle/jem.rbs +8 -0
- data.tar.gz.sig +0 -0
- metadata +870 -32
- metadata.gz.sig +0 -0
data/README.md
ADDED
|
@@ -0,0 +1,794 @@
|
|
|
1
|
+
<a href="https://github.com/structuredmerge"><img alt="structuredmerge Logo by GitHub" src="https://github.com/structuredmerge.png?size=192" width="12%" align="right"/></a> <a href="https://github.com/structuredmerge/structuredmerge-ruby/tree/main/gems/kettle-jem"><img alt="kettle-jem Logo by Aboling0, CC BY-SA 4.0" src="https://logos.galtzo.com/assets/images/structuredmerge/structuredmerge-ruby/kettle-jem/avatar-128px.svg" width="12%" align="right"/></a>
|
|
2
|
+
|
|
3
|
+
# 🔮 Kettle::Jem
|
|
4
|
+
|
|
5
|
+
[![Version][👽versioni]][👽version] [![Ruby Users Forum][✉️ruby-forum-top-img]][✉️ruby-forum] [![GitHub tag (latest SemVer)][⛳️tag-img]][⛳️tag] [![License: AGPL-3.0-only OR PolyForm-Small-Business-1.0.0][📄license-img]][📄license] [![Total downloads][👽dl-ranki]][👽dl-rank] [![CI Current][🚎11-c-wfi]][🚎11-c-wf]
|
|
6
|
+
|
|
7
|
+
`if ci_badges.map(&:color).detect { it != "green"}` ☝️ [let me know on Discord][✉️discord-invite] or [RubyForum][✉️ruby-forum], as I may have missed the notification.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
`if ci_badges.map(&:color).all? { it == "green"}` 👇️ send money so I can do more of this. FLOSS maintenance is now my full-time job.
|
|
12
|
+
|
|
13
|
+
[![Sponsor Me on Github][🖇sponsor-img]][🖇sponsor] [![Liberapay Goal Progress][⛳liberapay-img]][⛳liberapay] [![Donate on PayPal][🖇paypal-img]][🖇paypal] [![Buy me a coffee][🖇buyme-small-img]][🖇buyme] [![Donate at ko-fi.com][🖇kofi-img]][🖇kofi]
|
|
14
|
+
|
|
15
|
+
<details markdown="1">
|
|
16
|
+
<summary>👣 How will this project approach the September 2025 hostile takeover of RubyGems? 🚑️</summary>
|
|
17
|
+
|
|
18
|
+
I've summarized my thoughts in [this blog post](https://dev.to/galtzo/hostile-takeover-of-rubygems-my-thoughts-5hlo).
|
|
19
|
+
|
|
20
|
+
</details>
|
|
21
|
+
|
|
22
|
+
## 🌻 Synopsis <a href="https://discord.gg/3qme4XHNKN"><img alt="Galtzo FLOSS Logo by Aboling0, CC BY-SA 4.0" src="https://logos.galtzo.com/assets/images/galtzo-floss/avatar-128px.svg" width="8%" align="right"/></a> <a href="https://ruby-toolbox.com"><img alt="ruby-lang Logo, Yukihiro Matsumoto, Ruby Visual Identity Team, CC BY-SA 2.5" src="https://logos.galtzo.com/assets/images/ruby-lang/avatar-128px.svg" width="8%" align="right"/></a>
|
|
23
|
+
|
|
24
|
+
Kettle::Jem is an AST-aware gem templating system that keeps hundreds of Ruby gems
|
|
25
|
+
in sync with a shared template while preserving each project's customizations.
|
|
26
|
+
Unlike line-based copy/merge tools, Kettle::Jem understands the *structure* of
|
|
27
|
+
every file it touches — Ruby via Prism, YAML via Psych, Markdown via Markly,
|
|
28
|
+
TOML via tree-sitter, and more — so template updates land precisely where they
|
|
29
|
+
belong, and project-specific additions are never clobbered.
|
|
30
|
+
|
|
31
|
+
Plugin authors can now use the dedicated [plugin authoring guide](KETTLE_JEM_PLUGINS.md)
|
|
32
|
+
to build `kettle-jem` extension gems against the supported plugin seam.
|
|
33
|
+
|
|
34
|
+
### Key Features
|
|
35
|
+
|
|
36
|
+
- **AST-aware merging** — 10 format-specific merge engines (prism, psych, markly, toml, json, jsonc, json5, bash, dotenv, rbs, text)
|
|
37
|
+
- **Token substitution** — `{KJ|TOKEN}` patterns resolved from config, ENV, or auto-derived from gemspec
|
|
38
|
+
- **Freeze blocks** — protect any section from template overwrites with `# kettle-jem:freeze` / `# kettle-jem:unfreeze`
|
|
39
|
+
- **Per-file strategies** — `merge`, `accept_template`, `keep_destination`, or `raw_copy`
|
|
40
|
+
- **Multi-phase pipeline** — 11 ordered phases (service_actor-based) from config sync through duplicate checking
|
|
41
|
+
- **SHA-pinned GitHub Actions** — template `uses:` always wins, propagating immutable SHAs
|
|
42
|
+
- **Convergence in one pass** — a single `kettle-jem install` applies all changes; a second run produces zero diff
|
|
43
|
+
- **Selftest divergence check** — CI verifies that project drift stays within a configurable threshold
|
|
44
|
+
|
|
45
|
+
## 💡 Info you can shake a stick at
|
|
46
|
+
|
|
47
|
+
| Tokens to Remember | [![Gem name][⛳️name-img]][⛳️gem-name] [![Gem namespace][⛳️namespace-img]][⛳️gem-namespace] |
|
|
48
|
+
|-------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
49
|
+
| Works with MRI Ruby 4 | [![Ruby current Compat][💎ruby-c-i]][🚎11-c-wf]|
|
|
50
|
+
| Support & Community | [![Join Me on Daily.dev's RubyFriends][✉️ruby-friends-img]][✉️ruby-friends] [![Get help from RubyForum][✉️ruby-forum-img]][✉️ruby-forum] [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite] [![Get help from me on Upwork][👨🏼🏫expsup-upwork-img]][👨🏼🏫expsup-upwork] [![Get help from me on Codementor][👨🏼🏫expsup-codementor-img]][👨🏼🏫expsup-codementor] |
|
|
51
|
+
| Source | [![Source on GitLab.com][📜src-gl-img]][📜src-gl] [![Source on CodeBerg.org][📜src-cb-img]][📜src-cb] [![Source on GitHub.com][📜src-gh-img]][📜src-gh] [![The best SHA: dQw4w9WgXcQ!][🧮kloc-img]][🧮kloc] |
|
|
52
|
+
| Documentation | [![Current release on RubyDoc.info][📜docs-cr-rd-img]][🚎yard-current] [![YARD on Galtzo.com][📜docs-head-rd-img]][🚎yard-head] [![Maintainer Blog][🚂maint-blog-img]][🚂maint-blog] [![GitLab Wiki][📜gl-wiki-img]][📜gl-wiki] [![GitHub Wiki][📜gh-wiki-img]][📜gh-wiki] |
|
|
53
|
+
| Compliance | [![License: AGPL-3.0-only OR PolyForm-Small-Business-1.0.0][📄license-img]][📄license] [![Apache license compatibility: Category X][📄license-compat-img]][📄license-compat] [![📄ilo-declaration-img]][📄ilo-declaration] [![Security Policy][🔐security-img]][🔐security] [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct] [![SemVer 2.0.0][📌semver-img]][📌semver] |
|
|
54
|
+
| Style | [![Enforced Code Style Linter][💎rlts-img]][💎rlts] [![Keep-A-Changelog 1.0.0][📗keep-changelog-img]][📗keep-changelog] [![Gitmoji Commits][📌gitmoji-img]][📌gitmoji] [![Compatibility appraised by: appraisal2][💎appraisal2-img]][💎appraisal2] |
|
|
55
|
+
| Maintainer 🎖️ | [![Follow Me on LinkedIn][💖🖇linkedin-img]][💖🖇linkedin] [![Follow Me on Ruby.Social][💖🐘ruby-mast-img]][💖🐘ruby-mast] [![Follow Me on Bluesky][💖🦋bluesky-img]][💖🦋bluesky] [![Contact Maintainer][🚂maint-contact-img]][🚂maint-contact] [![My technical writing][💖💁🏼♂️devto-img]][💖💁🏼♂️devto] |
|
|
56
|
+
| `...` 💖 | [![Find Me on WellFound:][💖✌️wellfound-img]][💖✌️wellfound] [![Find Me on CrunchBase][💖💲crunchbase-img]][💖💲crunchbase] [![My LinkTree][💖🌳linktree-img]][💖🌳linktree] [![More About Me][💖💁🏼♂️aboutme-img]][💖💁🏼♂️aboutme] [🧊][💖🧊berg] [🐙][💖🐙hub] [🛖][💖🛖hut] [🧪][💖🧪lab] |
|
|
57
|
+
|
|
58
|
+
### Compatibility
|
|
59
|
+
|
|
60
|
+
Compatible with MRI Ruby 4.0.0+, and JRuby.
|
|
61
|
+
CI workflows and Appraisals are generated for MRI Ruby 4.0.0+.
|
|
62
|
+
This test floor is configured by `ruby.test_minimum` in `.kettle-jem.yml` and
|
|
63
|
+
may be higher than the gem's runtime compatibility floor when legacy Rubies are
|
|
64
|
+
not practical for the current toolchain.
|
|
65
|
+
|
|
66
|
+
<a href="https://github.com/kettle-dev"><img alt="kettle-dev Logo by Aboling0, CC BY-SA 4.0" src="https://logos.galtzo.com/assets/images/kettle-dev/avatar-128px.svg" width="14%" align="right"/></a>
|
|
67
|
+
|
|
68
|
+
The _amazing_ test matrix is powered by the kettle-dev stack.
|
|
69
|
+
|
|
70
|
+
<details markdown="1">
|
|
71
|
+
<summary>How kettle-dev manages complexity in tests</summary>
|
|
72
|
+
|
|
73
|
+
| Gem | Source | Role | Total downloads |
|
|
74
|
+
|-----|--------|------|---------------------|
|
|
75
|
+
| [appraisal2](https://clickgems.clickhouse.com/dashboard/appraisal2) | [GitHub](https://github.com/appraisal-rb/appraisal2) | multi-dependency Appraisal matrix generation | [](https://clickgems.clickhouse.com/dashboard/appraisal2) |
|
|
76
|
+
| [appraisal2-rubocop](https://clickgems.clickhouse.com/dashboard/appraisal2-rubocop) | [GitHub](https://github.com/appraisal-rb/appraisal2-rubocop) | RuboCop Appraisal generator integration | [](https://clickgems.clickhouse.com/dashboard/appraisal2-rubocop) |
|
|
77
|
+
| [kettle-dev](https://clickgems.clickhouse.com/dashboard/kettle-dev) | [GitHub](https://github.com/kettle-dev/kettle-dev) | development, release, and CI workflow tooling | [](https://clickgems.clickhouse.com/dashboard/kettle-dev) |
|
|
78
|
+
| [kettle-soup-cover](https://clickgems.clickhouse.com/dashboard/kettle-soup-cover) | [GitHub](https://github.com/kettle-dev/kettle-soup-cover) | SimpleCov coverage policy and reporting | [](https://clickgems.clickhouse.com/dashboard/kettle-soup-cover) |
|
|
79
|
+
| [kettle-test](https://clickgems.clickhouse.com/dashboard/kettle-test) | [GitHub](https://github.com/kettle-dev/kettle-test) | standard test runner and coverage harness | [](https://clickgems.clickhouse.com/dashboard/kettle-test) |
|
|
80
|
+
| [rubocop-lts](https://clickgems.clickhouse.com/dashboard/rubocop-lts) | [GitHub](https://github.com/rubocop-lts/rubocop-lts) | Ruby-version-aware linting | [](https://clickgems.clickhouse.com/dashboard/rubocop-lts) |
|
|
81
|
+
| [turbo_tests2](https://clickgems.clickhouse.com/dashboard/turbo_tests2) | [GitHub](https://github.com/galtzo-floss/turbo_tests2) | parallel test execution | [](https://clickgems.clickhouse.com/dashboard/turbo_tests2) |
|
|
82
|
+
|
|
83
|
+
</details>
|
|
84
|
+
|
|
85
|
+
<details markdown="1">
|
|
86
|
+
<summary>StructuredMerge package family</summary>
|
|
87
|
+
|
|
88
|
+
This gem is part of the StructuredMerge Ruby package family. The implementation inventory, layering model, and backend notes live in the [root package-family guide][sm-family-guide]. Shared behavior is defined by the [StructuredMerge fixtures][sm-family-fixtures] and implemented by the [Go][sm-family-go], [Ruby][sm-family-ruby], [Rust][sm-family-rust], and [TypeScript][sm-family-typescript] repositories.
|
|
89
|
+
|
|
90
|
+
Merge analysis must enter parsing through `tree_haver`. Parser-specific gems register concrete TreeHaver backends; substrate gems register grammar mappings and keep shared format or language merge behavior in one place. Missing backends fail closed instead of falling back to direct parser-library calls.
|
|
91
|
+
|
|
92
|
+
</details>
|
|
93
|
+
|
|
94
|
+
[sm-family-guide]: https://github.com/structuredmerge/structuredmerge-ruby#package-family
|
|
95
|
+
[sm-family-fixtures]: https://github.com/structuredmerge/structuredmerge-fixtures
|
|
96
|
+
[sm-family-go]: https://github.com/structuredmerge/structuredmerge-go
|
|
97
|
+
[sm-family-ruby]: https://github.com/structuredmerge/structuredmerge-ruby
|
|
98
|
+
[sm-family-rust]: https://github.com/structuredmerge/structuredmerge-rust
|
|
99
|
+
[sm-family-typescript]: https://github.com/structuredmerge/structuredmerge-typescript
|
|
100
|
+
|
|
101
|
+
### Federated DVCS
|
|
102
|
+
|
|
103
|
+
<details markdown="1">
|
|
104
|
+
<summary>Find this repo on federated forges (Coming soon!)</summary>
|
|
105
|
+
|
|
106
|
+
| Federated [DVCS][💎d-in-dvcs] Repository | Status | Issues | PRs | Wiki | CI |
|
|
107
|
+
|-------------------------------------------------|-------------------------------------------|-------------------|------------------|-----------------|----------------|
|
|
108
|
+
| 🧪 [structuredmerge/structuredmerge-ruby on GitLab][📜src-gl] | The Truth | [💚][🤝gl-issues] | [💚][🤝gl-pulls] | [💚][📜gl-wiki] | 🐭 Tiny Matrix |
|
|
109
|
+
| 🧊 [structuredmerge/structuredmerge-ruby on CodeBerg][📜src-cb] | An Ethical Mirror ([Donate][🤝cb-donate]) | [💚][🤝cb-issues] | [💚][🤝cb-pulls] | ➖ | ⭕️ No Matrix |
|
|
110
|
+
| 🐙 [structuredmerge/structuredmerge-ruby on GitHub][📜src-gh] | Another Mirror | [💚][🤝gh-issues] | [💚][🤝gh-pulls] | [💚][📜gh-wiki] | 💯 Full Matrix |
|
|
111
|
+
|
|
112
|
+
</details>
|
|
113
|
+
|
|
114
|
+
### Enterprise Support [](https://tidelift.com/subscription/pkg/rubygems-kettle-jem?utm_source=rubygems-kettle-jem&utm_medium=referral&utm_campaign=readme)
|
|
115
|
+
|
|
116
|
+
Available as part of the Tidelift Subscription.
|
|
117
|
+
|
|
118
|
+
<details markdown="1">
|
|
119
|
+
<summary>Need enterprise-level guarantees?</summary>
|
|
120
|
+
|
|
121
|
+
The maintainers of this and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use.
|
|
122
|
+
|
|
123
|
+
[![Get help from me on Tidelift][🏙️entsup-tidelift-img]][🏙️entsup-tidelift]
|
|
124
|
+
|
|
125
|
+
- 💡Subscribe for support guarantees covering _all_ your FLOSS dependencies
|
|
126
|
+
- 💡Tidelift is part of [Sonar][🏙️entsup-tidelift-sonar]
|
|
127
|
+
- 💡Tidelift pays maintainers to maintain the software you depend on!<br/>📊`@`Pointy Haired Boss: An [enterprise support][🏙️entsup-tidelift] subscription is "[never gonna let you down][🧮kloc]", and *supports* open source maintainers
|
|
128
|
+
|
|
129
|
+
Alternatively:
|
|
130
|
+
|
|
131
|
+
- [![Ruby Users Forum][✉️ruby-forum-img]][✉️ruby-forum]
|
|
132
|
+
- [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite]
|
|
133
|
+
- [![Get help from me on Upwork][👨🏼🏫expsup-upwork-img]][👨🏼🏫expsup-upwork]
|
|
134
|
+
- [![Get help from me on Codementor][👨🏼🏫expsup-codementor-img]][👨🏼🏫expsup-codementor]
|
|
135
|
+
|
|
136
|
+
</details>
|
|
137
|
+
|
|
138
|
+
## ✨ Installation
|
|
139
|
+
|
|
140
|
+
Install the gem and add to the application's Gemfile by executing:
|
|
141
|
+
|
|
142
|
+
```console
|
|
143
|
+
bundle add kettle-jem
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
If bundler is not being used to manage dependencies, install the gem by executing:
|
|
147
|
+
|
|
148
|
+
```console
|
|
149
|
+
gem install kettle-jem
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## ⚙️ Configuration
|
|
153
|
+
|
|
154
|
+
Each gem that uses Kettle::Jem has a `.kettle-jem.yml` file at its root. This file controls
|
|
155
|
+
every aspect of how the template is applied.
|
|
156
|
+
|
|
157
|
+
### Minimal Configuration
|
|
158
|
+
|
|
159
|
+
```yaml
|
|
160
|
+
project_emoji: "🔮"
|
|
161
|
+
engines:
|
|
162
|
+
- ruby
|
|
163
|
+
licenses:
|
|
164
|
+
- MIT
|
|
165
|
+
tokens:
|
|
166
|
+
forge:
|
|
167
|
+
gh_user: "your-username"
|
|
168
|
+
author:
|
|
169
|
+
name: "Your Name"
|
|
170
|
+
email: "you@example.com"
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Full Configuration Reference
|
|
174
|
+
|
|
175
|
+
```yaml
|
|
176
|
+
# REQUIRED — unique emoji used in badges and gemspec summary
|
|
177
|
+
project_emoji: "🔮" # ENV override: KJ_PROJECT_EMOJI
|
|
178
|
+
|
|
179
|
+
# Ruby engines to include in CI matrix (remove to skip)
|
|
180
|
+
engines:
|
|
181
|
+
- ruby
|
|
182
|
+
- jruby
|
|
183
|
+
- truffleruby
|
|
184
|
+
|
|
185
|
+
# The generated direct dependency-heads workflow derives its Bundler lockfile
|
|
186
|
+
# platform from `engines`. JRuby gets an isolated temporary lockfile with the
|
|
187
|
+
# `universal-java` platform; MRI and TruffleRuby use the checked-in lock
|
|
188
|
+
# context. This avoids making one shared lockfile satisfy incompatible engine
|
|
189
|
+
# platforms.
|
|
190
|
+
|
|
191
|
+
# SPDX license identifiers
|
|
192
|
+
licenses:
|
|
193
|
+
- MIT
|
|
194
|
+
|
|
195
|
+
# Logo layout in README header: org | project | org_and_project
|
|
196
|
+
readme:
|
|
197
|
+
top_logo_mode: org
|
|
198
|
+
|
|
199
|
+
# Bot accounts to exclude from contributor lists
|
|
200
|
+
machine_users:
|
|
201
|
+
- dependabot
|
|
202
|
+
|
|
203
|
+
# Maximum allowed divergence (%) for selftest CI check
|
|
204
|
+
min_divergence_threshold: 5 # ENV override: KJ_MIN_DIVERGENCE_THRESHOLD
|
|
205
|
+
|
|
206
|
+
# Default merge behavior applied to all files
|
|
207
|
+
defaults:
|
|
208
|
+
preference: "template" # template | destination
|
|
209
|
+
add_template_only_nodes: true # add nodes that only exist in template
|
|
210
|
+
freeze_token: "kettle-jem" # marker for frozen sections
|
|
211
|
+
|
|
212
|
+
# Token values for {KJ|TOKEN} substitution
|
|
213
|
+
tokens:
|
|
214
|
+
forge:
|
|
215
|
+
gh_user: "github-username" # ENV override: KJ_GH_USER
|
|
216
|
+
gl_user: "gitlab-username" # ENV override: KJ_GL_USER
|
|
217
|
+
cb_user: "codeberg-username" # ENV override: KJ_CB_USER
|
|
218
|
+
sh_user: "sourcehut-user" # ENV override: KJ_SH_USER
|
|
219
|
+
author:
|
|
220
|
+
name: "Full Name" # ENV override: KJ_AUTHOR_NAME
|
|
221
|
+
given_names: "Full" # ENV override: KJ_AUTHOR_GIVEN_NAMES
|
|
222
|
+
family_names: "Name" # ENV override: KJ_AUTHOR_FAMILY_NAMES
|
|
223
|
+
email: "you@example.com" # ENV override: KJ_AUTHOR_EMAIL
|
|
224
|
+
domain: "example.com" # ENV override: KJ_AUTHOR_DOMAIN
|
|
225
|
+
orcid: "0000-0000-0000-0000" # ENV override: KJ_AUTHOR_ORCID
|
|
226
|
+
funding:
|
|
227
|
+
kofi: "username" # ENV override: KJ_FUNDING_KOFI
|
|
228
|
+
paypal: "username" # ENV override: KJ_FUNDING_PAYPAL
|
|
229
|
+
buymeacoffee: "username" # ENV override: KJ_FUNDING_BUYMEACOFFEE
|
|
230
|
+
liberapay: "username" # ENV override: KJ_FUNDING_LIBERAPAY
|
|
231
|
+
social:
|
|
232
|
+
mastodon: "username" # ENV override: KJ_SOCIAL_MASTODON
|
|
233
|
+
bluesky: "user.bsky.social" # ENV override: KJ_SOCIAL_BLUESKY
|
|
234
|
+
linktree: "username" # ENV override: KJ_SOCIAL_LINKTREE
|
|
235
|
+
devto: "username" # ENV override: KJ_SOCIAL_DEVTO
|
|
236
|
+
|
|
237
|
+
# Glob-based overrides (first match wins)
|
|
238
|
+
patterns:
|
|
239
|
+
- path: "certs/**"
|
|
240
|
+
strategy: raw_copy
|
|
241
|
+
|
|
242
|
+
# Per-file overrides
|
|
243
|
+
files:
|
|
244
|
+
Rakefile:
|
|
245
|
+
strategy: merge
|
|
246
|
+
preference: destination # preserve local tasks
|
|
247
|
+
AGENTS.md:
|
|
248
|
+
strategy: accept_template # always use template version
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Framework Matrix vs. Appraisals
|
|
252
|
+
|
|
253
|
+
`workflows.preset: framework` and `workflows.framework_matrix` are meant for a
|
|
254
|
+
simple 2D matrix: **Ruby versions × one framework gem/version axis**. This is a
|
|
255
|
+
good fit when you want kettle-jem to generate framework-version modular gemfiles,
|
|
256
|
+
`Appraisals` entries, and CI matrix entries for a single framework dependency.
|
|
257
|
+
|
|
258
|
+
If you need a deeper or more complex matrix, prefer
|
|
259
|
+
**`kettle-jem-appraisals`**, which generates `Appraisals` entries and is the
|
|
260
|
+
better fit for Appraisals-style combinations.
|
|
261
|
+
|
|
262
|
+
### Strategies
|
|
263
|
+
|
|
264
|
+
| Strategy | Behavior |
|
|
265
|
+
|--------------------|-----------------------------------------------------------------------|
|
|
266
|
+
| `merge` | Resolve tokens, then AST-merge template + destination (default) |
|
|
267
|
+
| `accept_template` | Resolve tokens, overwrite destination with template result |
|
|
268
|
+
| `keep_destination` | Skip entirely — no merge, no creation |
|
|
269
|
+
| `raw_copy` | Copy bytes as-is — no token resolution, no merge (for binary assets) |
|
|
270
|
+
|
|
271
|
+
`raw_copy` exists for bootstrap files that may be needed before the full
|
|
272
|
+
templating stack is available. Because it bypasses normal template processing,
|
|
273
|
+
do not use it for templates that contain `{KJ|...}` tokens or require
|
|
274
|
+
StructuredMerge normalization.
|
|
275
|
+
|
|
276
|
+
### Token Substitution
|
|
277
|
+
|
|
278
|
+
Tokens use `{KJ|TOKEN}` syntax and are resolved in priority order:
|
|
279
|
+
|
|
280
|
+
1. **ENV variables** (highest) — e.g., `KJ_AUTHOR_NAME`
|
|
281
|
+
2. **`.kettle-jem.yml` `tokens:` section** — explicit values
|
|
282
|
+
3. **Auto-derived from gemspec** (lowest) — author name, email, domain
|
|
283
|
+
|
|
284
|
+
Common tokens:
|
|
285
|
+
|
|
286
|
+
| Token | Source |
|
|
287
|
+
|------------------------|-----------------------------------|
|
|
288
|
+
| `{KJ\|GEM_NAME}` | Gem name from gemspec |
|
|
289
|
+
| `{KJ\|NAMESPACE}` | Ruby module namespace |
|
|
290
|
+
| `{KJ\|AUTHOR:NAME}` | Author full name |
|
|
291
|
+
| `{KJ\|AUTHOR:EMAIL}` | Author email |
|
|
292
|
+
| `{KJ\|GH:USER}` | GitHub username |
|
|
293
|
+
| `{KJ\|PROJECT_EMOJI}` | Project emoji from config |
|
|
294
|
+
| `{KJ\|MIN_RUBY}` | Minimum Ruby version |
|
|
295
|
+
| `{KJ\|FREEZE_TOKEN}` | Freeze marker name |
|
|
296
|
+
|
|
297
|
+
### Freeze Blocks
|
|
298
|
+
|
|
299
|
+
Protect sections in any file from template overwrites:
|
|
300
|
+
|
|
301
|
+
```ruby
|
|
302
|
+
# kettle-jem:freeze
|
|
303
|
+
gem "my-local-fork", path: "../custom"
|
|
304
|
+
# kettle-jem:unfreeze
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
Content between freeze/unfreeze markers is always preserved from the destination,
|
|
308
|
+
regardless of what the template contains. Works in all supported formats (Ruby, YAML,
|
|
309
|
+
Markdown, TOML, JSON, Bash, etc.).
|
|
310
|
+
|
|
311
|
+
### Merge Engine Selection
|
|
312
|
+
|
|
313
|
+
Kettle::Jem selects the merge engine by file type:
|
|
314
|
+
|
|
315
|
+
| File Pattern | Merge Engine | Key Behaviors |
|
|
316
|
+
|----------------------------------------------------------|---------------|--------------------------------------------|
|
|
317
|
+
| `*.rb`, `Gemfile`, `*.gemspec`, `Rakefile`, `Appraisals` | Prism::Merge | Three-phase matching, gemspec var renaming |
|
|
318
|
+
| `*.yml`, `*.yaml` | Psych::Merge | SHA-pinned `uses:`, per-key preferences |
|
|
319
|
+
| `*.md`, `*.markdown` | Markly::Merge | Heading/list matching, inner list merge |
|
|
320
|
+
| `*.toml` | Toml::Merge | Sort keys, table matching |
|
|
321
|
+
| `*.json` | Json::Merge | Key-based matching |
|
|
322
|
+
| `*.jsonc` | Json::Merge | With comment preservation |
|
|
323
|
+
| `*.json5` | Json::Merge | JSON5 keys, strings, comments, and trailing commas |
|
|
324
|
+
| `*.sh`, `*.bash`, `.envrc` | Bash::Merge | Block matching |
|
|
325
|
+
| `.env*` | Dotenv::Merge | KEY=value matching |
|
|
326
|
+
| `*.rbs` | RBS::Merge | Type signature matching |
|
|
327
|
+
| `.gitignore` | Text::Merge | Intentional line-based merge |
|
|
328
|
+
|
|
329
|
+
> **No silent fallback:** If a tree-sitter grammar is unavailable for a file
|
|
330
|
+
> type that requires AST merging, kettle-jem will **fail** (default) or
|
|
331
|
+
> **skip** the file — never silently degrade to text-based merging.
|
|
332
|
+
> See `PARSE_ERROR_MODE` below.
|
|
333
|
+
|
|
334
|
+
## 🔧 Basic Usage
|
|
335
|
+
|
|
336
|
+
### Initial Setup
|
|
337
|
+
|
|
338
|
+
```bash
|
|
339
|
+
gem install kettle-jem
|
|
340
|
+
cd my-gem
|
|
341
|
+
kettle-jem
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
The setup CLI runs a two-phase bootstrap:
|
|
345
|
+
|
|
346
|
+
1. **Bootstrap** — creates `.kettle-jem.yml`, installs modular gemfiles, ensures dev dependencies
|
|
347
|
+
2. **Bundled** — loads the full runtime and runs `kettle-jem install`
|
|
348
|
+
|
|
349
|
+
### Applying Template Updates
|
|
350
|
+
|
|
351
|
+
After initial setup, re-run the template process to pull in updates:
|
|
352
|
+
|
|
353
|
+
```bash
|
|
354
|
+
K_JEM_TEMPLATING=true bundle exec kettle-jem install
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
This applies all template phases, then runs the local finishing steps such as
|
|
358
|
+
`bin/setup`, curated binstub generation, hooks, and lockfile normalization.
|
|
359
|
+
|
|
360
|
+
| Phase | Description | Files Affected |
|
|
361
|
+
|-------|--------------------------------------|---------------------------------------|
|
|
362
|
+
| 0 | Config sync | `.kettle-jem.yml` |
|
|
363
|
+
| 1 | Dev container | `.devcontainer/` |
|
|
364
|
+
| 2 | GitHub workflows | `.github/workflows/`, `FUNDING.yml` |
|
|
365
|
+
| 3 | Quality config | `.qlty/qlty.toml` |
|
|
366
|
+
| 4 | Modular gemfiles | `gemfiles/modular/` |
|
|
367
|
+
| 5 | Spec helper | `spec/spec_helper.rb` |
|
|
368
|
+
| 6 | Environment templates | `.env.local.example` |
|
|
369
|
+
| 7 | Remaining files | gemspec, README, LICENSE, Rakefile, … |
|
|
370
|
+
| 8 | Git hooks | `.git-hooks/` |
|
|
371
|
+
| 9 | License files | `LICENSE*` |
|
|
372
|
+
| 10 | Duplicate check | _(validation only)_ |
|
|
373
|
+
|
|
374
|
+
Each phase is implemented as a composable [service_actor](https://github.com/sunny/actor)
|
|
375
|
+
actor, enabling per-phase statistics (📄 templates, 🆕 created, 📋 pre-existing,
|
|
376
|
+
🟰 identical, ✏️ changed) and future slice-based workflows.
|
|
377
|
+
|
|
378
|
+
### Checking Divergence
|
|
379
|
+
|
|
380
|
+
CI can verify that a project hasn't drifted too far from the template:
|
|
381
|
+
|
|
382
|
+
```bash
|
|
383
|
+
bundle exec rake kettle:jem:selftest
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
This re-applies the template in a temporary checkout and measures the diff.
|
|
387
|
+
Output is condensed to two summary lines after the template run:
|
|
388
|
+
|
|
389
|
+
```
|
|
390
|
+
[selftest] 📄 Report - tmp/template_test/report/summary.md
|
|
391
|
+
[selftest] ✅ Score: 100.0% · Divergence: 0.0% · Threshold: fail when divergence reaches 5.0%
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
If divergence exceeds `min_divergence_threshold` (default 5%), the check fails.
|
|
395
|
+
|
|
396
|
+
### Workflow-Specific Options
|
|
397
|
+
|
|
398
|
+
For GitHub Actions workflows, the template always wins for `uses:` lines
|
|
399
|
+
(SHA-pinned action references) while destination wins for job configuration:
|
|
400
|
+
|
|
401
|
+
```yaml
|
|
402
|
+
# Template updates this SHA automatically:
|
|
403
|
+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
|
|
404
|
+
|
|
405
|
+
# Your matrix customizations are preserved:
|
|
406
|
+
matrix:
|
|
407
|
+
ruby: ["3.2", "3.3", "3.4"]
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### Per-File Overrides
|
|
411
|
+
|
|
412
|
+
Override merge behavior for specific files in `.kettle-jem.yml`:
|
|
413
|
+
|
|
414
|
+
```yaml
|
|
415
|
+
files:
|
|
416
|
+
Rakefile:
|
|
417
|
+
strategy: merge
|
|
418
|
+
preference: destination # keep your custom tasks
|
|
419
|
+
certs/my.pem:
|
|
420
|
+
strategy: raw_copy # binary file, no merging
|
|
421
|
+
generated/report.md:
|
|
422
|
+
strategy: keep_destination # never touch this file
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
### Environment Variables & CLI Options
|
|
426
|
+
|
|
427
|
+
Kettle::Jem behavior is controlled via environment variables (which double as
|
|
428
|
+
Rake task arguments) and CLI flags passed to `kettle-jem setup`.
|
|
429
|
+
|
|
430
|
+
#### Merge & Error Handling
|
|
431
|
+
|
|
432
|
+
| Variable | CLI Flag | Default | Description |
|
|
433
|
+
|----------|----------|---------|-------------|
|
|
434
|
+
| `FAILURE_MODE` | `--failure-mode=VAL` | `error` | How general merge failures are handled. `error` raises and halts; `rescue` logs a warning and uses unmerged content. |
|
|
435
|
+
| `PARSE_ERROR_MODE` | — | `fail` | How AST parser unavailability is handled. `fail` raises immediately (recommended); `skip` warns and preserves the destination file unchanged. **There is no text-merge fallback** — AST merge or nothing. |
|
|
436
|
+
|
|
437
|
+
#### Task Control
|
|
438
|
+
|
|
439
|
+
| Variable | CLI Flag | Default | Description |
|
|
440
|
+
|----------|----------|---------|-------------|
|
|
441
|
+
| `allowed` | `--allowed=VAL` | `true` | Set to `false`/`0`/`no` to require manual review of env file changes before continuing. |
|
|
442
|
+
| — | `--interactive` | _(off)_ | Enable interactive prompts (opt-in). Overrides the default non-interactive behavior. |
|
|
443
|
+
| `KETTLE_JEM_VERBOSE` | `--verbose` | `false` | Show detailed output including per-file messages and setup progress. Overrides the default quiet behavior. |
|
|
444
|
+
| `only` | `--only=VAL` | _(all)_ | Comma-separated glob patterns — only template files matching at least one pattern are processed. |
|
|
445
|
+
| `include` | `--include=VAL` | _(all)_ | Comma-separated glob patterns — additional files to include beyond the default set. |
|
|
446
|
+
| `hook_templates` | `--hook_templates=VAL` | _(prompt)_ | Git hook install location: `l`/`local`, `g`/`global`, or `n`/`none`. Also via `KETTLE_DEV_HOOK_TEMPLATES`. |
|
|
447
|
+
| `KETTLE_JEM_CHECKSUMS` | `--checksums=VAL` | `template,ignore-dest` | Checksum skip mode. See "Checksum Skip Modes" below. |
|
|
448
|
+
| — | `--ignore-checksums` | _(off)_ | Alias for `--checksums=off`; disables checksum-based skipping. |
|
|
449
|
+
|
|
450
|
+
#### Checksum Skip Modes
|
|
451
|
+
|
|
452
|
+
Kettle::Jem writes managed template state to
|
|
453
|
+
`.structuredmerge/kettle-jem.lock`. The legacy whole-template checksum
|
|
454
|
+
inventory now lives under `template_state.checksums`.
|
|
455
|
+
That inventory is useful for coarse template drift state, but it is not used to
|
|
456
|
+
skip individual files. File skipping uses `files.*.input_fingerprint`, a
|
|
457
|
+
per-destination digest that includes the selected template source SHA, recipe
|
|
458
|
+
identity/version, resolved token digest, and kettle-jem implementation SHA.
|
|
459
|
+
Token values are hashed into the fingerprint and are not written to the lockfile.
|
|
460
|
+
|
|
461
|
+
`--checksums` accepts comma-separated modes:
|
|
462
|
+
|
|
463
|
+
| Mode | Behavior |
|
|
464
|
+
|------|----------|
|
|
465
|
+
| `template` | Skip a destination file only when its `input_fingerprint` matches the lock. This is the default template-input check. |
|
|
466
|
+
| `ignore-dest` | Do not compare the destination file checksum. This is the default destination behavior. |
|
|
467
|
+
| `dest` | Also require the destination file checksum to match the lock before skipping. `dest` implies `template` unless `ignore-template` is present. |
|
|
468
|
+
| `ignore-template` | Do not compare `input_fingerprint`; useful only with `dest` when local destination state should be the only skip gate. |
|
|
469
|
+
| `off` | Disable checksum-based skipping. This cannot be combined with other modes. |
|
|
470
|
+
|
|
471
|
+
Common combinations:
|
|
472
|
+
|
|
473
|
+
| Value | Result |
|
|
474
|
+
|-------|--------|
|
|
475
|
+
| `template,ignore-dest` | Default. Retemplate when relevant template input changes; ignore local destination edits. |
|
|
476
|
+
| `dest,template` | Retemplate when relevant template input changes or the destination differs from the prior templated result. |
|
|
477
|
+
| `dest,ignore-template` | Skip only when the destination checksum matches; ignore template input changes. |
|
|
478
|
+
| `off` | Run normal templating without checksum skip shortcuts. |
|
|
479
|
+
|
|
480
|
+
#### Config & Identity (KJ_ prefix)
|
|
481
|
+
|
|
482
|
+
These map directly to `.kettle-jem.yml` keys, seed freshly created configs,
|
|
483
|
+
fill missing keys during config sync, and act as runtime overrides.
|
|
484
|
+
|
|
485
|
+
| Variable | Description |
|
|
486
|
+
|----------|-------------|
|
|
487
|
+
| `KJ_PROJECT_EMOJI` | Project identifying emoji (e.g. `🪙`). Required in config. |
|
|
488
|
+
| `KJ_MIN_DIVERGENCE_THRESHOLD` | Selftest divergence threshold for `min_divergence_threshold`. |
|
|
489
|
+
| `KJ_AUTHOR_NAME` | Gem author full name |
|
|
490
|
+
| `KJ_AUTHOR_EMAIL` | Gem author email |
|
|
491
|
+
| `KJ_AUTHOR_DOMAIN` | Author website domain (derived from email if unset) |
|
|
492
|
+
| `KJ_AUTHOR_GIVEN_NAMES` | First/given names |
|
|
493
|
+
| `KJ_AUTHOR_FAMILY_NAMES` | Last/family names |
|
|
494
|
+
| `KJ_AUTHOR_ORCID` | ORCID identifier |
|
|
495
|
+
| `FORGE_ORG` | Preferred forge organization or owner used for scaffolded repository URLs when no forge remote is available |
|
|
496
|
+
| `KJ_GH_ORG` | GitHub-specific organization or owner fallback for scaffolded repository URLs |
|
|
497
|
+
| `KJ_GH_USER` | GitHub username used for maintainer profile and sponsor links |
|
|
498
|
+
| `KJ_GL_USER` | GitLab username |
|
|
499
|
+
| `KJ_CB_USER` | Codeberg username |
|
|
500
|
+
| `KJ_SH_USER` | SourceHut username |
|
|
501
|
+
|
|
502
|
+
#### Workspace & Funding
|
|
503
|
+
|
|
504
|
+
| Variable | Description |
|
|
505
|
+
|----------|-------------|
|
|
506
|
+
| `KETTLE_DEV_DEV` | Workspace root for local sibling gems. `true` = `~/src/my`; a path = that path; unset/`false` = released gems. |
|
|
507
|
+
| `KETTLE_DEV_DEBUG` | Set to `true` for verbose debug output. |
|
|
508
|
+
| `FUNDING_ORG` | OpenCollective organization handle for FUNDING.yml. Auto-derived from git remote if unset. |
|
|
509
|
+
| `OPENCOLLECTIVE_HANDLE` | Alternative to `FUNDING_ORG` for personal OpenCollective pages. |
|
|
510
|
+
| `KJ_FUNDING_KOFI` | Ko-fi handle for FUNDING.yml |
|
|
511
|
+
| `KJ_FUNDING_PAYPAL` | PayPal handle for FUNDING.yml |
|
|
512
|
+
| `KJ_FUNDING_BUYMEACOFFEE` | Buy Me a Coffee handle for funding links |
|
|
513
|
+
| `KJ_FUNDING_LIBERAPAY` | Liberapay handle for funding links |
|
|
514
|
+
| `KJ_SOCIAL_MASTODON` | Mastodon handle for social/profile links |
|
|
515
|
+
| `KJ_SOCIAL_BLUESKY` | Bluesky handle for social/profile links |
|
|
516
|
+
| `KJ_SOCIAL_LINKTREE` | Linktree handle for social/profile links |
|
|
517
|
+
| `KJ_SOCIAL_DEVTO` | DEV Community handle for social/profile links |
|
|
518
|
+
|
|
519
|
+
#### Templating Examples
|
|
520
|
+
|
|
521
|
+
```bash
|
|
522
|
+
# Standard template update (quiet, non-interactive — the default)
|
|
523
|
+
K_JEM_TEMPLATING=true bundle exec kettle-jem install
|
|
524
|
+
|
|
525
|
+
# Verbose output
|
|
526
|
+
K_JEM_TEMPLATING=true KETTLE_JEM_VERBOSE=true bundle exec kettle-jem install
|
|
527
|
+
|
|
528
|
+
# Interactive mode (prompts before each change)
|
|
529
|
+
K_JEM_TEMPLATING=true bundle exec kettle-jem install --interactive
|
|
530
|
+
|
|
531
|
+
# Force re-evaluation of every selected template file
|
|
532
|
+
K_JEM_TEMPLATING=true bundle exec kettle-jem install --ignore-checksums
|
|
533
|
+
|
|
534
|
+
# Retemplate when either template inputs or destination checksums changed
|
|
535
|
+
K_JEM_TEMPLATING=true bundle exec kettle-jem install --checksums=dest,template
|
|
536
|
+
|
|
537
|
+
# Only workflow files, skip unparseable. Scoped template runs skip install
|
|
538
|
+
# finishing steps and are intended for surgical file updates.
|
|
539
|
+
K_JEM_TEMPLATING=true PARSE_ERROR_MODE=skip bundle exec kettle-jem template --only=".github/**"
|
|
540
|
+
|
|
541
|
+
# Rescue on merge failure (don't halt)
|
|
542
|
+
K_JEM_TEMPLATING=true FAILURE_MODE=rescue bundle exec kettle-jem install
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
The `kettle:jem:*` rake tasks are internal targets used by the executable after
|
|
546
|
+
it prepares the templating environment; call `kettle-jem` directly for normal
|
|
547
|
+
templating work.
|
|
548
|
+
|
|
549
|
+
## 🔐 Security
|
|
550
|
+
|
|
551
|
+
See [SECURITY.md][🔐security].
|
|
552
|
+
|
|
553
|
+
## 🤝 Contributing
|
|
554
|
+
|
|
555
|
+
If you need some ideas of where to help, you could work on adding more code coverage,
|
|
556
|
+
or if it is already 💯 (see [below](#code-coverage)) check [issues][🤝gh-issues] or [PRs][🤝gh-pulls],
|
|
557
|
+
or use the gem and think about how it could be better.
|
|
558
|
+
|
|
559
|
+
We [![Keep A Changelog][📗keep-changelog-img]][📗keep-changelog] so if you make changes, remember to update it.
|
|
560
|
+
|
|
561
|
+
See [CONTRIBUTING.md][🤝contributing] for more detailed instructions.
|
|
562
|
+
|
|
563
|
+
### 🚀 Release Instructions
|
|
564
|
+
|
|
565
|
+
See [CONTRIBUTING.md][🤝contributing].
|
|
566
|
+
|
|
567
|
+
### Code Coverage
|
|
568
|
+
|
|
569
|
+
<details markdown="1">
|
|
570
|
+
<summary>Coverage service badges</summary>
|
|
571
|
+
|
|
572
|
+
</details>
|
|
573
|
+
|
|
574
|
+
### 🪇 Code of Conduct
|
|
575
|
+
|
|
576
|
+
Everyone interacting with this project's codebases, issue trackers,
|
|
577
|
+
chat rooms and mailing lists agrees to follow the [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct].
|
|
578
|
+
|
|
579
|
+
## 🌈 Contributors
|
|
580
|
+
|
|
581
|
+
[![Contributors][🖐contributors-img]][🖐contributors]
|
|
582
|
+
|
|
583
|
+
Made with [contributors-img][🖐contrib-rocks].
|
|
584
|
+
|
|
585
|
+
Also see GitLab Contributors: [https://gitlab.com/structuredmerge/structuredmerge-ruby/-/graphs/main][🚎contributors-gl]
|
|
586
|
+
|
|
587
|
+
## 📌 Versioning
|
|
588
|
+
|
|
589
|
+
This library follows [![Semantic Versioning 2.0.0][📌semver-img]][📌semver] for its public API where practical.
|
|
590
|
+
For most applications, prefer the [Pessimistic Version Constraint][📌pvc] with two digits of precision.
|
|
591
|
+
|
|
592
|
+
For example:
|
|
593
|
+
|
|
594
|
+
```ruby
|
|
595
|
+
spec.add_dependency("kettle-jem", "~> 7.0")
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
<details markdown="1">
|
|
599
|
+
<summary>📌 Is "Platform Support" part of the public API? More details inside.</summary>
|
|
600
|
+
|
|
601
|
+
Dropping support for a platform can be a breaking change for affected users.
|
|
602
|
+
If a release changes supported platforms, it should be called out clearly in the changelog and versioned with that impact in mind.
|
|
603
|
+
|
|
604
|
+
To get a better understanding of how SemVer is intended to work over a project's lifetime,
|
|
605
|
+
read this article from the creator of SemVer:
|
|
606
|
+
|
|
607
|
+
- ["Major Version Numbers are Not Sacred"][📌major-versions-not-sacred]
|
|
608
|
+
|
|
609
|
+
</details>
|
|
610
|
+
|
|
611
|
+
See [CHANGELOG.md][📌changelog] for a list of releases.
|
|
612
|
+
|
|
613
|
+
## 📄 License
|
|
614
|
+
|
|
615
|
+
The gem is available under the following licenses: [AGPL-3.0-only](https://github.com/structuredmerge/structuredmerge-ruby/blob/main/AGPL-3.0-only.md), [PolyForm-Small-Business-1.0.0](https://github.com/structuredmerge/structuredmerge-ruby/blob/main/PolyForm-Small-Business-1.0.0.md).
|
|
616
|
+
See [LICENSE.md][📄license] for details.
|
|
617
|
+
|
|
618
|
+
If none of the available licenses suit your use case, please [contact us](mailto:floss@galtzo.com) to discuss a custom commercial license.
|
|
619
|
+
|
|
620
|
+
### © Copyright
|
|
621
|
+
|
|
622
|
+
See [LICENSE.md][📄license] for the official copyright notice.
|
|
623
|
+
|
|
624
|
+
<details markdown="1">
|
|
625
|
+
<summary>Copyright holders</summary>
|
|
626
|
+
|
|
627
|
+
- Required Notice: Copyright (c) 2026 Peter H. Boling
|
|
628
|
+
|
|
629
|
+
</details>
|
|
630
|
+
|
|
631
|
+
## 🤑 A request for help
|
|
632
|
+
|
|
633
|
+
Maintainers have teeth and need to pay their dentists.
|
|
634
|
+
After getting laid off in an RIF in March, and encountering difficulty finding a new one,
|
|
635
|
+
I began spending most of my time building open source tools.
|
|
636
|
+
I'm hoping to be able to pay for my kids' health insurance this month,
|
|
637
|
+
so if you value the work I am doing, I need your support.
|
|
638
|
+
Please consider sponsoring me or the project.
|
|
639
|
+
|
|
640
|
+
To join the community or get help, use the RubyForum or Discord.
|
|
641
|
+
|
|
642
|
+
[![Ruby Users Forum][✉️ruby-forum-img]][✉️ruby-forum]
|
|
643
|
+
[![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite]
|
|
644
|
+
|
|
645
|
+
To say "thanks!" ☝️ Join the community or 👇️ send money.
|
|
646
|
+
|
|
647
|
+
[![Sponsor me on GitHub Sponsors][🖇sponsor-bottom-img]][🖇sponsor] 💌 [![Sponsor me on Liberapay][⛳liberapay-bottom-img]][⛳liberapay] 💌 [![Donate on PayPal][🖇paypal-bottom-img]][🖇paypal]
|
|
648
|
+
|
|
649
|
+
### Please give the project a star ⭐ ♥.
|
|
650
|
+
|
|
651
|
+
Many parts of this project are actively managed by a [kettle-jem](https://github.com/structuredmerge/structuredmerge-ruby/tree/main/gems/kettle-jem) smart template utilizing [StructuredMerge.org](https://structuredmerge.org) merge contracts.
|
|
652
|
+
|
|
653
|
+
Thanks for RTFM. ☺️
|
|
654
|
+
|
|
655
|
+
[⛳liberapay-img]: https://img.shields.io/liberapay/goal/pboling.svg?logo=liberapay&color=a51611&style=flat
|
|
656
|
+
[⛳liberapay-bottom-img]: https://img.shields.io/liberapay/goal/pboling.svg?style=for-the-badge&logo=liberapay&color=a51611
|
|
657
|
+
[⛳liberapay]: https://liberapay.com/pboling/donate
|
|
658
|
+
[🖇sponsor-img]: https://img.shields.io/badge/Sponsor_Me!-pboling.svg?style=social&logo=github
|
|
659
|
+
[🖇sponsor-bottom-img]: https://img.shields.io/badge/Sponsor_Me!-pboling-blue?style=for-the-badge&logo=github
|
|
660
|
+
[🖇sponsor]: https://github.com/sponsors/pboling
|
|
661
|
+
[🖇kofi-img]: https://img.shields.io/badge/ko--fi-%E2%9C%93-a51611.svg?style=flat
|
|
662
|
+
[🖇kofi]: https://ko-fi.com/pboling
|
|
663
|
+
[🖇buyme-small-img]: https://img.shields.io/badge/buy_me_a_coffee-%E2%9C%93-a51611.svg?style=flat
|
|
664
|
+
[🖇buyme-img]: https://img.buymeacoffee.com/button-api/?text=Buy%20me%20a%20latte&emoji=&slug=pboling&button_colour=FFDD00&font_colour=000000&font_family=Cookie&outline_colour=000000&coffee_colour=ffffff
|
|
665
|
+
[🖇buyme]: https://www.buymeacoffee.com/pboling
|
|
666
|
+
[🖇paypal-img]: https://img.shields.io/badge/donate-paypal-a51611.svg?style=flat&logo=paypal
|
|
667
|
+
[🖇paypal-bottom-img]: https://img.shields.io/badge/donate-paypal-a51611.svg?style=for-the-badge&logo=paypal&color=0A0A0A
|
|
668
|
+
[🖇paypal]: https://www.paypal.com/paypalme/peterboling
|
|
669
|
+
[🖇floss-funding.dev]: https://floss-funding.dev
|
|
670
|
+
[🖇floss-funding-gem]: https://github.com/galtzo-floss/floss_funding
|
|
671
|
+
[✉️discord-invite]: https://discord.gg/3qme4XHNKN
|
|
672
|
+
[✉️discord-invite-img-ftb]: https://img.shields.io/discord/1373797679469170758?style=for-the-badge&logo=discord
|
|
673
|
+
[✉️ruby-friends-img]: https://img.shields.io/badge/daily.dev-%F0%9F%92%8E_Ruby_Friends-0A0A0A?style=for-the-badge&logo=dailydotdev&logoColor=white
|
|
674
|
+
[✉️ruby-friends]: https://app.daily.dev/squads/rubyfriends
|
|
675
|
+
[✉️ruby-forum-top-img]: https://img.shields.io/discourse/topics?server=https%3A%2F%2Fwww.rubyforum.org&style=flat&logo=discourse&label=Ruby%20Users%20Forum
|
|
676
|
+
[✉️ruby-forum-img]: https://img.shields.io/discourse/topics?server=https%3A%2F%2Fwww.rubyforum.org&style=for-the-badge&logo=discourse&label=Ruby%20Users%20Forum
|
|
677
|
+
[✉️ruby-forum]: https://www.rubyforum.org/tag/structuredmerge
|
|
678
|
+
|
|
679
|
+
[✇bundle-group-pattern]: https://gist.github.com/pboling/4564780
|
|
680
|
+
[⛳️gem-namespace]: https://github.com/structuredmerge/structuredmerge-ruby/tree/main/gems/kettle-jem
|
|
681
|
+
[⛳️namespace-img]: https://img.shields.io/badge/namespace-Kettle::Jem-3C2D2D.svg?style=square&logo=ruby&logoColor=white
|
|
682
|
+
[⛳️gem-name]: https://clickgems.clickhouse.com/dashboard/kettle-jem
|
|
683
|
+
[⛳️name-img]: https://img.shields.io/badge/name-kettle--jem-3C2D2D.svg?style=square&logo=rubygems&logoColor=red
|
|
684
|
+
[⛳️tag-img]: https://img.shields.io/github/tag/structuredmerge/structuredmerge-ruby.svg
|
|
685
|
+
[⛳️tag]: https://github.com/structuredmerge/structuredmerge-ruby/releases
|
|
686
|
+
[🚂maint-blog]: http://www.railsbling.com/tags/kettle-jem
|
|
687
|
+
[🚂maint-blog-img]: https://img.shields.io/badge/blog-railsbling-0093D0.svg?style=for-the-badge&logo=rubyonrails&logoColor=orange
|
|
688
|
+
[🚂maint-contact]: http://www.railsbling.com/contact
|
|
689
|
+
[🚂maint-contact-img]: https://img.shields.io/badge/Contact-Maintainer-0093D0.svg?style=flat&logo=rubyonrails&logoColor=red
|
|
690
|
+
[💖🖇linkedin]: http://www.linkedin.com/in/peterboling
|
|
691
|
+
[💖🖇linkedin-img]: https://img.shields.io/badge/LinkedIn-Profile-0B66C2?style=flat&logo=newjapanprowrestling
|
|
692
|
+
[💖✌️wellfound]: https://wellfound.com/u/peter-boling
|
|
693
|
+
[💖✌️wellfound-img]: https://img.shields.io/badge/peter--boling-orange?style=flat&logo=wellfound
|
|
694
|
+
[💖💲crunchbase]: https://www.crunchbase.com/person/peter-boling
|
|
695
|
+
[💖💲crunchbase-img]: https://img.shields.io/badge/peter--boling-purple?style=flat&logo=crunchbase
|
|
696
|
+
[💖🐘ruby-mast]: https://ruby.social/@galtzo
|
|
697
|
+
[💖🐘ruby-mast-img]: https://img.shields.io/mastodon/follow/109447111526622197?domain=https://ruby.social&style=flat&logo=mastodon&label=Ruby%20@galtzo
|
|
698
|
+
[💖🦋bluesky]: https://bsky.app/profile/galtzo.com
|
|
699
|
+
[💖🦋bluesky-img]: https://img.shields.io/badge/@galtzo.com-0285FF?style=flat&logo=bluesky&logoColor=white
|
|
700
|
+
[💖🌳linktree]: https://linktr.ee/galtzo
|
|
701
|
+
[💖🌳linktree-img]: https://img.shields.io/badge/galtzo-purple?style=flat&logo=linktree
|
|
702
|
+
[💖💁🏼♂️devto]: https://dev.to/galtzo
|
|
703
|
+
[💖💁🏼♂️devto-img]: https://img.shields.io/badge/dev.to-0A0A0A?style=flat&logo=devdotto&logoColor=white
|
|
704
|
+
[💖💁🏼♂️aboutme]: https://about.me/peter.boling
|
|
705
|
+
[💖💁🏼♂️aboutme-img]: https://img.shields.io/badge/about.me-0A0A0A?style=flat&logo=aboutme&logoColor=white
|
|
706
|
+
[💖🧊berg]: https://codeberg.org/pboling
|
|
707
|
+
[💖🐙hub]: https://github.org/pboling
|
|
708
|
+
[💖🛖hut]: https://sr.ht/~galtzo/
|
|
709
|
+
[💖🧪lab]: https://gitlab.com/pboling
|
|
710
|
+
[👨🏼🏫expsup-upwork]: https://www.upwork.com/freelancers/~014942e9b056abdf86?mp_source=share
|
|
711
|
+
[👨🏼🏫expsup-upwork-img]: https://img.shields.io/badge/UpWork-13544E?style=for-the-badge&logo=Upwork&logoColor=white
|
|
712
|
+
[👨🏼🏫expsup-codementor]: https://www.codementor.io/peterboling?utm_source=github&utm_medium=button&utm_term=peterboling&utm_campaign=github
|
|
713
|
+
[👨🏼🏫expsup-codementor-img]: https://img.shields.io/badge/CodeMentor-Get_Help-1abc9c?style=for-the-badge&logo=CodeMentor&logoColor=white
|
|
714
|
+
[🏙️entsup-tidelift]: https://tidelift.com/subscription/pkg/rubygems-kettle-jem?utm_source=rubygems-kettle-jem&utm_medium=referral&utm_campaign=readme
|
|
715
|
+
[🏙️entsup-tidelift-img]: https://img.shields.io/badge/Tidelift_and_Sonar-Enterprise_Support-FD3456?style=for-the-badge&logo=sonar&logoColor=white
|
|
716
|
+
[🏙️entsup-tidelift-sonar]: https://blog.tidelift.com/tidelift-joins-sonar
|
|
717
|
+
[💁🏼♂️peterboling]: http://www.peterboling.com
|
|
718
|
+
[🚂railsbling]: http://www.railsbling.com
|
|
719
|
+
[📜src-gl-img]: https://img.shields.io/badge/GitLab-FBA326?style=for-the-badge&logo=Gitlab&logoColor=orange
|
|
720
|
+
[📜src-gl]: https://gitlab.com/structuredmerge/structuredmerge-ruby/-/tree/main/gems/kettle-jem
|
|
721
|
+
[📜src-cb-img]: https://img.shields.io/badge/CodeBerg-4893CC?style=for-the-badge&logo=CodeBerg&logoColor=blue
|
|
722
|
+
[📜src-cb]: https://codeberg.org/structuredmerge/structuredmerge-ruby/src/branch/main/gems/kettle-jem
|
|
723
|
+
[📜src-gh-img]: https://img.shields.io/badge/GitHub-238636?style=for-the-badge&logo=GitHub&logoColor=green
|
|
724
|
+
[📜src-gh]: https://github.com/structuredmerge/structuredmerge-ruby/tree/main/gems/kettle-jem
|
|
725
|
+
[📜docs-cr-rd-img]: https://img.shields.io/badge/RubyDoc-Current_Release-943CD2?style=for-the-badge&logo=readthedocs&logoColor=white
|
|
726
|
+
[📜docs-head-rd-img]: https://img.shields.io/badge/YARD_on_Galtzo.com-HEAD-943CD2?style=for-the-badge&logo=readthedocs&logoColor=white
|
|
727
|
+
[📜gl-wiki]: https://gitlab.com/structuredmerge/structuredmerge-ruby/-/wikis/home
|
|
728
|
+
[📜gh-wiki]: https://github.com/structuredmerge/structuredmerge-ruby/wiki
|
|
729
|
+
[📜gl-wiki-img]: https://img.shields.io/badge/wiki-gitlab-943CD2.svg?style=for-the-badge&logo=gitlab&logoColor=white
|
|
730
|
+
[📜gh-wiki-img]: https://img.shields.io/badge/wiki-github-943CD2.svg?style=for-the-badge&logo=github&logoColor=white
|
|
731
|
+
[👽dl-rank]: https://clickgems.clickhouse.com/dashboard/kettle-jem
|
|
732
|
+
[👽dl-ranki]: https://img.shields.io/gem/dt/kettle-jem.svg
|
|
733
|
+
[👽version]: https://clickgems.clickhouse.com/dashboard/kettle-jem
|
|
734
|
+
[👽versioni]: https://img.shields.io/gem/v/kettle-jem.svg
|
|
735
|
+
[🚎11-c-wf]: https://github.com/structuredmerge/structuredmerge-ruby/actions/workflows/current.yml
|
|
736
|
+
[🚎11-c-wfi]: https://github.com/structuredmerge/structuredmerge-ruby/actions/workflows/current.yml/badge.svg
|
|
737
|
+
[💎ruby-c-i]: https://img.shields.io/badge/Ruby-current-CC342D?style=for-the-badge&logo=ruby&logoColor=green
|
|
738
|
+
[🤝gh-issues]: https://github.com/structuredmerge/structuredmerge-ruby/issues
|
|
739
|
+
[🤝gh-pulls]: https://github.com/structuredmerge/structuredmerge-ruby/pulls
|
|
740
|
+
[🤝gl-issues]: https://gitlab.com/structuredmerge/structuredmerge-ruby/-/issues
|
|
741
|
+
[🤝gl-pulls]: https://gitlab.com/structuredmerge/structuredmerge-ruby/-/merge_requests
|
|
742
|
+
[🤝cb-issues]: https://codeberg.org/structuredmerge/structuredmerge-ruby/issues
|
|
743
|
+
[🤝cb-pulls]: https://codeberg.org/structuredmerge/structuredmerge-ruby/pulls
|
|
744
|
+
[🤝cb-donate]: https://donate.codeberg.org/
|
|
745
|
+
[🤝contributing]: https://github.com/structuredmerge/structuredmerge-ruby/blob/main/CONTRIBUTING.md
|
|
746
|
+
[🖐contrib-rocks]: https://contrib.rocks
|
|
747
|
+
[🖐contributors]: https://github.com/structuredmerge/structuredmerge-ruby/graphs/contributors
|
|
748
|
+
[🖐contributors-img]: https://contrib.rocks/image?repo=structuredmerge/structuredmerge-ruby
|
|
749
|
+
[🚎contributors-gl]: https://gitlab.com/structuredmerge/structuredmerge-ruby/-/graphs/main
|
|
750
|
+
[🪇conduct]: https://github.com/structuredmerge/structuredmerge-ruby/blob/main/CODE_OF_CONDUCT.md
|
|
751
|
+
[🪇conduct-img]: https://img.shields.io/badge/Contributor_Covenant-2.1-259D6C.svg
|
|
752
|
+
[📌pvc]: http://guides.rubygems.org/patterns/#pessimistic-version-constraint
|
|
753
|
+
[📌semver]: https://semver.org/spec/v2.0.0.html
|
|
754
|
+
[📌semver-img]: https://img.shields.io/badge/semver-2.0.0-259D6C.svg?style=flat
|
|
755
|
+
[📌semver-breaking]: https://github.com/semver/semver/issues/716#issuecomment-869336139
|
|
756
|
+
[📌major-versions-not-sacred]: https://tom.preston-werner.com/2022/05/23/major-version-numbers-are-not-sacred.html
|
|
757
|
+
[📌changelog]: https://github.com/structuredmerge/structuredmerge-ruby/blob/main/CHANGELOG.md
|
|
758
|
+
[📗keep-changelog]: https://keepachangelog.com/en/1.0.0/
|
|
759
|
+
[📗keep-changelog-img]: https://img.shields.io/badge/keep--a--changelog-1.0.0-34495e.svg?style=flat
|
|
760
|
+
[📌gitmoji]: https://gitmoji.dev
|
|
761
|
+
[📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
762
|
+
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
763
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-11.445-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
|
764
|
+
[🔐security]: https://github.com/structuredmerge/structuredmerge-ruby/blob/main/SECURITY.md
|
|
765
|
+
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
|
766
|
+
[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
|
|
767
|
+
[📄license]: LICENSE.md
|
|
768
|
+
[📄license-ref]: LICENSE.md
|
|
769
|
+
[📄license-img]: https://img.shields.io/badge/License-AGPL--3.0--only_OR_PolyForm--Small--Business--1.0.0-259D6C.svg
|
|
770
|
+
[📄license-compat]: https://www.apache.org/legal/resolved.html#category-x
|
|
771
|
+
[📄license-compat-img]: https://img.shields.io/badge/Apache_Incompatible:_Category_X-%E2%9C%97-C0392B.svg?style=flat&logo=Apache
|
|
772
|
+
|
|
773
|
+
[📄ilo-declaration]: https://www.ilo.org/declaration/lang--en/index.htm
|
|
774
|
+
[📄ilo-declaration-img]: https://img.shields.io/badge/ILO_Fundamental_Principles-✓-259D6C.svg?style=flat
|
|
775
|
+
[🚎yard-current]: http://rubydoc.info/gems/kettle-jem
|
|
776
|
+
[🚎yard-head]: https://kettle-jem.galtzo.com
|
|
777
|
+
[💎stone_checksums]: https://github.com/galtzo-floss/stone_checksums
|
|
778
|
+
[💎SHA_checksums]: https://gitlab.com/structuredmerge/structuredmerge-ruby/-/tree/main/checksums
|
|
779
|
+
[💎rlts]: https://github.com/rubocop-lts/rubocop-lts
|
|
780
|
+
[💎rlts-img]: https://img.shields.io/badge/code_style_&_linting-rubocop--lts-34495e.svg?plastic&logo=ruby&logoColor=white
|
|
781
|
+
[💎appraisal2]: https://github.com/appraisal-rb/appraisal2
|
|
782
|
+
[💎appraisal2-img]: https://img.shields.io/badge/appraised_by-appraisal2-34495e.svg?plastic&logo=ruby&logoColor=white
|
|
783
|
+
[💎d-in-dvcs]: https://railsbling.com/posts/dvcs/put_the_d_in_dvcs/
|
|
784
|
+
|
|
785
|
+
<!-- kettle-jem:metadata:start -->
|
|
786
|
+
| Field | Value |
|
|
787
|
+
|---|---|
|
|
788
|
+
| Package | kettle-jem |
|
|
789
|
+
| Description | 🔮 Kettle::Jem provides gem scaffolding, templating, and setup automation using the *-merge gem family for AST-based file merging and token-resolver for template token resolution. Includes MergerConfig presets, YAML recipes, and a complete gem template scaffold. |
|
|
790
|
+
| Homepage | https://github.com/structuredmerge/structuredmerge-ruby |
|
|
791
|
+
| Source | https://github.com/structuredmerge/structuredmerge-ruby |
|
|
792
|
+
| License | `AGPL-3.0-only` OR `PolyForm-Small-Business-1.0.0` |
|
|
793
|
+
| Funding | https://github.com/sponsors/pboling, https://ko-fi.com/pboling, https://liberapay.com/pboling/donate, https://thanks.dev/u/gh/pboling, https://tidelift.com/funding/github/rubygems/kettle-jem, https://www.buymeacoffee.com/pboling |
|
|
794
|
+
<!-- kettle-jem:metadata:end -->
|