kettle-dev 1.2.3 → 2.0.0

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.
Files changed (133) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +176 -3
  4. data/CITATION.cff +2 -2
  5. data/CONTRIBUTING.md +11 -17
  6. data/README.md +390 -319
  7. data/exe/kettle-dev-setup +12 -63
  8. data/exe/kettle-gh-release +82 -0
  9. data/lib/kettle/dev/gem_spec_reader.rb +2 -2
  10. data/lib/kettle/dev/open_collective_config.rb +12 -0
  11. data/lib/kettle/dev/rakelib/yard.rake +15 -0
  12. data/lib/kettle/dev/tasks/ci_task.rb +4 -4
  13. data/lib/kettle/dev/version.rb +1 -1
  14. data/lib/kettle/dev.rb +4 -12
  15. data/sig/kettle/dev/source_merger.rbs +40 -56
  16. data.tar.gz.sig +0 -0
  17. metadata +15 -144
  18. metadata.gz.sig +0 -0
  19. data/.aiignore.example +0 -19
  20. data/.devcontainer/apt-install/devcontainer-feature.json +0 -9
  21. data/.devcontainer/apt-install/install.sh +0 -11
  22. data/.devcontainer/devcontainer.json +0 -28
  23. data/.env.local.example +0 -31
  24. data/.envrc +0 -47
  25. data/.envrc.example +0 -51
  26. data/.envrc.no-osc.example +0 -51
  27. data/.git-hooks/commit-msg +0 -54
  28. data/.git-hooks/commit-subjects-goalie.txt +0 -8
  29. data/.git-hooks/footer-template.erb.txt +0 -16
  30. data/.git-hooks/prepare-commit-msg +0 -8
  31. data/.github/.codecov.yml.example +0 -14
  32. data/.github/FUNDING.yml +0 -13
  33. data/.github/FUNDING.yml.no-osc.example +0 -13
  34. data/.github/dependabot.yml +0 -13
  35. data/.github/workflows/ancient.yml +0 -83
  36. data/.github/workflows/ancient.yml.example +0 -81
  37. data/.github/workflows/auto-assign.yml +0 -21
  38. data/.github/workflows/codeql-analysis.yml +0 -70
  39. data/.github/workflows/coverage.yml +0 -127
  40. data/.github/workflows/coverage.yml.example +0 -127
  41. data/.github/workflows/current.yml +0 -116
  42. data/.github/workflows/current.yml.example +0 -115
  43. data/.github/workflows/dep-heads.yml +0 -117
  44. data/.github/workflows/dependency-review.yml +0 -20
  45. data/.github/workflows/discord-notifier.yml.example +0 -39
  46. data/.github/workflows/heads.yml +0 -117
  47. data/.github/workflows/heads.yml.example +0 -116
  48. data/.github/workflows/jruby.yml +0 -82
  49. data/.github/workflows/jruby.yml.example +0 -72
  50. data/.github/workflows/legacy.yml +0 -76
  51. data/.github/workflows/license-eye.yml +0 -40
  52. data/.github/workflows/locked_deps.yml +0 -85
  53. data/.github/workflows/opencollective.yml +0 -40
  54. data/.github/workflows/style.yml +0 -67
  55. data/.github/workflows/supported.yml +0 -75
  56. data/.github/workflows/truffle.yml +0 -99
  57. data/.github/workflows/unlocked_deps.yml +0 -84
  58. data/.github/workflows/unsupported.yml +0 -76
  59. data/.gitignore +0 -50
  60. data/.gitlab-ci.yml.example +0 -134
  61. data/.idea/.gitignore +0 -45
  62. data/.junie/guidelines-rbs.md +0 -49
  63. data/.junie/guidelines.md +0 -141
  64. data/.junie/guidelines.md.example +0 -140
  65. data/.licenserc.yaml +0 -7
  66. data/.opencollective.yml +0 -3
  67. data/.opencollective.yml.example +0 -3
  68. data/.qlty/qlty.toml +0 -79
  69. data/.rspec +0 -9
  70. data/.rubocop.yml +0 -13
  71. data/.rubocop_rspec.yml +0 -33
  72. data/.simplecov +0 -16
  73. data/.simplecov.example +0 -11
  74. data/.tool-versions +0 -1
  75. data/.yardignore +0 -13
  76. data/.yardopts +0 -14
  77. data/Appraisal.root.gemfile +0 -10
  78. data/Appraisals +0 -151
  79. data/Appraisals.example +0 -102
  80. data/CHANGELOG.md.example +0 -47
  81. data/CONTRIBUTING.md.example +0 -227
  82. data/FUNDING.md.no-osc.example +0 -63
  83. data/Gemfile +0 -40
  84. data/Gemfile.example +0 -34
  85. data/README.md.example +0 -570
  86. data/README.md.no-osc.example +0 -536
  87. data/Rakefile.example +0 -68
  88. data/gemfiles/modular/coverage.gemfile +0 -6
  89. data/gemfiles/modular/debug.gemfile +0 -13
  90. data/gemfiles/modular/documentation.gemfile +0 -14
  91. data/gemfiles/modular/erb/r2/v3.0.gemfile +0 -1
  92. data/gemfiles/modular/erb/r2.3/default.gemfile +0 -6
  93. data/gemfiles/modular/erb/r2.6/v2.2.gemfile +0 -3
  94. data/gemfiles/modular/erb/r3/v5.0.gemfile +0 -1
  95. data/gemfiles/modular/erb/r3.1/v4.0.gemfile +0 -2
  96. data/gemfiles/modular/erb/vHEAD.gemfile +0 -2
  97. data/gemfiles/modular/injected.gemfile +0 -60
  98. data/gemfiles/modular/mutex_m/r2/v0.3.gemfile +0 -2
  99. data/gemfiles/modular/mutex_m/r2.4/v0.1.gemfile +0 -3
  100. data/gemfiles/modular/mutex_m/r3/v0.3.gemfile +0 -2
  101. data/gemfiles/modular/mutex_m/vHEAD.gemfile +0 -2
  102. data/gemfiles/modular/optional.gemfile +0 -8
  103. data/gemfiles/modular/optional.gemfile.example +0 -5
  104. data/gemfiles/modular/runtime_heads.gemfile +0 -10
  105. data/gemfiles/modular/runtime_heads.gemfile.example +0 -8
  106. data/gemfiles/modular/stringio/r2/v3.0.gemfile +0 -5
  107. data/gemfiles/modular/stringio/r2.4/v0.0.2.gemfile +0 -4
  108. data/gemfiles/modular/stringio/r3/v3.0.gemfile +0 -5
  109. data/gemfiles/modular/stringio/vHEAD.gemfile +0 -2
  110. data/gemfiles/modular/style.gemfile +0 -25
  111. data/gemfiles/modular/style.gemfile.example +0 -25
  112. data/gemfiles/modular/templating.gemfile +0 -3
  113. data/gemfiles/modular/x_std_libs/r2/libs.gemfile +0 -3
  114. data/gemfiles/modular/x_std_libs/r2.3/libs.gemfile +0 -3
  115. data/gemfiles/modular/x_std_libs/r2.4/libs.gemfile +0 -3
  116. data/gemfiles/modular/x_std_libs/r2.6/libs.gemfile +0 -3
  117. data/gemfiles/modular/x_std_libs/r3/libs.gemfile +0 -3
  118. data/gemfiles/modular/x_std_libs/r3.1/libs.gemfile +0 -3
  119. data/gemfiles/modular/x_std_libs/vHEAD.gemfile +0 -3
  120. data/gemfiles/modular/x_std_libs.gemfile +0 -2
  121. data/kettle-dev.gemspec.example +0 -154
  122. data/lib/kettle/dev/modular_gemfiles.rb +0 -119
  123. data/lib/kettle/dev/prism_appraisals.rb +0 -351
  124. data/lib/kettle/dev/prism_gemfile.rb +0 -177
  125. data/lib/kettle/dev/prism_gemspec.rb +0 -284
  126. data/lib/kettle/dev/prism_utils.rb +0 -201
  127. data/lib/kettle/dev/rakelib/install.rake +0 -10
  128. data/lib/kettle/dev/rakelib/template.rake +0 -10
  129. data/lib/kettle/dev/setup_cli.rb +0 -403
  130. data/lib/kettle/dev/source_merger.rb +0 -622
  131. data/lib/kettle/dev/tasks/install_task.rb +0 -553
  132. data/lib/kettle/dev/tasks/template_task.rb +0 -975
  133. data/lib/kettle/dev/template_helpers.rb +0 -685
data/README.md CHANGED
@@ -1,37 +1,4 @@
1
- | 📍 NOTE |
2
- |---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
3
- | RubyGems (the [GitHub org][rubygems-org], not the website) [suffered][draper-security] a [hostile takeover][ellen-takeover] in September 2025. |
4
- | Ultimately [4 maintainers][simi-removed] were [hard removed][martin-removed] and a reason has been given for only 1 of those, while 2 others resigned in protest. |
5
- | It is a [complicated story][draper-takeover] which is difficult to [parse quickly][draper-lies]. |
6
- | Simply put - there was active policy for adding or removing maintainers/owners of [rubygems][rubygems-maint-policy] and [bundler][bundler-maint-policy], and those [policies were not followed][policy-fail]. |
7
- | I'm adding notes like this to gems because I [don't condone theft][draper-theft] of repositories or gems from their rightful owners. |
8
- | If a similar theft happened with my repos/gems, I'd hope some would stand up for me. |
9
- | Disenfranchised former-maintainers have started [gem.coop][gem-coop]. |
10
- | Once available I will publish there exclusively; unless RubyCentral makes amends with the community. |
11
- | The ["Technology for Humans: Joel Draper"][reinteractive-podcast] podcast episode by [reinteractive][reinteractive] is the most cogent summary I'm aware of. |
12
- | See [here][gem-naming], [here][gem-coop] and [here][martin-ann] for more info on what comes next. |
13
- | What I'm doing: A (WIP) proposal for [bundler/gem scopes][gem-scopes], and a (WIP) proposal for a federated [gem server][gem-server]. |
14
-
15
- [rubygems-org]: https://github.com/rubygems/
16
- [draper-security]: https://joel.drapper.me/p/ruby-central-security-measures/
17
- [draper-takeover]: https://joel.drapper.me/p/ruby-central-takeover/
18
- [ellen-takeover]: https://pup-e.com/blog/goodbye-rubygems/
19
- [simi-removed]: https://www.reddit.com/r/ruby/s/gOk42POCaV
20
- [martin-removed]: https://bsky.app/profile/martinemde.com/post/3m3occezxxs2q
21
- [draper-lies]: https://joel.drapper.me/p/ruby-central-fact-check/
22
- [draper-theft]: https://joel.drapper.me/p/ruby-central/
23
- [reinteractive]: https://reinteractive.com/ruby-on-rails
24
- [gem-coop]: https://gem.coop
25
- [gem-naming]: https://github.com/gem-coop/gem.coop/issues/12
26
- [martin-ann]: https://martinemde.com/2025/10/05/announcing-gem-coop.html
27
- [gem-scopes]: https://github.com/galtzo-floss/bundle-namespace
28
- [gem-server]: https://github.com/galtzo-floss/gem-server
29
- [reinteractive-podcast]: https://youtu.be/_H4qbtC5qzU?si=BvuBU90R2wAqD2E6
30
- [bundler-maint-policy]: https://github.com/ruby/rubygems/blob/b1ab33a3d52310a84d16b193991af07f5a6a07c0/doc/bundler/playbooks/TEAM_CHANGES.md
31
- [rubygems-maint-policy]: https://github.com/ruby/rubygems/blob/b1ab33a3d52310a84d16b193991af07f5a6a07c0/doc/rubygems/POLICIES.md?plain=1#L187-L196
32
- [policy-fail]: https://www.reddit.com/r/ruby/comments/1ove9vp/rubycentral_hates_this_one_fact/
33
-
34
- [![Galtzo FLOSS Logo by Aboling0, CC BY-SA 4.0][🖼️galtzo-i]][🖼️galtzo-discord] [![ruby-lang Logo, Yukihiro Matsumoto, Ruby Visual Identity Team, CC BY-SA 2.5][🖼️ruby-lang-i]][🖼️ruby-lang] [![kettle-dev Logo by Aboling0, CC BY-SA 4.0][🖼️kettle-dev-i]][🖼️kettle-dev]
1
+ [![Galtzo FLOSS Logo by Aboling0, CC BY-SA 4.0][🖼️galtzo-i]][🖼️galtzo-discord] [![ruby-lang Logo, Yukihiro Matsumoto, Ruby Visual Identity Team, CC BY-SA 2.5][🖼️ruby-lang-i]][🖼️ruby-lang] [![kettle-dev Logo by Aboling0, CC BY-SA 4.0][🖼️kettle-dev-i]][📜src-gh]
35
2
 
36
3
  [🖼️galtzo-i]: https://logos.galtzo.com/assets/images/galtzo-floss/avatar-192px.svg
37
4
  [🖼️galtzo-discord]: https://discord.gg/3qme4XHNKN
@@ -42,16 +9,23 @@
42
9
 
43
10
  # 🍲 Kettle::Dev
44
11
 
45
- [![Version][👽versioni]][👽version] [![GitHub tag (latest SemVer)][⛳️tag-img]][⛳️tag] [![License: MIT][📄license-img]][📄license-ref] [![Downloads Rank][👽dl-ranki]][👽dl-rank] [![Open Source Helpers][👽oss-helpi]][👽oss-help] [![CodeCov Test Coverage][🏀codecovi]][🏀codecov] [![Coveralls Test Coverage][🏀coveralls-img]][🏀coveralls] [![QLTY Test Coverage][🏀qlty-covi]][🏀qlty-cov] [![QLTY Maintainability][🏀qlty-mnti]][🏀qlty-mnt] [![CI Heads][🚎3-hd-wfi]][🚎3-hd-wf] [![CI Runtime Dependencies @ HEAD][🚎12-crh-wfi]][🚎12-crh-wf] [![CI Current][🚎11-c-wfi]][🚎11-c-wf] [![CI Truffle Ruby][🚎9-t-wfi]][🚎9-t-wf] [![CI JRuby][🚎10-j-wfi]][🚎10-j-wf] [![Deps Locked][🚎13-🔒️-wfi]][🚎13-🔒️-wf] [![Deps Unlocked][🚎14-🔓️-wfi]][🚎14-🔓️-wf] [![CI Supported][🚎6-s-wfi]][🚎6-s-wf] [![CI Legacy][🚎4-lg-wfi]][🚎4-lg-wf] [![CI Unsupported][🚎7-us-wfi]][🚎7-us-wf] [![CI Ancient][🚎1-an-wfi]][🚎1-an-wf] [![CI Test Coverage][🚎2-cov-wfi]][🚎2-cov-wf] [![CI Style][🚎5-st-wfi]][🚎5-st-wf] [![CodeQL][🖐codeQL-img]][🖐codeQL] [![Apache SkyWalking Eyes License Compatibility Check][🚎15-🪪-wfi]][🚎15-🪪-wf]
12
+ [![Version][👽versioni]][👽dl-rank] [![GitHub tag (latest SemVer)][⛳️tag-img]][⛳️tag] [![License: MIT][📄license-img]][📄license-ref] [![Downloads Rank][👽dl-ranki]][👽dl-rank] [![Open Source Helpers][👽oss-helpi]][👽oss-help] [![CodeCov Test Coverage][🏀codecovi]][🏀codecov] [![Coveralls Test Coverage][🏀coveralls-img]][🏀coveralls] [![QLTY Test Coverage][🏀qlty-covi]][🏀qlty-cov] [![QLTY Maintainability][🏀qlty-mnti]][🏀qlty-mnt] [![CI Heads][🚎3-hd-wfi]][🚎3-hd-wf] [![CI Runtime Dependencies @ HEAD][🚎12-crh-wfi]][🚎12-crh-wf] [![CI Current][🚎11-c-wfi]][🚎11-c-wf] [![CI Truffle Ruby][🚎9-t-wfi]][🚎9-t-wf] [![CI JRuby][🚎10-j-wfi]][🚎10-j-wf] [![Deps Locked][🚎13-🔒️-wfi]][🚎13-🔒️-wf] [![Deps Unlocked][🚎14-🔓️-wfi]][🚎14-🔓️-wf] [![CI Supported][🚎6-s-wfi]][🚎6-s-wf] [![CI Legacy][🚎4-lg-wfi]][🚎4-lg-wf] [![CI Unsupported][🚎7-us-wfi]][🚎7-us-wf] [![CI Ancient][🚎1-an-wfi]][🚎1-an-wf] [![CI Test Coverage][🚎2-cov-wfi]][🚎2-cov-wf] [![CI Style][🚎5-st-wfi]][🚎5-st-wf] [![CodeQL][🖐codeQL-img]][🖐codeQL] [![Apache SkyWalking Eyes License Compatibility Check][🚎15-🪪-wfi]][🚎15-🪪-wf]
46
13
 
47
14
  `if ci_badges.map(&:color).detect { it != "green"}` ☝️ [let me know][🖼️galtzo-discord], as I may have missed the [discord notification][🖼️galtzo-discord].
48
15
 
49
- ---
16
+ -----
50
17
 
51
18
  `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.
52
19
 
53
20
  [![OpenCollective Backers][🖇osc-backers-i]][🖇osc-backers] [![OpenCollective Sponsors][🖇osc-sponsors-i]][🖇osc-sponsors] [![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 on Polar][🖇polar-img]][🖇polar] [![Donate at ko-fi.com][🖇kofi-img]][🖇kofi]
54
21
 
22
+ <details>
23
+ <summary>👣 How will this project approach the September 2025 hostile takeover of RubyGems? 🚑️</summary>
24
+
25
+ I've summarized my thoughts in [this blog post](https://dev.to/galtzo/hostile-takeover-of-rubygems-my-thoughts-5hlo).
26
+
27
+ </details>
28
+
55
29
  ## 🌻 Synopsis
56
30
 
57
31
  Run the one-time project bootstrapper:
@@ -81,52 +55,201 @@ bundle exec rake kettle:dev:install
81
55
  Making sure to review the changes, and retain overwritten bits that matter.
82
56
 
83
57
  Later, when ready to release:
58
+
84
59
  ```console
85
60
  bin/kettle-changelog
86
61
  bin/kettle-release
87
62
  ```
88
63
 
64
+ ### The `*-merge` Gem Family
65
+
66
+ The `*-merge` gem family provides intelligent, AST-based merging for various file formats. At the foundation is [tree_haver][tree_haver], which provides a unified cross-Ruby parsing API that works seamlessly across MRI, JRuby, and TruffleRuby.
67
+
68
+ | Gem | Version / CI | Language<br>/ Format | Parser Backend(s) | Description |
69
+ |------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------:|----------------------|-------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------|
70
+ | [tree_haver][tree_haver] | [![Version][tree_haver-gem-i]][tree_haver-gem] <br/> [![CI][tree_haver-ci-i]][tree_haver-ci] | Multi | Supported Backends: MRI C, Rust, FFI, Java, Prism, Psych, Commonmarker, Markly, Citrus, Parslet | **Foundation**: Cross-Ruby adapter for parsing libraries (like Faraday for HTTP) |
71
+ | [ast-merge][ast-merge] | [![Version][ast-merge-gem-i]][ast-merge-gem] <br/> [![CI][ast-merge-ci-i]][ast-merge-ci] | Text | internal | **Infrastructure**: Shared base classes and merge logic for all `*-merge` gems |
72
+ | [bash-merge][bash-merge] | [![Version][bash-merge-gem-i]][bash-merge-gem] <br/> [![CI][bash-merge-ci-i]][bash-merge-ci] | Bash | [tree-sitter-bash][ts-bash] (via tree_haver) | Smart merge for Bash scripts |
73
+ | [commonmarker-merge][commonmarker-merge] | [![Version][commonmarker-merge-gem-i]][commonmarker-merge-gem] <br/> [![CI][commonmarker-merge-ci-i]][commonmarker-merge-ci] | Markdown | [Commonmarker][commonmarker] (via tree_haver) | Smart merge for Markdown (CommonMark via comrak Rust) |
74
+ | [dotenv-merge][dotenv-merge] | [![Version][dotenv-merge-gem-i]][dotenv-merge-gem] <br/> [![CI][dotenv-merge-ci-i]][dotenv-merge-ci] | Dotenv | internal | Smart merge for `.env` files |
75
+ | [json-merge][json-merge] | [![Version][json-merge-gem-i]][json-merge-gem] <br/> [![CI][json-merge-ci-i]][json-merge-ci] | JSON | [tree-sitter-json][ts-json] (via tree_haver) | Smart merge for JSON files |
76
+ | [jsonc-merge][jsonc-merge] | [![Version][jsonc-merge-gem-i]][jsonc-merge-gem] <br/> [![CI][jsonc-merge-ci-i]][jsonc-merge-ci] | JSONC | [tree-sitter-jsonc][ts-jsonc] (via tree_haver) | ⚠️ Proof of concept; Smart merge for JSON with Comments |
77
+ | [markdown-merge][markdown-merge] | [![Version][markdown-merge-gem-i]][markdown-merge-gem] <br/> [![CI][markdown-merge-ci-i]][markdown-merge-ci] | Markdown | [Commonmarker][commonmarker] / [Markly][markly] (via tree_haver), [Parslet][parslet] | **Foundation**: Shared base for Markdown mergers with inner code block merging |
78
+ | [markly-merge][markly-merge] | [![Version][markly-merge-gem-i]][markly-merge-gem] <br/> [![CI][markly-merge-ci-i]][markly-merge-ci] | Markdown | [Markly][markly] (via tree_haver) | Smart merge for Markdown (CommonMark via cmark-gfm C) |
79
+ | [prism-merge][prism-merge] | [![Version][prism-merge-gem-i]][prism-merge-gem] <br/> [![CI][prism-merge-ci-i]][prism-merge-ci] | Ruby | [Prism][prism] (`prism` std lib gem) | Smart merge for Ruby source files |
80
+ | [psych-merge][psych-merge] | [![Version][psych-merge-gem-i]][psych-merge-gem] <br/> [![CI][psych-merge-ci-i]][psych-merge-ci] | YAML | [Psych][psych] (`psych` std lib gem) | Smart merge for YAML files |
81
+ | [rbs-merge][rbs-merge] | [![Version][rbs-merge-gem-i]][rbs-merge-gem] <br/> [![CI][rbs-merge-ci-i]][rbs-merge-ci] | RBS | [tree-sitter-rbs][ts-rbs] (via tree_haver), [RBS][rbs] (`rbs` std lib gem) | Smart merge for Ruby type signatures |
82
+ | [toml-merge][toml-merge] | [![Version][toml-merge-gem-i]][toml-merge-gem] <br/> [![CI][toml-merge-ci-i]][toml-merge-ci] | TOML | [Parslet + toml][toml], [Citrus + toml-rb][toml-rb], [tree-sitter-toml][ts-toml] (all via tree_haver) | Smart merge for TOML files |
83
+
84
+ #### Backend Platform Compatibility
85
+
86
+ tree_haver supports multiple parsing backends, but not all backends work on all Ruby platforms:
87
+
88
+ | Platform 👉️<br> TreeHaver Backend 👇️ | MRI | JRuby | TruffleRuby | Notes |
89
+ |-------------------------------------------------|:---:|:-----:|:-----------:|----------------------------------------------------------------------------|
90
+ | **MRI** ([ruby_tree_sitter][ruby_tree_sitter]) | ✅ | ❌ | ❌ | C extension, MRI only |
91
+ | **Rust** ([tree_stump][tree_stump]) | ✅ | ❌ | ❌ | Rust extension via magnus/rb-sys, MRI only |
92
+ | **FFI** ([ffi][ffi]) | ✅ | ✅ | ❌ | TruffleRuby's FFI doesn't support `STRUCT_BY_VALUE` |
93
+ | **Java** ([jtreesitter][jtreesitter]) | ❌ | ✅ | ❌ | JRuby only, requires grammar JARs |
94
+ | **Prism** ([prism][prism]) | ✅ | ✅ | ✅ | Ruby parsing, stdlib in Ruby 3.4+ |
95
+ | **Psych** ([psych][psych]) | ✅ | ✅ | ✅ | YAML parsing, stdlib |
96
+ | **Citrus** ([citrus][citrus]) | ✅ | ✅ | ✅ | Pure Ruby PEG parser, no native dependencies |
97
+ | **Parslet** ([parslet][parslet]) | ✅ | ✅ | ✅ | Pure Ruby PEG parser, no native dependencies |
98
+ | **Commonmarker** ([commonmarker][commonmarker]) | ✅ | ❌ | ❓ | Rust extension for Markdown (via [commonmarker-merge][commonmarker-merge]) |
99
+ | **Markly** ([markly][markly]) | ✅ | ❌ | ❓ | C extension for Markdown (via [markly-merge][markly-merge]) |
100
+
101
+ **Legend**: ✅ = Works, ❌ = Does not work, ❓ = Untested
102
+
103
+ **Why some backends don't work on certain platforms**:
104
+
105
+ - **JRuby**: Runs on the JVM; cannot load native C/Rust extensions (`.so` files)
106
+ - **TruffleRuby**: Has C API emulation via Sulong/LLVM, but it doesn't expose all MRI internals that native extensions require (e.g., `RBasic.flags`, `rb_gc_writebarrier`)
107
+ - **FFI on TruffleRuby**: TruffleRuby's FFI implementation doesn't support returning structs by value, which tree-sitter's C API requires
108
+
109
+ **Example implementations** for the gem templating use case:
110
+
111
+ | Gem | Purpose | Description |
112
+ |--------------------------|-----------------|-----------------------------------------------|
113
+ | [kettle-dev][kettle-dev] | Gem Development | Development tooling, CI automation, and release workflows |
114
+ | [kettle-jem][kettle-jem] | Gem Templating | Gem template library with smart merge support |
115
+
116
+ [tree_haver]: https://github.com/kettle-rb/tree_haver
117
+ [ast-merge]: https://github.com/kettle-rb/ast-merge
118
+ [prism-merge]: https://github.com/kettle-rb/prism-merge
119
+ [psych-merge]: https://github.com/kettle-rb/psych-merge
120
+ [json-merge]: https://github.com/kettle-rb/json-merge
121
+ [jsonc-merge]: https://github.com/kettle-rb/jsonc-merge
122
+ [bash-merge]: https://github.com/kettle-rb/bash-merge
123
+ [rbs-merge]: https://github.com/kettle-rb/rbs-merge
124
+ [dotenv-merge]: https://github.com/kettle-rb/dotenv-merge
125
+ [toml-merge]: https://github.com/kettle-rb/toml-merge
126
+ [markdown-merge]: https://github.com/kettle-rb/markdown-merge
127
+ [markly-merge]: https://github.com/kettle-rb/markly-merge
128
+ [commonmarker-merge]: https://github.com/kettle-rb/commonmarker-merge
129
+ [kettle-dev]: https://github.com/kettle-rb/kettle-dev
130
+ [kettle-jem]: https://github.com/kettle-rb/kettle-jem
131
+ [tree_haver-gem]: https://bestgems.org/gems/tree_haver
132
+ [ast-merge-gem]: https://bestgems.org/gems/ast-merge
133
+ [prism-merge-gem]: https://bestgems.org/gems/prism-merge
134
+ [psych-merge-gem]: https://bestgems.org/gems/psych-merge
135
+ [json-merge-gem]: https://bestgems.org/gems/json-merge
136
+ [jsonc-merge-gem]: https://bestgems.org/gems/jsonc-merge
137
+ [bash-merge-gem]: https://bestgems.org/gems/bash-merge
138
+ [rbs-merge-gem]: https://bestgems.org/gems/rbs-merge
139
+ [dotenv-merge-gem]: https://bestgems.org/gems/dotenv-merge
140
+ [toml-merge-gem]: https://bestgems.org/gems/toml-merge
141
+ [markdown-merge-gem]: https://bestgems.org/gems/markdown-merge
142
+ [markly-merge-gem]: https://bestgems.org/gems/markly-merge
143
+ [commonmarker-merge-gem]: https://bestgems.org/gems/commonmarker-merge
144
+ [kettle-dev-gem]: https://bestgems.org/gems/kettle-dev
145
+ [kettle-jem-gem]: https://bestgems.org/gems/kettle-jem
146
+ [tree_haver-gem-i]: https://img.shields.io/gem/v/tree_haver.svg
147
+ [ast-merge-gem-i]: https://img.shields.io/gem/v/ast-merge.svg
148
+ [prism-merge-gem-i]: https://img.shields.io/gem/v/prism-merge.svg
149
+ [psych-merge-gem-i]: https://img.shields.io/gem/v/psych-merge.svg
150
+ [json-merge-gem-i]: https://img.shields.io/gem/v/json-merge.svg
151
+ [jsonc-merge-gem-i]: https://img.shields.io/gem/v/jsonc-merge.svg
152
+ [bash-merge-gem-i]: https://img.shields.io/gem/v/bash-merge.svg
153
+ [rbs-merge-gem-i]: https://img.shields.io/gem/v/rbs-merge.svg
154
+ [dotenv-merge-gem-i]: https://img.shields.io/gem/v/dotenv-merge.svg
155
+ [toml-merge-gem-i]: https://img.shields.io/gem/v/toml-merge.svg
156
+ [markdown-merge-gem-i]: https://img.shields.io/gem/v/markdown-merge.svg
157
+ [markly-merge-gem-i]: https://img.shields.io/gem/v/markly-merge.svg
158
+ [commonmarker-merge-gem-i]: https://img.shields.io/gem/v/commonmarker-merge.svg
159
+ [kettle-dev-gem-i]: https://img.shields.io/gem/v/kettle-dev.svg
160
+ [kettle-jem-gem-i]: https://img.shields.io/gem/v/kettle-jem.svg
161
+ [tree_haver-ci-i]: https://github.com/kettle-rb/tree_haver/actions/workflows/current.yml/badge.svg
162
+ [ast-merge-ci-i]: https://github.com/kettle-rb/ast-merge/actions/workflows/current.yml/badge.svg
163
+ [prism-merge-ci-i]: https://github.com/kettle-rb/prism-merge/actions/workflows/current.yml/badge.svg
164
+ [psych-merge-ci-i]: https://github.com/kettle-rb/psych-merge/actions/workflows/current.yml/badge.svg
165
+ [json-merge-ci-i]: https://github.com/kettle-rb/json-merge/actions/workflows/current.yml/badge.svg
166
+ [jsonc-merge-ci-i]: https://github.com/kettle-rb/jsonc-merge/actions/workflows/current.yml/badge.svg
167
+ [bash-merge-ci-i]: https://github.com/kettle-rb/bash-merge/actions/workflows/current.yml/badge.svg
168
+ [rbs-merge-ci-i]: https://github.com/kettle-rb/rbs-merge/actions/workflows/current.yml/badge.svg
169
+ [dotenv-merge-ci-i]: https://github.com/kettle-rb/dotenv-merge/actions/workflows/current.yml/badge.svg
170
+ [toml-merge-ci-i]: https://github.com/kettle-rb/toml-merge/actions/workflows/current.yml/badge.svg
171
+ [markdown-merge-ci-i]: https://github.com/kettle-rb/markdown-merge/actions/workflows/current.yml/badge.svg
172
+ [markly-merge-ci-i]: https://github.com/kettle-rb/markly-merge/actions/workflows/current.yml/badge.svg
173
+ [commonmarker-merge-ci-i]: https://github.com/kettle-rb/commonmarker-merge/actions/workflows/current.yml/badge.svg
174
+ [kettle-dev-ci-i]: https://github.com/kettle-rb/kettle-dev/actions/workflows/current.yml/badge.svg
175
+ [kettle-jem-ci-i]: https://github.com/kettle-rb/kettle-jem/actions/workflows/current.yml/badge.svg
176
+ [tree_haver-ci]: https://github.com/kettle-rb/tree_haver/actions/workflows/current.yml
177
+ [ast-merge-ci]: https://github.com/kettle-rb/ast-merge/actions/workflows/current.yml
178
+ [prism-merge-ci]: https://github.com/kettle-rb/prism-merge/actions/workflows/current.yml
179
+ [psych-merge-ci]: https://github.com/kettle-rb/psych-merge/actions/workflows/current.yml
180
+ [json-merge-ci]: https://github.com/kettle-rb/json-merge/actions/workflows/current.yml
181
+ [jsonc-merge-ci]: https://github.com/kettle-rb/jsonc-merge/actions/workflows/current.yml
182
+ [bash-merge-ci]: https://github.com/kettle-rb/bash-merge/actions/workflows/current.yml
183
+ [rbs-merge-ci]: https://github.com/kettle-rb/rbs-merge/actions/workflows/current.yml
184
+ [dotenv-merge-ci]: https://github.com/kettle-rb/dotenv-merge/actions/workflows/current.yml
185
+ [toml-merge-ci]: https://github.com/kettle-rb/toml-merge/actions/workflows/current.yml
186
+ [markdown-merge-ci]: https://github.com/kettle-rb/markdown-merge/actions/workflows/current.yml
187
+ [markly-merge-ci]: https://github.com/kettle-rb/markly-merge/actions/workflows/current.yml
188
+ [commonmarker-merge-ci]: https://github.com/kettle-rb/commonmarker-merge/actions/workflows/current.yml
189
+ [kettle-dev-ci]: https://github.com/kettle-rb/kettle-dev/actions/workflows/current.yml
190
+ [kettle-jem-ci]: https://github.com/kettle-rb/kettle-jem/actions/workflows/current.yml
191
+ [prism]: https://github.com/ruby/prism
192
+ [psych]: https://github.com/ruby/psych
193
+ [ffi]: https://github.com/ffi/ffi
194
+ [ts-json]: https://github.com/tree-sitter/tree-sitter-json
195
+ [ts-jsonc]: https://gitlab.com/WhyNotHugo/tree-sitter-jsonc
196
+ [ts-bash]: https://github.com/tree-sitter/tree-sitter-bash
197
+ [ts-rbs]: https://github.com/joker1007/tree-sitter-rbs
198
+ [ts-toml]: https://github.com/tree-sitter-grammars/tree-sitter-toml
199
+ [dotenv]: https://github.com/bkeepers/dotenv
200
+ [rbs]: https://github.com/ruby/rbs
201
+ [toml-rb]: https://github.com/emancu/toml-rb
202
+ [toml]: https://github.com/jm/toml
203
+ [markly]: https://github.com/ioquatix/markly
204
+ [commonmarker]: https://github.com/gjtorikian/commonmarker
205
+ [ruby_tree_sitter]: https://github.com/Faveod/ruby-tree-sitter
206
+ [tree_stump]: https://github.com/joker1007/tree_stump
207
+ [jtreesitter]: https://central.sonatype.com/artifact/io.github.tree-sitter/jtreesitter
208
+ [citrus]: https://github.com/mjackson/citrus
209
+ [parslet]: https://github.com/kschiess/parslet
210
+
89
211
  ## 💡 Info you can shake a stick at
90
212
 
91
- | Tokens to Remember | [![Gem name][⛳️name-img]][⛳️gem-name] [![Gem namespace][⛳️namespace-img]][⛳️gem-namespace] |
92
- |-------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
93
- | Works with JRuby | ![JRuby 9.1 Compat][💎jruby-9.1i] ![JRuby 9.2 Compat][💎jruby-9.2i] ![JRuby 9.3 Compat][💎jruby-9.3i] <br/> [![JRuby 9.4 Compat][💎jruby-9.4i]][🚎10-j-wf] [![JRuby 10.0 Compat][💎jruby-c-i]][🚎11-c-wf] [![JRuby HEAD Compat][💎jruby-headi]][🚎3-hd-wf] |
94
- | Works with Truffle Ruby | ![Truffle Ruby 22.3 Compat][💎truby-22.3i] ![Truffle Ruby 23.0 Compat][💎truby-23.0i] <br/> [![Truffle Ruby 23.1 Compat][💎truby-23.1i]][🚎9-t-wf] [![Truffle Ruby 24.1 Compat][💎truby-c-i]][🚎11-c-wf] |
95
- | Works with MRI Ruby 3 | [![Ruby 3.0 Compat][💎ruby-3.0i]][🚎4-lg-wf] [![Ruby 3.1 Compat][💎ruby-3.1i]][🚎6-s-wf] [![Ruby 3.2 Compat][💎ruby-3.2i]][🚎6-s-wf] [![Ruby 3.3 Compat][💎ruby-3.3i]][🚎6-s-wf] [![Ruby 3.4 Compat][💎ruby-c-i]][🚎11-c-wf] [![Ruby HEAD Compat][💎ruby-headi]][🚎3-hd-wf] |
96
- | Works with MRI Ruby 2 | [![Ruby 2.3 Compat][💎ruby-2.3i]][🚎1-an-wf] [![Ruby 2.4 Compat][💎ruby-2.4i]][🚎1-an-wf] [![Ruby 2.5 Compat][💎ruby-2.5i]][🚎1-an-wf] [![Ruby 2.6 Compat][💎ruby-2.6i]][🚎7-us-wf] [![Ruby 2.7 Compat][💎ruby-2.7i]][🚎7-us-wf] |
97
- | Support & Community | [![Join Me on Daily.dev's RubyFriends][✉️ruby-friends-img]][✉️ruby-friends] [![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] |
98
- | 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] |
99
- | 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] |
100
- | Compliance | [![License: MIT][📄license-img]][📄license-ref] [![Compatible with Apache Software Projects: Verified by SkyWalking Eyes][📄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] |
101
- | 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] |
102
- | 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] |
103
- | `...` 💖 | [![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] |
213
+ | Tokens to Remember | [![Gem name][⛳️name-img]][👽dl-rank] [![Gem namespace][⛳️namespace-img]][📜src-gh] |
214
+ |-------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
215
+ | Works with JRuby | ![JRuby 9.1 Compat][💎jruby-9.1i] ![JRuby 9.2 Compat][💎jruby-9.2i] ![JRuby 9.3 Compat][💎jruby-9.3i] <br/> [![JRuby 9.4 Compat][💎jruby-9.4i]][🚎10-j-wf] [![JRuby 10.0 Compat][💎jruby-c-i]][🚎11-c-wf] [![JRuby HEAD Compat][💎jruby-headi]][🚎3-hd-wf] |
216
+ | Works with Truffle Ruby | ![Truffle Ruby 22.3 Compat][💎truby-22.3i] ![Truffle Ruby 23.0 Compat][💎truby-23.0i] <br/> [![Truffle Ruby 23.1 Compat][💎truby-23.1i]][🚎9-t-wf] [![Truffle Ruby 24.1 Compat][💎truby-c-i]][🚎11-c-wf] |
217
+ | Works with MRI Ruby 3 | [![Ruby 3.0 Compat][💎ruby-3.0i]][🚎4-lg-wf] [![Ruby 3.1 Compat][💎ruby-3.1i]][🚎6-s-wf] [\!\[Ruby 3.2 Compat\]\[💎ruby-3.2i\]][🚎6-s-wf] [![Ruby 3.3 Compat][💎ruby-3.3i]][🚎6-s-wf] [![Ruby 3.4 Compat][💎ruby-c-i]][🚎11-c-wf] [![Ruby HEAD Compat][💎ruby-headi]][🚎3-hd-wf] |
218
+ | Works with MRI Ruby 2 | [![Ruby 2.3 Compat][💎ruby-2.3i]][🚎1-an-wf] [![Ruby 2.4 Compat][💎ruby-2.4i]][🚎1-an-wf] [![Ruby 2.5 Compat][💎ruby-2.5i]][🚎1-an-wf] [![Ruby 2.6 Compat][💎ruby-2.6i]][🚎7-us-wf] [![Ruby 2.7 Compat][💎ruby-2.7i]][🚎7-us-wf] |
219
+ | Support & Community | [![Join Me on Daily.dev's RubyFriends][✉️ruby-friends-img]][✉️ruby-friends] [![Live Chat on Discord][✉️discord-invite-img-ftb]][🖼️galtzo-discord] [![Get help from me on Upwork][👨🏼‍🏫expsup-upwork-img]][👨🏼‍🏫expsup-upwork] [![Get help from me on Codementor][👨🏼‍🏫expsup-codementor-img]][👨🏼‍🏫expsup-codementor] |
220
+ | 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] |
221
+ | 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] |
222
+ | Compliance | [![License: MIT][📄license-img]][📄license-ref] [![Compatible with Apache Software Projects: Verified by SkyWalking Eyes][📄license-compat-img]][📄license-compat] [![📄ilo-declaration-img][📄ilo-declaration-img]][📄ilo-declaration] [![Security Policy][🔐security-img]][🔐security] [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct] [![SemVer 2.0.0][📌semver-img]][📌semver] |
223
+ | 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] |
224
+ | 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] |
225
+ | `...` 💖 | [![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] |
104
226
 
105
227
  ### Compatibility
106
228
 
107
- Compatible with MRI Ruby 2.3+, and concordant releases of JRuby, and TruffleRuby.
229
+ Compatible with MRI Ruby 2.3.0+, and concordant releases of JRuby, and TruffleRuby.
230
+ Templating features (AST-aware merging) are provided by [kettle-jem][kettle-jem], which requires Ruby 3.2+ and relies on [prism-merge][prism-merge]. It is recommended to run the template tasks / scripts in the latest release of Ruby\!
108
231
 
109
- | 🚚 _Amazing_ test matrix was brought to you by | 🔎 appraisal2 🔎 and the color 💚 green 💚 |
110
- |------------------------------------------------|--------------------------------------------------------|
111
- | 👟 Check it out! | ✨ [github.com/appraisal-rb/appraisal2][💎appraisal2] ✨ |
232
+ | 🚚 *Amazing* test matrix was brought to you by | 🔎 appraisal2 🔎 and the color 💚 green 💚 |
233
+ | --- | --- |
234
+ | 👟 Check it out\! | ✨ [github.com/appraisal-rb/appraisal2][💎appraisal2] ✨ |
112
235
 
113
236
  ### Federated DVCS
114
237
 
115
238
  <details markdown="1">
116
239
  <summary>Find this repo on federated forges (Coming soon!)</summary>
117
240
 
118
- | Federated [DVCS][💎d-in-dvcs] Repository | Status | Issues | PRs | Wiki | CI | Discussions |
119
- |-------------------------------------------------|-----------------------------------------------------------------------|---------------------------|--------------------------|---------------------------|--------------------------|------------------------------|
120
- | 🧪 [kettle-rb/kettle-dev on GitLab][📜src-gl] | The Truth | [💚][🤝gl-issues] | [💚][🤝gl-pulls] | [💚][📜gl-wiki] | 🐭 Tiny Matrix | ➖ |
121
- | 🧊 [kettle-rb/kettle-dev on CodeBerg][📜src-cb] | An Ethical Mirror ([Donate][🤝cb-donate]) | [💚][🤝cb-issues] | [💚][🤝cb-pulls] | ➖ | ⭕️ No Matrix | ➖ |
122
- | 🐙 [kettle-rb/kettle-dev on GitHub][📜src-gh] | Another Mirror | [💚][🤝gh-issues] | [💚][🤝gh-pulls] | [💚][📜gh-wiki] | 💯 Full Matrix | [💚][gh-discussions] |
123
- | 🎮️ [Discord Server][✉️discord-invite] | [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite] | [Let's][✉️discord-invite] | [talk][✉️discord-invite] | [about][✉️discord-invite] | [this][✉️discord-invite] | [library!][✉️discord-invite] |
241
+ | Federated [DVCS][💎d-in-dvcs] Repository | Status | Issues | PRs | Wiki | CI | Discussions |
242
+ | --- | --- | --- | --- | --- | --- | --- |
243
+ | 🧪 [kettle-rb/kettle-dev on GitLab][📜src-gl] | The Truth | [💚][🤝gl-issues] | [💚][🤝gl-pulls] | [💚][📜gl-wiki] | 🐭 Tiny Matrix | ➖ |
244
+ | 🧊 [kettle-rb/kettle-dev on CodeBerg][📜src-cb] | An Ethical Mirror ([Donate][🤝cb-donate]) | [💚][🤝cb-issues] | [💚][🤝cb-pulls] | ➖ | ⭕️ No Matrix | ➖ |
245
+ | 🐙 [kettle-rb/kettle-dev on GitHub][📜src-gh] | Another Mirror | [💚][🤝gh-issues] | [💚][🤝gh-pulls] | [💚][📜gh-wiki] | 💯 Full Matrix | [💚][gh-discussions] |
246
+ | 🎮️ [Discord Server][🖼️galtzo-discord] | [![Live Chat on Discord][✉️discord-invite-img-ftb]][🖼️galtzo-discord] | [Let's][🖼️galtzo-discord] | [talk][🖼️galtzo-discord] | [about][🖼️galtzo-discord] | [this][🖼️galtzo-discord] | [library\!][🖼️galtzo-discord] |
124
247
 
125
248
  </details>
126
249
 
127
250
  [gh-discussions]: https://github.com/kettle-rb/kettle-dev/discussions
128
251
 
129
- ### Enterprise Support [![Tidelift](https://tidelift.com/badges/package/rubygems/kettle-dev)](https://tidelift.com/subscription/pkg/rubygems-kettle-dev?utm_source=rubygems-kettle-dev&utm_medium=referral&utm_campaign=readme)
252
+ ### Enterprise Support [![Tidelift](https://tidelift.com/badges/package/rubygems/kettle-dev)][🏙️entsup-tidelift]
130
253
 
131
254
  Available as part of the Tidelift Subscription.
132
255
 
@@ -137,14 +260,17 @@ The maintainers of this and thousands of other packages are working with Tidelif
137
260
 
138
261
  [![Get help from me on Tidelift][🏙️entsup-tidelift-img]][🏙️entsup-tidelift]
139
262
 
140
- - 💡Subscribe for support guarantees covering _all_ your FLOSS dependencies
263
+ - 💡Subscribe for support guarantees covering *all* your FLOSS dependencies
264
+
141
265
  - 💡Tidelift is part of [Sonar][🏙️entsup-tidelift-sonar]
142
- - 💡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
143
266
 
144
- Alternatively:
267
+ - 💡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
268
+ Alternatively:
269
+
270
+ - [![Live Chat on Discord][✉️discord-invite-img-ftb]][🖼️galtzo-discord]
145
271
 
146
- - [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite]
147
272
  - [![Get help from me on Upwork][👨🏼‍🏫expsup-upwork-img]][👨🏼‍🏫expsup-upwork]
273
+
148
274
  - [![Get help from me on Codementor][👨🏼‍🏫expsup-codementor-img]][👨🏼‍🏫expsup-codementor]
149
275
 
150
276
  </details>
@@ -168,11 +294,11 @@ gem install kettle-dev
168
294
  <details markdown="1">
169
295
  <summary>For Medium or High Security Installations</summary>
170
296
 
171
- This gem is cryptographically signed, and has verifiable [SHA-256 and SHA-512][💎SHA_checksums] checksums by
172
- [stone_checksums][💎stone_checksums]. Be sure the gem you install hasn’t been tampered with
297
+ This gem is cryptographically signed and has verifiable [SHA-256 and SHA-512][💎SHA_checksums] checksums by
298
+ [stone\_checksums][💎stone_checksums]. Be sure the gem you install hasn’t been tampered with
173
299
  by following the instructions below.
174
300
 
175
- Add my public key (if you haven’t already, expires 2045-04-29) as a trusted certificate:
301
+ Add my public key (if you haven’t already; key expires 2045-04-29) as a trusted certificate:
176
302
 
177
303
  ```console
178
304
  gem cert --add <(curl -Ls https://raw.github.com/galtzo-floss/certs/main/pboling.pem)
@@ -201,7 +327,8 @@ NOTE: Be prepared to track down certs for signed gems and add them the same way
201
327
  ## ⚙️ Configuration
202
328
 
203
329
  Note on executables vs Rake tasks
204
- - Executable scripts provided by this gem (exe/* and installed binstubs) work when the gem is installed as a system gem (gem install kettle-dev). They do not require the gem to be in your bundle to run.
330
+
331
+ - Executable scripts provided by this gem (exe/\* and installed binstubs) work when the gem is installed as a system gem (gem install kettle-dev). They do not require the gem to be in your bundle to run.
205
332
  - The Rake tasks provided by this gem require kettle-dev to be declared as a development dependency in your Gemfile and loaded in your project's Rakefile. Ensure your Gemfile includes:
206
333
  ```ruby
207
334
  group :development do
@@ -255,9 +382,11 @@ kettle-dev-setup --allowed=true --force
255
382
  You'll be able to compare the changes with your diff tool, and certainly revert some of them.
256
383
 
257
384
  For your protection:
385
+
258
386
  - it won't run if git doesn't start out porcelain clean.
387
+ After bootstrapping, to update the template to the latest version from a new release of this gem, run:
259
388
 
260
- After bootstrapping, to update the template to the latest version from a new release of this gem, run:
389
+ <!-- end list -->
261
390
 
262
391
  ```console
263
392
  bundle exec rake kettle:dev:install
@@ -271,172 +400,177 @@ It may have some prompts, which can mostly be avoided by running with options:
271
400
  bundle exec rake kettle:dev:install allowed=true force=true
272
401
  ```
273
402
 
274
- Hopefully, all the files that get overwritten are tracked in git!
403
+ Hopefully, all the files that get overwritten are tracked in git\!
275
404
  I wrote this for myself, and it fits my patterns of development.
276
405
 
277
406
  The install task will write a report at the end with:
278
- 1. A file list summary of the changes made.
279
- 2. Next steps for using the tools.
280
- 3. A warning about .env.local (DO NOT COMMIT IT, as it will likely have secrets added)
281
407
 
282
- That’s it. Once installed, kettle-dev:
408
+ 1. A file list summary of the changes made.
409
+ 2. Next steps for using the tools.
410
+ 3. A warning about .env.local (DO NOT COMMIT IT, as it will likely have secrets added)
411
+ That’s it. Once installed, kettle-dev:
412
+
413
+ <!-- end list -->
414
+
283
415
  - Registers RuboCop-LTS tasks and wires your default Rake task to run the gradual linter.
284
- - Locally: default task prefers `rubocop_gradual:autocorrect`.
285
- - On CI (`CI=true`): default task prefers `rubocop_gradual:check`.
416
+ - Locally: default task prefers `rubocop_gradual:autocorrect`.
417
+ - On CI (`CI=true`): default task prefers `rubocop_gradual:check`.
286
418
  - Integrates optional coverage tasks via kettle-soup-cover (enabled locally when present).
287
419
  - Adds gem-shipped Rake tasks from `lib/kettle/dev/rakelib`, including:
288
- - `ci:act` — interactive selector for running GitHub Actions workflows via `act`.
289
- - `kettle:dev:install` — copies this repo’s .github automation, offers to install .git-hooks templates, and overwrites many files in your project.
290
- - Grapheme syncing: detects the grapheme (e.g., emoji) immediately following the first `#` H1 in README.md and ensures the same grapheme, followed by a single space, prefixes both `spec.summary` and `spec.description` in your gemspec. If the H1 has none, you’ll be prompted to enter one; tests use an input adapter, so runs never hang in CI.
291
- - option: force: When truthy (1, true, y, yes), treat all y/N prompts as Yes. Useful for non-interactive runs or to accept defaults quickly. Example: `bundle exec rake kettle:dev:template force=true`
292
- - option: allowed: When truthy (1, true, y, yes), resume task after you have reviewed `.envrc`/`.env.local` and run `direnv allow`. If either file is created or updated, the task will abort with instructions unless `allowed=true` is present. Example: `bundle exec rake kettle:dev:install allowed=true`
293
- - option: only: A comma-separated list of glob patterns to include in templating. Any destination file whose path+filename does not match one of the patterns is excluded. Patterns are matched relative to your project root. Examples: `only="README.md,.github/**"`, `only="docs/**,lib/**/*.rb"`.
294
- - option: include: A comma-separated list of glob patterns that opt-in additional, non-default files. Currently, `.github/workflows/discord-notifier.yml` is not copied by default and will only be copied when `include` matches it (e.g., `include=".github/workflows/discord-notifier.yml"`).
295
- - `kettle:dev:template` — templates files from this gem into your project (e.g., .github workflows, .devcontainer, .qlty, modular Gemfiles, README/CONTRIBUTING stubs). You can run this independently to refresh templates without the extra install prompts.
296
- - option: force: When truthy (1, true, y, yes), treat all y/N prompts as Yes. Useful for non-interactive runs or to accept defaults quickly. Example: `bundle exec rake kettle:dev:template force=true`
297
- - option: allowed: When truthy (1, true, y, yes), resume task after you have reviewed `.envrc`/`.env.local` and run `direnv allow`. If either file is created or updated, the task will abort with instructions unless `allowed=true` is present. Example: `bundle exec rake kettle:dev:template allowed=true`
298
- - option: only: Same as for install; limits which destination files are written based on glob patterns relative to the project root.
299
- - option: include: Same as for install; opts into optional files (e.g., `.github/workflows/discord-notifier.yml`).
300
-
301
- Recommended one-time setup in your project:
420
+ - `ci:act` — interactive selector for running GitHub Actions workflows via `act`.
421
+ - `kettle:dev:install` — copies this repo’s .github automation, offers to install .git-hooks templates, and overwrites many files in your project.
422
+ - Grapheme syncing: detects the grapheme (e.g., emoji) immediately following the first `#` H1 in README.md and ensures the same grapheme, followed by a single space, prefixes both `spec.summary` and `spec.description` in your gemspec. If the H1 has none, you’ll be prompted to enter one; tests use an input adapter, so runs never hang in CI.
423
+ - option: force: When truthy (1, true, y, yes), treat all y/N prompts as Yes. Useful for non-interactive runs or to accept defaults quickly. Example: `bundle exec rake kettle:dev:install force=true`
424
+ - option: allowed: When truthy (1, true, y, yes), resume task after you have reviewed `.envrc`/`.env.local` and run `direnv allow`. If either file is created or updated, the task will abort with instructions unless `allowed=true` is present. Example: `bundle exec rake kettle:dev:install allowed=true`
425
+ - option: only: A comma-separated list of glob patterns to include in templating. Any destination file whose path+filename does not match one of the patterns is excluded. Patterns are matched relative to your project root. Examples: `only="README.md,.github/**"`, `only="docs/**,lib/**/*.rb"`.
426
+ - option: include: A comma-separated list of glob patterns that opt-in additional, non-default files. Currently, `.github/workflows/discord-notifier.yml` is not copied by default and will only be copied when `include` matches it (e.g., `include=".github/workflows/discord-notifier.yml"`).
427
+ - `kettle:jem:template` (provided by [kettle-jem][kettle-jem]) — templates files from this gem into your project (e.g., .github workflows, .devcontainer, .qlty, modular Gemfiles, README/CONTRIBUTING stubs). You can run this independently to refresh templates without the extra install prompts.
428
+ - option: force: When truthy (1, true, y, yes), treat all y/N prompts as Yes. Useful for non-interactive runs or to accept defaults quickly. Example: `bundle exec rake kettle:dev:install force=true`
429
+ - option: allowed: When truthy (1, true, y, yes), resume task after you have reviewed `.envrc`/`.env.local` and run `direnv allow`. If either file is created or updated, the task will abort with instructions unless `allowed=true` is present. Example: `bundle exec rake kettle:jem:template allowed=true`
430
+ - option: only: Same as for install; limits which destination files are written based on glob patterns relative to the project root.
431
+ - option: include: Same as for install; opts into optional files (e.g., `.github/workflows/discord-notifier.yml`).
432
+ Recommended one-time setup in your project:
302
433
  - Install binstubs so kettle-dev executables are available under `./bin`:
303
- - `bundle binstubs kettle-dev --path bin`
434
+ - `bundle binstubs kettle-dev --path bin`
304
435
  - Use direnv (recommended) so `./bin` is on PATH automatically:
305
- - `brew install direnv`
306
- - In your project’s `.envrc` add:
307
- - `# Run any command in this library's bin/ without the bin/ prefix!`
308
- - `PATH_add bin`
436
+ - `brew install direnv`
437
+ - In your project’s `.envrc` add:
438
+ - `# Run any command in this library's bin/ without the bin/ prefix!`
439
+ - `PATH_add bin`
309
440
  - Configure shared git hooks path (optional, recommended):
310
- - `git config --global core.hooksPath .git-hooks`
441
+ - `git config --global core.hooksPath .git-hooks`
311
442
  - Install project automation and sample hooks/templates:
312
- - `bundle exec rake kettle:dev:install` and follow prompts (copies .github and installs .git-hooks templates locally or globally).
313
-
314
- See the next section for environment variables that tweak behavior.
443
+ - `bundle exec rake kettle:dev:install` and follow prompts (copies .github and installs .git-hooks templates locally or globally).
444
+ See the next section for environment variables that tweak behavior.
315
445
 
316
446
  ### Environment Variables
317
447
 
318
448
  Below are the primary environment variables recognized by kettle-dev (and its integrated tools). Unless otherwise noted, set boolean values to the string "true" to enable.
319
449
 
320
450
  General/runtime
321
- - DEBUG: Enable extra internal logging for this library (default: false)
322
- - REQUIRE_BENCH: Enable `require_bench` to profile requires (default: false)
323
- - CI: When set to true, adjusts default rake tasks toward CI behavior
451
+
452
+ - `DEBUG`: Enable extra internal logging for this library (default: false)
453
+ - `REQUIRE_BENCH`: Enable `require_bench` to profile requires (default: false)
454
+ - `CI`: When set to true, adjusts default rake tasks toward CI behavior
324
455
 
325
456
  Coverage (kettle-soup-cover / SimpleCov)
326
- - K_SOUP_COV_DO: Enable coverage collection (default: true in .envrc)
327
- - K_SOUP_COV_FORMATTERS: Comma-separated list of formatters (html, xml, rcov, lcov, json, tty)
328
- - K_SOUP_COV_MIN_LINE: Minimum line coverage threshold (integer, e.g., 100)
329
- - K_SOUP_COV_MIN_BRANCH: Minimum branch coverage threshold (integer, e.g., 100)
330
- - K_SOUP_COV_MIN_HARD: Fail the run if thresholds are not met (true/false)
331
- - K_SOUP_COV_MULTI_FORMATTERS: Enable multiple formatters at once (true/false)
332
- - K_SOUP_COV_OPEN_BIN: Path to browser opener for HTML (empty disables auto-open)
333
- - MAX_ROWS: Limit console output rows for simplecov-console (e.g., 1)
457
+
458
+ - `K_SOUP_COV_DO`: Enable coverage collection (default: true in .envrc)
459
+ - `K_SOUP_COV_FORMATTERS`: Comma-separated list of formatters (html, xml, rcov, lcov, json, tty)
460
+ - `K_SOUP_COV_MIN_LINE`: Minimum line coverage threshold (integer, e.g., 100)
461
+ - `K_SOUP_COV_MIN_BRANCH`: Minimum branch coverage threshold (integer, e.g., 100)
462
+ - `K_SOUP_COV_MIN_HARD`: Fail the run if thresholds are not met (true/false)
463
+ - `K_SOUP_COV_MULTI_FORMATTERS`: Enable multiple formatters at once (true/false)
464
+ - `K_SOUP_COV_OPEN_BIN`: Path to browser opener for HTML (empty disables auto-open)
465
+ - `MAX_ROWS`: Limit console output rows for simplecov-console (e.g., 1)
466
+
334
467
  Tip: When running a single spec file locally, you may want `K_SOUP_COV_MIN_HARD=false` to avoid failing thresholds for a partial run.
335
468
 
336
469
  GitHub API and CI helpers
337
- - GITHUB_TOKEN or GH_TOKEN: Token used by `ci:act` and release workflow checks to query GitHub Actions status at higher rate limits
338
- - GITLAB_TOKEN or GL_TOKEN: Token used by `ci:act` and CI monitor to query GitLab pipeline status
470
+
471
+ - `GITHUB_TOKEN` or `GH_TOKEN`: Token used by `ci:act` and release workflow checks to query GitHub Actions status at higher rate limits
472
+ - `GITLAB_TOKEN` or `GL_TOKEN`: Token used by `ci:act` and CI monitor to query GitLab pipeline status
339
473
 
340
474
  Releasing and signing
341
- - SKIP_GEM_SIGNING: If set, skip gem signing during build/release
342
- - GEM_CERT_USER: Username for selecting your public cert in `certs/<USER>.pem` (defaults to $USER)
343
- - SOURCE_DATE_EPOCH: Reproducible build timestamp. `kettle-release` will set this automatically for the session.
475
+
476
+ - `SKIP_GEM_SIGNING`: If set, skip gem signing during build/release
477
+ - `GEM_CERT_USER`: Username for selecting your public cert in `certs/<USER>.pem` (defaults to $USER)
478
+ - `SOURCE_DATE_EPOCH`: Reproducible build timestamp. `kettle-release` will set this automatically for the session.
344
479
 
345
480
  Git hooks and commit message helpers (exe/kettle-commit-msg)
346
- - GIT_HOOK_BRANCH_VALIDATE: Branch name validation mode (e.g., `jira`) or `false` to disable
347
- - GIT_HOOK_FOOTER_APPEND: Append a footer to commit messages when goalie allows (true/false)
348
- - GIT_HOOK_FOOTER_SENTINEL: Required when footer append is enabled a unique first-line sentinel to prevent duplicates
349
- - GIT_HOOK_FOOTER_APPEND_DEBUG: Extra debug output in the footer template (true/false)
481
+
482
+ - `GIT_HOOK_BRANCH_VALIDATE`: Branch name validation mode (e.g., `jira`) or `false` to disable
483
+ - `GIT_HOOK_FOOTER_APPEND`: Append a footer to commit messages when goalie allows (true/false)
484
+ - `GIT_HOOK_FOOTER_SENTINEL`: Required when footer append is enabled a unique first-line sentinel to prevent duplicates
485
+ - `GIT_HOOK_FOOTER_APPEND_DEBUG`: Extra debug output in the footer template (true/false)
350
486
 
351
487
  For a quick starting point, this repository’s `.envrc` shows sane defaults, and `.env.local` can override them locally.
352
488
 
353
489
  ## 🔧 Basic Usage
354
490
 
355
491
  Common flows
492
+
356
493
  - Default quality workflow (locally):
357
- - `bundle exec rake` — runs the curated default task set (gradual RuboCop autocorrect, coverage if available, and other local tasks). On CI `CI=true`, the default task is adjusted to be CI-friendly.
494
+ - `bundle exec rake` — runs the curated default task set (gradual RuboCop autocorrect, coverage if available, and other local tasks). On CI `CI=true`, the default task is adjusted to be CI-friendly.
358
495
  - Run specs:
359
- - `bin/rspec` or `bundle exec rspec`
360
- - To run a subset without failing coverage thresholds: `K_SOUP_COV_MIN_HARD=false bin/rspec spec/path/to/file_spec.rb`
361
- - To produce multiple coverage reports: `K_SOUP_COV_FORMATTERS="html,xml,rcov,lcov,json,tty" bin/rspec`
496
+ - `bin/rspec` or `bundle exec rspec`
497
+ - To run a subset without failing coverage thresholds: `K_SOUP_COV_MIN_HARD=false bin/rspec spec/path/to/file_spec.rb`
498
+ - To produce multiple coverage reports: `K_SOUP_COV_FORMATTERS="html,xml,rcov,lcov,json,tty" bin/rspec`
362
499
  - Linting (Gradual):
363
- - `bundle exec rake rubocop_gradual:autocorrect`
364
- - `bundle exec rake rubocop_gradual:check` (CI-friendly)
500
+ - `bundle exec rake rubocop_gradual:autocorrect`
501
+ - `bundle exec rake rubocop_gradual:check` (CI-friendly)
365
502
  - Reek and docs:
366
- - `bundle exec rake reek` or `bundle exec rake reek:update`
367
- - `bundle exec rake yard`
368
-
369
- [Appraisals][💎appraisal2] helpers
503
+ - `bundle exec rake reek` or `bundle exec rake reek:update`
504
+ - `bundle exec rake yard`
505
+ [Appraisals][💎appraisal2] helpers
370
506
  - `bundle exec rake appraisal:isntall` — First time Appraisal setup.
371
507
  - `bundle exec rake appraisal:update` — Update Appraisal gemfiles and run RuboCop Gradual autocorrect.
372
- - `bundle exec rake appraisal:reset` — Delete all Appraisal lockfiles in gemfiles/ (*.gemfile.lock). Useful before regenerating appraisals or when switching Ruby versions.
373
-
374
- GitHub Actions local runner helper
508
+ - `bundle exec rake appraisal:reset` — Delete all Appraisal lockfiles in gemfiles/ (\*.gemfile.lock). Useful before regenerating appraisals or when switching Ruby versions.
509
+ GitHub Actions local runner helper
375
510
  - `bundle exec rake ci:act` — interactive menu shows workflows from `.github/workflows` with live status and short codes (first 3 letters of file name). Type a number or short code.
376
511
  - Non-interactive: `bundle exec rake ci:act[loc]` (short code), or `bundle exec rake ci:act[locked_deps.yml]` (filename).
377
-
378
- Setup tokens for API status (GitHub and GitLab)
512
+ Setup tokens for API status (GitHub and GitLab)
379
513
  - Purpose: ci:act displays the latest status for GitHub Actions runs and (when applicable) the latest GitLab pipeline for the current branch. Unauthenticated requests are rate-limited; private repositories require tokens. Provide tokens to get reliable status.
380
514
  - GitHub token (recommended: fine-grained):
381
- - Where to create: https://github.com/settings/personal-access-tokens
382
- - Fine-grained: “Tokens (fine-grained)” → Generate new token
383
- - Classic (fallback): “Tokens (classic)” → Generate new token
384
- - Minimum permissions:
385
- - Fine-grained: Repository access: Read-only for the target repository (or your org); Permissions → Actions: Read
386
- - Classic: For public repos, no scopes are strictly required, but rate limits are very low; for private repos, include the repo scope
387
- - Add to environment (.env.local via direnv):
388
- - GITHUB_TOKEN=your_token_here (or GH_TOKEN=…)
515
+ - Where to create: https://github.com/settings/personal-access-tokens
516
+ - Fine-grained: “Tokens (fine-grained)” → Generate new token
517
+ - Classic (fallback): “Tokens (classic)” → Generate new token
518
+ - Minimum permissions:
519
+ - Fine-grained: Repository access: Read-only for the target repository (or your org); Permissions → Actions: Read
520
+ - Classic: For public repos, no scopes are strictly required, but rate limits are very low; for private repos, include the repo scope
521
+ - Add to environment (`.env.local` via `direnv`):
522
+ - `GITHUB_TOKEN=your_token_here` (or `GH_TOKEN=…`)
389
523
  - GitLab token:
390
- - Where to create (gitlab.com): https://gitlab.com/-/user_settings/personal_access_tokens
391
- - Minimum scope: read_api (sufficient to read pipelines)
392
- - Add to environment (.env.local via direnv):
393
- - GITLAB_TOKEN=your_token_here (or GL_TOKEN=…)
524
+ - Where to create: [gitlab.com](https://gitlab.com/-/user_settings/personal_access_tokens)
525
+ - Minimum scope: `read_api` (sufficient to read pipelines)
526
+ - Add to environment (.env.local via direnv):
527
+ - `GITLAB_TOKEN=your_token_here` (or `GL_TOKEN=…`)
394
528
  - Load environment:
395
- - Save tokens in .env.local (never commit this file), then run: direnv allow
529
+ - Save tokens in `.env.local` (never commit this file), then run: `direnv allow`
396
530
  - Verify:
397
- - Run: bundle exec rake ci:act
398
- - The header will include Repo/Upstream/HEAD; entries will show “Latest GHA …” and “Latest GL … pipeline” with emoji status. On failure to authenticate or rate-limit, you’ll see a brief error/result code.
399
-
400
- Project automation bootstrap
531
+ - Run: bundle exec rake ci:act
532
+ - The header will include Repo/Upstream/HEAD; entries will show “Latest GHA …” and “Latest GL … pipeline” with emoji status. On failure to authenticate or rate-limit, you’ll see a brief error/result code.
533
+ Project automation bootstrap
401
534
  - `bundle exec rake kettle:dev:install` — copies the library’s `.github` folder into your project and offers to install `.git-hooks` templates locally or globally.
402
- - `bundle exec rake kettle:dev:template` — runs only the templating step used by install; useful to re-apply updates to templates (.github workflows, .devcontainer, .qlty, modular Gemfiles, README, and friends) without the `install` task’s extra prompts.
403
- - Also copies maintainer certificate `certs/pboling.pem` into your project when present (used for signed gem builds).
404
- - README carry-over during templating: when your project’s README.md is replaced by the template, selected sections from your existing README are preserved and merged into the new one. Specifically, the task carries over the following sections (matched case-insensitively):
405
- - "Synopsis"
406
- - "Configuration"
407
- - "Basic Usage"
408
- - Any section whose heading starts with "Note:" at any heading level (for example: "# NOTE: …", "## Note: …", or "### note: …").
409
- - Headings are recognized at any level using Markdown hashes (#, ##, ###, …).
535
+ - `bundle exec rake kettle:jem:template` — runs only the templating step used by install; useful to re-apply updates to templates (.github workflows, .devcontainer, .qlty, modular Gemfiles, README, and friends) without the `install` task’s extra prompts.
536
+ - Also copies maintainer certificate `certs/pboling.pem` into your project when present (used for signed gem builds).
537
+ - README carry-over during templating: when your project’s README.md is replaced by the template, selected sections from your existing README are preserved and merged into the new one. Specifically, the task carries over the following sections (matched case-insensitively):
538
+ - "Synopsis"
539
+ - "Configuration"
540
+ - "Basic Usage"
541
+ - Any section whose heading starts with "Note:" at any heading level (for example: "\# NOTE: …", "\#\# Note: …", or "\#\#\# note: …").
542
+ - Headings are recognized at any level using Markdown hashes (\#, \#\#, \#\#\#, …).
410
543
  - Notes about task options:
411
- - Non-interactive confirmations: append `force=true` to accept all y/N prompts as Yes, e.g., `bundle exec rake kettle:dev:template force=true`.
412
- - direnv review flow: if `.envrc` or `.env.local` is created or updated, the task stops and asks you to run `direnv allow`. After you review and allow, resume with `allowed=true`:
413
- - `bundle exec rake kettle:dev:template allowed=true`
414
- - `bundle exec rake kettle:dev:install allowed=true`
544
+ - Non-interactive confirmations: append `force=true` to accept all y/N prompts as Yes, e.g., `bundle exec rake kettle:jem:template force=true`.
545
+ - direnv review flow: if `.envrc` or `.env.local` is created or updated, the task stops and asks you to run `direnv allow`. After you review and allow, resume with `allowed=true`:
546
+ - `bundle exec rake kettle:jem:template allowed=true`
547
+ - `bundle exec rake kettle:dev:install allowed=true`
415
548
  - After that, set up binstubs and direnv for convenience:
416
- - `bundle binstubs kettle-dev --path bin`
417
- - Add to `.envrc`: `PATH_add bin` (so `bin/` tools run without the prefix)
549
+ - `bundle binstubs kettle-dev --path bin`
550
+ - Add to `.envrc`: `PATH_add bin` (so `bin/` tools run without the prefix)
418
551
 
419
552
  ### kettle-dvcs (normalize multi-forge remotes)
420
553
 
421
554
  - Script: `exe/kettle-dvcs` (install binstubs for convenience: `bundle binstubs kettle-dev --path bin`)
422
555
  - Purpose: Normalize git remotes across GitHub, GitLab, and Codeberg, and create an `all` remote that pushes to all and fetches only from your chosen origin.
423
556
  - Assumptions: org and repo names are identical across forges.
557
+ Usage:
424
558
 
425
- Usage:
559
+ <!-- end list -->
426
560
 
427
561
  ```console
428
562
  kettle-dvcs [options] [ORG] [REPO]
429
563
  ```
430
564
 
431
565
  Options:
566
+
432
567
  - `--origin [github|gitlab|codeberg]` Which forge to use as `origin` (default: github)
433
568
  - `--protocol [ssh|https]` URL style (default: ssh)
434
569
  - `--github-name NAME` Remote name for GitHub when not origin (default: gh)
435
570
  - `--gitlab-name NAME` Remote name for GitLab (default: gl)
436
571
  - `--codeberg-name NAME` Remote name for Codeberg (default: cb)
437
572
  - `--force` Non-interactive; accept defaults, and do not prompt for ORG/REPO
438
-
439
- Examples:
573
+ Examples:
440
574
  - Default, interactive (infers ORG/REPO from an existing remote when possible):
441
575
  ```console
442
576
  kettle-dvcs
@@ -451,171 +585,120 @@ Examples:
451
585
  ```
452
586
 
453
587
  What it does:
588
+
454
589
  - Ensures remotes exist and have consistent URLs for each forge.
455
- - Renames existing remotes when their URL already matches the desired target but their name does not (e.g., `gitlab` -> `gl`).
590
+ - Renames existing remotes when their URL already matches the desired target but their name does not (e.g., `gitlab` -\> `gl`).
456
591
  - Creates/refreshes an `all` remote that:
457
592
  - fetches only from your chosen `origin` forge.
458
593
  - has pushurls configured for all three forges so `git push all <branch>` updates all mirrors.
459
594
  - Prints `git remote -v` at the end.
460
595
  - Attempts to `git fetch` each forge remote to check availability:
461
- - If all succeed, the README’s federated DVCS summary line has “(Coming soon!)” removed.
596
+ - If all succeed, the README’s federated DVCS summary line has “(Coming soon\!)” removed.
462
597
  - If any fail, the script prints import links to help you create a mirror on that forge.
463
598
 
464
- ### Template .example files are preferred
465
-
466
- - The templating step dynamically prefers any `*.example` file present in this gem’s templates. When a `*.example` exists alongside the non-example template, the `.example` content is used, and the destination file is written without the `.example` suffix.
467
- - This applies across all templated files, including:
468
- - Root files like `.gitlab-ci.yml` (copied from `.gitlab-ci.yml.example` when present).
469
- - Nested files like `.github/workflows/coverage.yml` (copied from `.github/workflows/coverage.yml.example` when present).
470
- - This behavior is automatic for any future `*.example` files added to the templates.
471
- - Exception: `.env.local` is handled specially for safety. Regardless of whether the template provides `.env.local` or `.env.local.example`, the installer copies it to `.env.local.example` in your project, and will never create or overwrite `.env.local`.
472
-
473
599
  ### Releasing (maintainers)
474
600
 
475
601
  - Script: `exe/kettle-release` (run as `kettle-release`)
476
602
  - Purpose: guided release helper that:
477
- - Runs sanity checks (`bin/setup`, `bin/rake`), confirms version/changelog, optionally updates Appraisals, commits “🔖 Prepare release vX.Y.Z”.
478
- - Optionally runs your CI locally with `act` before any push:
479
- - Enable with env: `K_RELEASE_LOCAL_CI="true"` (run automatically) or `K_RELEASE_LOCAL_CI="ask"` (prompt [Y/n]).
480
- - Select workflow with `K_RELEASE_LOCAL_CI_WORKFLOW` (with or without .yml/.yaml). Defaults to `locked_deps.yml` if present; otherwise the first workflow discovered.
481
- - On failure, the release prep commit is soft-rolled-back (`git reset --soft HEAD^`) and the process aborts.
482
- - Ensures trunk sync and rebases feature as needed, pushes, monitors GitHub Actions with a progress bar, and merges feature to trunk on success.
483
- - Exports `SOURCE_DATE_EPOCH`, builds (optionally signed), creates gem checksums, and runs `bundle exec rake release` (prompts for signing key + RubyGems MFA OTP as needed).
603
+ - Runs sanity checks (`bin/setup`, `bin/rake`), confirms version/changelog, optionally updates Appraisals, commits “🔖 Prepare release vX.Y.Z”.
604
+ - Optionally runs your CI locally with `act` before any push:
605
+ - Enable with env: `K_RELEASE_LOCAL_CI="true"` (run automatically) or `K_RELEASE_LOCAL_CI="ask"` (prompt \[Y/n\]).
606
+ - Select workflow with `K_RELEASE_LOCAL_CI_WORKFLOW` (with or without .yml/.yaml). Defaults to `locked_deps.yml` if present; otherwise the first workflow discovered.
607
+ - On failure, the release prep commit is soft-rolled-back (`git reset --soft HEAD^`) and the process aborts.
608
+ - Ensures trunk sync and rebases feature as needed, pushes, monitors GitHub Actions with a progress bar, and merges feature to trunk on success.
609
+ - Exports `SOURCE_DATE_EPOCH`, builds (optionally signed), creates gem checksums, and runs `bundle exec rake release` (prompts for signing key + RubyGems MFA OTP as needed).
484
610
  - Options:
485
- - start_step map (skip directly to a phase):
486
- 1. Verify Bundler >= 2.7 (always runs; start at 1 to do everything)
487
- 2. Detect version; RubyGems sanity check; confirm CHANGELOG/version; sync copyright years; update badges/headers
488
- 3. Run bin/setup
489
- 4. Run bin/rake (default task)
490
- 5. Run bin/rake appraisal:update if Appraisals present
491
- 6. Ensure git user configured; commit release prep
492
- 7. Optional local CI with `act` (controlled by K_RELEASE_LOCAL_CI)
493
- 8. Ensure trunk in sync across remotes; rebase feature as needed
494
- 9. Push current branch to remotes (or 'all' remote)
495
- 10. Monitor CI after push; abort on failures
496
- 11. Merge feature into trunk and push
497
- 12. Checkout trunk and pull latest
498
- 13. Gem signing checks/guidance (skip with SKIP_GEM_SIGNING=true)
499
- 14. Build gem (bundle exec rake build)
500
- 15. Release gem (bundle exec rake release)
501
- 16. Generate and validate checksums (bin/gem_checksums)
502
- 17. Push checksum commit
503
- 18. Create GitHub Release (requires GITHUB_TOKEN)
504
- 19. Push tags to remotes (final)
611
+ - `start_step` map (skip directly to a phase):
612
+ 1. Verify Bundler \>= 2.7 (always runs; start at 1 to do everything)
613
+ 2. Detect version; RubyGems sanity check; confirm CHANGELOG/version; sync copyright years; update badges/headers
614
+ 3. Run bin/setup
615
+ 4. Run bin/rake (default task)
616
+ 5. Run bin/rake appraisal:update if Appraisals present
617
+ 6. Ensure git user configured; commit release prep
618
+ 7. Optional local CI with `act` (controlled by `K_RELEASE_LOCAL_CI`)
619
+ 8. Ensure trunk in sync across remotes; rebase feature as needed
620
+ 9. Push current branch to remotes (or 'all' remote)
621
+ 10. Monitor CI after push; abort on failures
622
+ 11. Merge feature into trunk and push
623
+ 12. Checkout trunk and pull latest
624
+ 13. Gem signing checks/guidance (skip with `SKIP_GEM_SIGNING=true`)
625
+ 14. Build gem (bundle exec rake build)
626
+ 15. Release gem (bundle exec rake release)
627
+ 16. Generate and validate checksums (`bin/gem_checksums`)
628
+ 17. Push checksum commit
629
+ 18. Create GitHub Release (requires `GITHUB_TOKEN`)
630
+ 19. Push tags to remotes (final)
505
631
  - Examples:
506
- - After intermittent CI failure, restart from monitoring: `bundle exec kettle-release start_step=10`
632
+ - After intermittent CI failure, restart from monitoring: `bundle exec kettle-release start_step=10`
507
633
  - Tips:
508
- - The commit message helper `exe/kettle-commit-msg` prefers project-local `.git-hooks` (then falls back to `~/.git-hooks`).
509
- - The goalie file `commit-subjects-goalie.txt` controls when a footer is appended; customize `footer-template.erb.txt` as you like.
634
+ - The commit message helper `exe/kettle-commit-msg` prefers project-local `.git-hooks` (then falls back to `~/.git-hooks`).
635
+ - The goalie file `commit-subjects-goalie.txt` controls when a footer is appended; customize `footer-template.erb.txt` as you like.
510
636
 
511
637
  ### Changelog generator
512
638
 
513
639
  - Script: `exe/kettle-changelog` (run as `kettle-changelog`)
514
640
  - Purpose: Generates a new CHANGELOG.md section for the current version read from `lib/**/version.rb`, moves notes from the Unreleased section, and updates comparison links.
515
641
  - Prerequisites:
516
- - `coverage/coverage.json` present (generate with: `K_SOUP_COV_FORMATTERS="json" bin/rspec`).
517
- - `bin/yard` available (Bundler-installed), to compute documentation coverage.
642
+ - `coverage/coverage.json` present (generate with: `K_SOUP_COV_FORMATTERS="json" bin/rspec`).
643
+ - `bin/yard` available (Bundler-installed), to compute documentation coverage.
518
644
  - Usage:
519
- - `kettle-changelog`
645
+ - `kettle-changelog`
520
646
  - Behavior:
521
- - Reads version from the unique `lib/**/version.rb` in the project.
522
- - Moves entries from the `[Unreleased]` section into a new `[#.#.#] - YYYY-MM-DD` section.
523
- - Prepends 4 lines with TAG, line coverage, branch coverage, and percent documented.
524
- - Converts any GitLab-style compare links at the bottom to GitHub style, adds new tag/compare links for the new release and a temporary tag reference `[X.Y.Zt]`.
647
+ - Reads version from the unique `lib/**/version.rb` in the project.
648
+ - Moves entries from the `[Unreleased]` section into a new `[#.#.#] - YYYY-MM-DD` section.
649
+ - Prepends 4 lines with TAG, line coverage, branch coverage, and percent documented.
650
+ - Converts any GitLab-style compare links at the bottom to GitHub style, adds new tag/compare links for the new release and a temporary tag reference `[X.Y.Zt]`.
525
651
 
526
652
  ### Pre-release checks
527
653
 
528
654
  - Script: `exe/kettle-pre-release` (run as `kettle-pre-release`)
529
655
  - Purpose: Run a suite of pre-release validations to catch avoidable mistakes (resumable by check number).
530
656
  - Usage:
531
- - `kettle-pre-release [--check-num N]`
532
- - Short option: `kettle-pre-release -cN`
657
+ - `kettle-pre-release [--check-num N]`
658
+ - Short option: `kettle-pre-release -cN`
533
659
  - Options:
534
- - `--check-num N` Start from check number N (default: 1)
660
+ - `--check-num N` Start from check number N (default: 1)
535
661
  - Checks:
536
- - 1) Validate that all image URLs referenced by Markdown files resolve (HTTP HEAD)
662
+ - 1) Validate that all image URLs referenced by Markdown files resolve (HTTP HEAD)
537
663
 
538
664
  ### Commit message helper (git hook)
539
665
 
540
666
  - Script: `exe/kettle-commit-msg` (run by git as `.git/hooks/commit-msg`)
541
667
  - Purpose: Append a standardized footer and optionally enforce branch naming rules when configured.
542
668
  - Usage:
543
- - Git invokes this with the path to the commit message file: `kettle-commit-msg .git/COMMIT_EDITMSG`
544
- - Install via `bundle exec rake kettle:dev:install` to copy hook templates into `.git-hooks` and wire them up.
669
+ - Git invokes this with the path to the commit message file: `kettle-commit-msg .git/COMMIT_EDITMSG`
670
+ - Install via `bundle exec rake kettle:dev:install` to copy hook templates into `.git-hooks` and wire them up.
545
671
  - Behavior:
546
- - When `GIT_HOOK_BRANCH_VALIDATE=jira`, validates the current branch matches the pattern: `^(hotfix|bug|feature|candy)/[0-9]{8,}-…`.
547
- - If it matches and the commit message lacks the numeric ID, appends `[<type>][<id>]`.
548
- - Always invokes `Kettle::Dev::GitCommitFooter.render` to potentially append a footer if allowed by the goalie.
549
- - Prefers project-local `.git-hooks` templates; falls back to `~/.git-hooks`.
672
+ - When `GIT_HOOK_BRANCH_VALIDATE=jira`, validates the current branch matches the pattern: `^(hotfix|bug|feature|candy)/[0-9]{8,}-…`.
673
+ - If it matches and the commit message lacks the numeric ID, appends `[<type>][<id>]`.
674
+ - Always invokes `Kettle::Dev::GitCommitFooter.render` to potentially append a footer if allowed by the goalie.
675
+ - Prefers project-local `.git-hooks` templates; falls back to `~/.git-hooks`.
550
676
  - Environment:
551
- - `GIT_HOOK_BRANCH_VALIDATE` Branch rule (e.g., `jira`) or `false` to disable.
552
- - `GIT_HOOK_FOOTER_APPEND` Enable footer auto-append when goalie allows (true/false).
553
- - `GIT_HOOK_FOOTER_SENTINEL` Required marker to avoid duplicate appends when enabled.
554
- - `GIT_HOOK_FOOTER_APPEND_DEBUG` Extra debug output in the footer template (true/false).
677
+ - `GIT_HOOK_BRANCH_VALIDATE` Branch rule (e.g., `jira`) or `false` to disable.
678
+ - `GIT_HOOK_FOOTER_APPEND` Enable footer auto-append when goalie allows (true/false).
679
+ - `GIT_HOOK_FOOTER_SENTINEL` Required marker to avoid duplicate appends when enabled.
680
+ - `GIT_HOOK_FOOTER_APPEND_DEBUG` Extra debug output in the footer template (true/false).
555
681
 
556
682
  ### Project bootstrap installer
557
683
 
558
684
  - Script: `exe/kettle-dev-setup` (run as `kettle-dev-setup`)
559
685
  - Purpose: Bootstrap a host gem repository to use kettle-dev’s tooling without manual steps.
560
686
  - Usage:
561
- - `kettle-dev-setup [options] [passthrough args]`
687
+ - `kettle-dev-setup [options] [passthrough args]`
562
688
  - Options (mapped through to `rake kettle:dev:install`):
563
- - `--allowed=VAL` Pass `allowed=VAL` to acknowledge prior direnv allow, etc.
564
- - `--force` Pass `force=true` to accept prompts non-interactively.
565
- - `--hook_templates=VAL` Pass `hook_templates=VAL` to control git hook templating.
566
- - `--only=VAL` Pass `only=VAL` to restrict install scope.
567
- - `--include=VAL` Pass `include=VAL` to include optional files by glob (see notes below).
568
- - `-h`, `--help` Show help.
689
+ - `--allowed=VAL` Pass `allowed=VAL` to acknowledge prior direnv allow, etc.
690
+ - `--force` Pass `force=true` to accept prompts non-interactively.
691
+ - `--hook_templates=VAL` Pass `hook_templates=VAL` to control git hook templating.
692
+ - `--only=VAL` Pass `only=VAL` to restrict install scope.
693
+ - `--include=VAL` Pass `include=VAL` to include optional files by glob (see notes below).
694
+ - `-h`, `--help` Show help.
569
695
  - Behavior:
570
- - Verifies a clean git working tree, presence of a Gemfile and a gemspec.
571
- - Syncs development dependencies from this gem’s example gemspec into the target gemspec (replacing or inserting `add_development_dependency` lines as needed).
572
- - Ensures `bin/setup` exists (copies from gem if missing) and replaces/creates the project’s `Rakefile` from `Rakefile.example`.
573
- - Runs `bin/setup`, then `bundle exec bundle binstubs --all`.
574
- - Stages and commits any bootstrap changes with message: `🎨 Template bootstrap by kettle-dev-setup v<version>`.
575
- - Executes `bin/rake kettle:dev:install` with the parsed passthrough args.
576
-
577
- ### Template Manifest and AST Strategies
578
-
579
- `kettle:dev:template` looks at `template_manifest.yml` to determine how each file should be updated. Each entry has a `path` (exact file or glob) and a `strategy`:
580
-
581
- | Strategy | Behavior |
582
- | --- | --- |
583
- | `skip` | Legacy behavior: template content is copied with token replacements and any bespoke merge logic already in place. |
584
- | `replace` | Template AST replaces the destination outside of `kettle-dev:freeze` sections. |
585
- | `append` | Only missing AST nodes (e.g., `gem` or `task` declarations) are appended; existing nodes remain untouched. |
586
- | `merge` | Destination nodes are updated in-place using the template AST (used for `Gemfile`, `*.gemspec`, and `Rakefile`). |
587
-
588
- All Ruby files receive this reminder (inserted after shebang/frozen-string-literal lines):
589
-
590
- ```
591
- # To force retention during kettle-dev templating:
592
- # kettle-dev:freeze
593
- # # ... your code
594
- # kettle-dev:unfreeze
595
- ```
596
-
597
- Wrap any code you never want rewritten between `kettle-dev:freeze` / `kettle-dev:unfreeze` comments. When an AST merge fails, the task emits an error asking you to file an issue at https://github.com/kettle-rb/kettle-dev/issues and then aborts—there is no regex fallback.
598
-
599
- ### Template Example
600
-
601
- Here is an example `template_manifest.yml`:
602
-
603
- ```yaml
604
- # For each file or glob, specify a strategy for how it should be managed.
605
- # See https://github.com/kettle-rb/kettle-dev/blob/main/docs/README.md#template-manifest-and-ast-strategies
606
- # for details on each strategy.
607
- files:
608
- - path: "Gemfile"
609
- strategy: "merge"
610
- - path: "*.gemspec"
611
- strategy: "merge"
612
- - path: "Rakefile"
613
- strategy: "merge"
614
- - path: "README.md"
615
- strategy: "replace"
616
- - path: ".env.local"
617
- strategy: "skip"
618
- ```
696
+ - Verifies a clean git working tree, presence of a Gemfile and a gemspec.
697
+ - Syncs development dependencies from this gem’s example gemspec into the target gemspec (replacing or inserting `add_development_dependency` lines as needed).
698
+ - Ensures `bin/setup` exists (copies from gem if missing) and replaces/creates the project’s `Rakefile` from `Rakefile.example`.
699
+ - Runs `bin/setup`, then `bundle exec bundle binstubs --all`.
700
+ - Stages and commits any bootstrap changes with message: `🎨 Template bootstrap by kettle-dev-setup v<version>`.
701
+ - Executes `bin/rake kettle:dev:install` with the parsed passthrough args.
619
702
 
620
703
  ### Open Collective README updater
621
704
 
@@ -630,15 +713,15 @@ files:
630
713
  - Backers (Individuals): `<!-- <TAG>:START --> … <!-- <TAG>:END -->` or `<!-- <TAG>-INDIVIDUALS:START --> … <!-- <TAG>-INDIVIDUALS:END -->`
631
714
  - Sponsors (Organizations): `<!-- <TAG>-ORGANIZATIONS:START --> … <!-- <TAG>-ORGANIZATIONS:END -->`
632
715
  - Handle resolution:
633
- 1. `OPENCOLLECTIVE_HANDLE` environment variable, if set
634
- 2. `opencollective.yml` in the project root (e.g., `collective: "kettle-rb"` in this repo)
716
+ 1. `OPENCOLLECTIVE_HANDLE` environment variable, if set
717
+ 2. `opencollective.yml` in the project root (e.g., `collective: "kettle-rb"` in this repo)
635
718
  - Usage:
636
719
  - `exe/kettle-readme-backers`
637
720
  - `OPENCOLLECTIVE_HANDLE=my-collective exe/kettle-readme-backers`
638
721
  - Behavior:
639
722
  - Writes to README.md only if content between the tags would change.
640
723
  - If neither the backers nor sponsors tags are present, prints a helpful warning and exits with status 2.
641
- - When there are no entries, inserts a friendly placeholder: "No backers yet. Be the first!" or "No sponsors yet. Be the first!".
724
+ - When there are no entries, inserts a friendly placeholder: "No backers yet. Be the first\!" or "No sponsors yet. Be the first\!".
642
725
  - When updates are written and the repository is a git work tree, the script stages README.md and commits with a message thanking new backers and subscribers, including mentions for any newly added backers and subscribers (GitHub @handles when their website/profile is a github.com URL; otherwise their name).
643
726
  - Customize the commit subject via env var: `KETTLE_README_BACKERS_COMMIT_SUBJECT="💸 Thanks 🙏 to our new backers 🎒 and subscribers 📜"`.
644
727
  - Or via .opencollective.yml: set `readme-backers-commit-subject: "💸 Thanks 🙏 to our new backers 🎒 and subscribers 📜"`.
@@ -646,7 +729,7 @@ files:
646
729
  - Note: When used with the provided `.git-hooks`, the subject should start with a gitmoji character (see [gitmoji][📌gitmoji]).
647
730
  - Tip:
648
731
  - Run this locally before committing to keep your README current, or schedule it in CI to refresh periodically.
649
- - It runs automatically on a once-a-week schedule by the .github/workflows/opencollective.yml workflow that is part of the kettle-dev template.
732
+ - It runs automatically on a once-a-week schedule by the .github/workflows/opencollective.yml workflow that is part of the kettle-jem template.
650
733
  - Authentication requirement:
651
734
  - When running in CI with the provided workflow, you must provide an organization-level Actions secret named `README_UPDATER_TOKEN`.
652
735
  - Create it under your GitHub organization settings: `https://github.com/organizations/<YOUR_ORG>/settings/secrets/actions`.
@@ -658,7 +741,7 @@ files:
658
741
  While kettle-rb tools are free software and will always be, the project would benefit immensely from some funding.
659
742
  Raising a monthly budget of... "dollars" would make the project more sustainable.
660
743
 
661
- We welcome both individual and corporate sponsors! We also offer a
744
+ We welcome both individual and corporate sponsors\! We also offer a
662
745
  wide array of funding channels to account for your preferences
663
746
  (although currently [Open Collective][🖇osc] is our preferred funding platform).
664
747
 
@@ -672,37 +755,39 @@ You can support the development of kettle-rb tools via
672
755
  [Open Collective][🖇osc]
673
756
  and [Tidelift][🏙️entsup-tidelift].
674
757
 
675
- | 📍 NOTE |
676
- |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
758
+ | 📍 NOTE |
759
+ | --- |
677
760
  | If doing a sponsorship in the form of donation is problematic for your company <br/> from an accounting standpoint, we'd recommend the use of Tidelift, <br/> where you can get a support-like subscription instead. |
678
761
 
679
762
  ### Open Collective for Individuals
680
763
 
681
- Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/kettle-rb#backer)]
764
+ Support us with a monthly donation and help us continue our activities. \[[Become a backer][🖇osc-backers]\]
682
765
 
683
766
  NOTE: [kettle-readme-backers][kettle-readme-backers] updates this list every day, automatically.
684
767
 
685
768
  <!-- OPENCOLLECTIVE-INDIVIDUALS:START -->
686
- No backers yet. Be the first!
769
+ No backers yet. Be the first\!
687
770
  <!-- OPENCOLLECTIVE-INDIVIDUALS:END -->
688
771
 
689
772
  ### Open Collective for Organizations
690
773
 
691
- Become a sponsor and get your logo on our README on GitHub with a link to your site. [[Become a sponsor](https://opencollective.com/kettle-rb#sponsor)]
774
+ Become a sponsor and get your logo on our README on GitHub with a link to your site. \[[Become a sponsor][🖇osc-sponsors]\]
692
775
 
693
776
  NOTE: [kettle-readme-backers][kettle-readme-backers] updates this list every day, automatically.
694
777
 
695
778
  <!-- OPENCOLLECTIVE-ORGANIZATIONS:START -->
696
- No sponsors yet. Be the first!
779
+ No sponsors yet. Be the first\!
697
780
  <!-- OPENCOLLECTIVE-ORGANIZATIONS:END -->
698
781
 
782
+ [kettle-readme-backers]: https://github.com/kettle-rb/kettle-dev/blob/main/exe/kettle-readme-backers
783
+
699
784
  ### Another way to support open-source
700
785
 
701
786
  I’m driven by a passion to foster a thriving open-source community – a space where people can tackle complex problems, no matter how small. Revitalizing libraries that have fallen into disrepair, and building new libraries focused on solving real-world challenges, are my passions. I was recently affected by layoffs, and the tech jobs market is unwelcoming. I’m reaching out here because your support would significantly aid my efforts to provide for my family, and my farm (11 🐔 chickens, 2 🐶 dogs, 3 🐰 rabbits, 8 🐈‍ cats).
702
787
 
703
788
  If you work at a company that uses my work, please encourage them to support me as a corporate sponsor. My work on gems you use might show up in `bundle fund`.
704
789
 
705
- I’m developing a new library, [floss_funding][🖇floss-funding-gem], designed to empower open-source developers like myself to get paid for the work we do, in a sustainable way. Please give it a look.
790
+ I’m developing a new library, [floss\_funding][🖇floss-funding-gem], designed to empower open-source developers like myself to get paid for the work we do, in a sustainable way. Please give it a look.
706
791
 
707
792
  **[Floss-Funding.dev][🖇floss-funding.dev]: 👉️ No network calls. 👉️ No tracking. 👉️ No oversight. 👉️ Minimal crypto hashing. 💡 Easily disabled nags**
708
793
 
@@ -722,12 +807,6 @@ We [![Keep A Changelog][📗keep-changelog-img]][📗keep-changelog] so if you m
722
807
 
723
808
  See [CONTRIBUTING.md][🤝contributing] for more detailed instructions.
724
809
 
725
- ### Roadmap
726
-
727
- - [ ] Template the RSpec test harness.
728
- - [ ] Enhance gitlab pipeline configuration.
729
- - [ ] Add focused, packaged, named, templating strategies, allowing, for example, only refreshing the Appraisals related template files.
730
-
731
810
  ### 🚀 Release Instructions
732
811
 
733
812
  See [CONTRIBUTING.md][🤝contributing].
@@ -751,7 +830,7 @@ chat rooms and mailing lists agrees to follow the [![Contributor Covenant 2.1][
751
830
 
752
831
  Made with [contributors-img][🖐contrib-rocks].
753
832
 
754
- Also see GitLab Contributors: [https://gitlab.com/kettle-rb/kettle-dev/-/graphs/main][🚎contributors-gl]
833
+ Also see GitLab Contributors: <https://gitlab.com/kettle-rb/kettle-dev/-/graphs/main>
755
834
 
756
835
  <details>
757
836
  <summary>⭐️ Star History</summary>
@@ -775,9 +854,9 @@ a new version should be immediately released that restores compatibility.
775
854
  Breaking changes to the public API will only be introduced with new major versions.
776
855
 
777
856
  > dropping support for a platform is both obviously and objectively a breaking change <br/>
778
- >—Jordan Harband ([@ljharb](https://github.com/ljharb), maintainer of SemVer) [in SemVer issue 716][📌semver-breaking]
857
+ > —Jordan Harband ([@ljharb](https://github.com/ljharb), maintainer of SemVer) [in SemVer issue 716][📌semver-breaking]
779
858
 
780
- I understand that policy doesn't work universally ("exceptions to every rule!"),
859
+ I understand that policy doesn't work universally ("exceptions to every rule\!"),
781
860
  but it is the policy here.
782
861
  As such, in many cases it is good to specify a dependency on this library using
783
862
  the [Pessimistic Version Constraint][📌pvc] with two digits of precision.
@@ -834,9 +913,9 @@ Please consider sponsoring me or the project.
834
913
 
835
914
  To join the community or get help 👇️ Join the Discord.
836
915
 
837
- [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite]
916
+ [![Live Chat on Discord][✉️discord-invite-img-ftb]][🖼️galtzo-discord]
838
917
 
839
- To say "thanks!" ☝️ Join the Discord or 👇️ send money.
918
+ To say "thanks\!" ☝️ Join the Discord or 👇️ send money.
840
919
 
841
920
  [![Sponsor kettle-rb/kettle-dev on Open Source Collective][🖇osc-all-bottom-img]][🖇osc] 💌 [![Sponsor me on GitHub Sponsors][🖇sponsor-bottom-img]][🖇sponsor] 💌 [![Sponsor me on Liberapay][⛳liberapay-bottom-img]][⛳liberapay] 💌 [![Donate on PayPal][🖇paypal-bottom-img]][🖇paypal]
842
921
 
@@ -879,7 +958,6 @@ Thanks for RTFM. ☺️
879
958
  [✉️discord-invite-img-ftb]: https://img.shields.io/discord/1373797679469170758?style=for-the-badge&logo=discord
880
959
  [✉️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
881
960
  [✉️ruby-friends]: https://app.daily.dev/squads/rubyfriends
882
-
883
961
  [✇bundle-group-pattern]: https://gist.github.com/pboling/4564780
884
962
  [⛳️gem-namespace]: https://github.com/kettle-rb/kettle-dev
885
963
  [⛳️namespace-img]: https://img.shields.io/badge/namespace-Kettle::Dev-3C2D2D.svg?style=square&logo=ruby&logoColor=white
@@ -985,19 +1063,12 @@ Thanks for RTFM. ☺️
985
1063
  [💎ruby-2.7i]: https://img.shields.io/badge/Ruby-2.7-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
986
1064
  [💎ruby-3.0i]: https://img.shields.io/badge/Ruby-3.0-CC342D?style=for-the-badge&logo=ruby&logoColor=white
987
1065
  [💎ruby-3.1i]: https://img.shields.io/badge/Ruby-3.1-CC342D?style=for-the-badge&logo=ruby&logoColor=white
988
- [💎ruby-3.2i]: https://img.shields.io/badge/Ruby-3.2-CC342D?style=for-the-badge&logo=ruby&logoColor=white
989
1066
  [💎ruby-3.3i]: https://img.shields.io/badge/Ruby-3.3-CC342D?style=for-the-badge&logo=ruby&logoColor=white
990
1067
  [💎ruby-c-i]: https://img.shields.io/badge/Ruby-current-CC342D?style=for-the-badge&logo=ruby&logoColor=green
991
1068
  [💎ruby-headi]: https://img.shields.io/badge/Ruby-HEAD-CC342D?style=for-the-badge&logo=ruby&logoColor=blue
992
- [💎truby-22.3i]: https://img.shields.io/badge/Truffle_Ruby-22.3_(%F0%9F%9A%ABCI)-AABBCC?style=for-the-badge&logo=ruby&logoColor=pink
993
- [💎truby-23.0i]: https://img.shields.io/badge/Truffle_Ruby-23.0_(%F0%9F%9A%ABCI)-AABBCC?style=for-the-badge&logo=ruby&logoColor=pink
994
1069
  [💎truby-23.1i]: https://img.shields.io/badge/Truffle_Ruby-23.1-34BCB1?style=for-the-badge&logo=ruby&logoColor=pink
995
1070
  [💎truby-c-i]: https://img.shields.io/badge/Truffle_Ruby-current-34BCB1?style=for-the-badge&logo=ruby&logoColor=green
996
1071
  [💎truby-headi]: https://img.shields.io/badge/Truffle_Ruby-HEAD-34BCB1?style=for-the-badge&logo=ruby&logoColor=blue
997
- [💎jruby-9.1i]: https://img.shields.io/badge/JRuby-9.1_(%F0%9F%9A%ABCI)-AABBCC?style=for-the-badge&logo=ruby&logoColor=red
998
- [💎jruby-9.2i]: https://img.shields.io/badge/JRuby-9.2_(%F0%9F%9A%ABCI)-AABBCC?style=for-the-badge&logo=ruby&logoColor=red
999
- [💎jruby-9.3i]: https://img.shields.io/badge/JRuby-9.3_(%F0%9F%9A%ABCI)-AABBCC?style=for-the-badge&logo=ruby&logoColor=red
1000
- [💎jruby-9.4i]: https://img.shields.io/badge/JRuby-9.4-FBE742?style=for-the-badge&logo=ruby&logoColor=red
1001
1072
  [💎jruby-c-i]: https://img.shields.io/badge/JRuby-current-FBE742?style=for-the-badge&logo=ruby&logoColor=green
1002
1073
  [💎jruby-headi]: https://img.shields.io/badge/JRuby-HEAD-FBE742?style=for-the-badge&logo=ruby&logoColor=blue
1003
1074
  [🤝gh-issues]: https://github.com/kettle-rb/kettle-dev/issues
@@ -1026,7 +1097,7 @@ Thanks for RTFM. ☺️
1026
1097
  [📌gitmoji]: https://gitmoji.dev
1027
1098
  [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
1028
1099
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
1029
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-5.010-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1100
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-2.793-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1030
1101
  [🔐security]: SECURITY.md
1031
1102
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
1032
1103
  [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
@@ -1036,7 +1107,7 @@ Thanks for RTFM. ☺️
1036
1107
  [📄license-compat]: https://dev.to/galtzo/how-to-check-license-compatibility-41h0
1037
1108
  [📄license-compat-img]: https://img.shields.io/badge/Apache_Compatible:_Category_A-%E2%9C%93-259D6C.svg?style=flat&logo=Apache
1038
1109
  [📄ilo-declaration]: https://www.ilo.org/declaration/lang--en/index.htm
1039
- [📄ilo-declaration-img]: https://img.shields.io/badge/ILO_Fundamental_Principles-✓-259D6C.svg?style=flat
1110
+ [📄ilo-declaration-img]: https://img.shields.io/badge/ILO_Fundamental_Principles-%E2%9C%93-259D6C.svg?style=flat
1040
1111
  [🚎yard-current]: http://rubydoc.info/gems/kettle-dev
1041
1112
  [🚎yard-head]: https://kettle-dev.galtzo.com
1042
1113
  [💎stone_checksums]: https://github.com/galtzo-floss/stone_checksums