kettle-dev 1.1.45 → 1.1.48
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.envrc +2 -2
- data/.git-hooks/footer-template.erb.txt +1 -1
- data/.github/workflows/coverage.yml +3 -4
- data/.github/workflows/style.yml +2 -0
- data/Appraisals +2 -0
- data/CHANGELOG.md +50 -1
- data/FUNDING.md +2 -2
- data/FUNDING.md.no-osc.example +1 -1
- data/README.md +5 -5
- data/README.md.example +5 -5
- data/README.md.no-osc.example +4 -4
- data/Rakefile.example +1 -1
- data/lib/kettle/dev/template_helpers.rb +307 -0
- data/lib/kettle/dev/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +4 -4
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 81727729ce153f3e6b055ffc4ec51edb98ac88948e721672ba594d7922073603
|
|
4
|
+
data.tar.gz: 18deca20469a370c4532b82d2f19536807218e31cf52838a96872c5896bc2c23
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b1f3dfe80ca9936aee99f3d300c9eaef1a3e9c3c2eb871af63574b130d6a5b2de5c33d083745e50f352e6cfc532c8495c57ae0201cd92c9ed68a74de215befb2
|
|
7
|
+
data.tar.gz: b0396f0e7e0f975ef32256c276bd0fbe7e9026eba2c8685a33c942b480561277c0a9330868b5472a4e2c82d6b37de05d03c5f2eae604c3e933ba8bd6b0728d52
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/.envrc
CHANGED
|
@@ -21,8 +21,8 @@ export K_SOUP_COV_DO=true # Means you want code coverage
|
|
|
21
21
|
export K_SOUP_COV_COMMAND_NAME="Test Coverage"
|
|
22
22
|
# Available formats are html, xml, rcov, lcov, json, tty
|
|
23
23
|
export K_SOUP_COV_FORMATTERS="html,xml,rcov,lcov,json,tty"
|
|
24
|
-
export K_SOUP_COV_MIN_BRANCH=
|
|
25
|
-
export K_SOUP_COV_MIN_LINE=
|
|
24
|
+
export K_SOUP_COV_MIN_BRANCH=77 # Means you want to enforce X% branch coverage
|
|
25
|
+
export K_SOUP_COV_MIN_LINE=92 # Means you want to enforce X% line coverage
|
|
26
26
|
export K_SOUP_COV_MIN_HARD=true # Means you want the build to fail if the coverage thresholds are not met
|
|
27
27
|
export K_SOUP_COV_MULTI_FORMATTERS=true
|
|
28
28
|
export K_SOUP_COV_OPEN_BIN= # Means don't try to open coverage results in browser
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
⚡️ A message from a fellow meat-based-AI ⚡️
|
|
2
|
-
- [❤️] Finely-crafted open-source tools like <%= @gem_name %> (& many more)
|
|
2
|
+
- [❤️] Finely-crafted open-source tools like <%= @gem_name %> (& many more) require time and effort.
|
|
3
3
|
- [❤️] Though I adore my work, it lacks financial sustainability.
|
|
4
4
|
- [❤️] Please, help me continue enhancing your tools by becoming a sponsor:
|
|
5
5
|
- [💲] https://liberapay.com/pboling/donate
|
|
@@ -6,9 +6,8 @@ permissions:
|
|
|
6
6
|
id-token: write
|
|
7
7
|
|
|
8
8
|
env:
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
K_SOUP_COV_MIN_LINE: 93
|
|
9
|
+
K_SOUP_COV_MIN_BRANCH: 77
|
|
10
|
+
K_SOUP_COV_MIN_LINE: 92
|
|
12
11
|
K_SOUP_COV_MIN_HARD: true
|
|
13
12
|
K_SOUP_COV_FORMATTERS: "xml,rcov,lcov,tty"
|
|
14
13
|
K_SOUP_COV_DO: true
|
|
@@ -116,7 +115,7 @@ jobs:
|
|
|
116
115
|
hide_complexity: true
|
|
117
116
|
indicators: true
|
|
118
117
|
output: both
|
|
119
|
-
thresholds: '
|
|
118
|
+
thresholds: '92 77'
|
|
120
119
|
continue-on-error: ${{ matrix.experimental != 'false' }}
|
|
121
120
|
|
|
122
121
|
- name: Add Coverage PR Comment
|
data/.github/workflows/style.yml
CHANGED
|
@@ -63,3 +63,5 @@ jobs:
|
|
|
63
63
|
run: bundle exec appraisal ${{ matrix.appraisal }} bundle
|
|
64
64
|
- name: Run ${{ matrix.appraisal }} checks via ${{ matrix.exec_cmd }}
|
|
65
65
|
run: bundle exec appraisal ${{ matrix.appraisal }} bundle exec ${{ matrix.exec_cmd }}
|
|
66
|
+
- name: Validate RBS Types
|
|
67
|
+
run: bundle exec appraisal ${{ matrix.appraisal }} bin/rbs validate
|
data/Appraisals
CHANGED
|
@@ -136,6 +136,8 @@ appraise "coverage" do
|
|
|
136
136
|
eval_gemfile "modular/optional.gemfile"
|
|
137
137
|
eval_gemfile "modular/recording/r3/recording.gemfile"
|
|
138
138
|
eval_gemfile "modular/x_std_libs.gemfile"
|
|
139
|
+
# Normally style is included in coverage runs only, but we need it for the test suite to get full coverage
|
|
140
|
+
eval_gemfile "modular/style.gemfile"
|
|
139
141
|
# Dependencies injected by the kettle-dev-setup script & kettle:dev:install rake task
|
|
140
142
|
# eval_gemfile "modular/injected.gemfile"
|
|
141
143
|
end
|
data/CHANGELOG.md
CHANGED
|
@@ -30,6 +30,49 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
30
30
|
|
|
31
31
|
### Security
|
|
32
32
|
|
|
33
|
+
## [1.1.48] - 2025-11-06
|
|
34
|
+
|
|
35
|
+
- TAG: [v1.1.48][1.1.48t]
|
|
36
|
+
- COVERAGE: 94.39% -- 4038/4278 lines in 26 files
|
|
37
|
+
- BRANCH COVERAGE: 78.93% -- 1663/2107 branches in 26 files
|
|
38
|
+
- 79.89% documented
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- Typo in markdown link
|
|
43
|
+
- Handling of pre-existing gemfile
|
|
44
|
+
|
|
45
|
+
## [1.1.47] - 2025-11-06
|
|
46
|
+
|
|
47
|
+
- TAG: [v1.1.47][1.1.47t]
|
|
48
|
+
- COVERAGE: 95.68% -- 4054/4237 lines in 26 files
|
|
49
|
+
- BRANCH COVERAGE: 80.45% -- 1675/2082 branches in 26 files
|
|
50
|
+
- 79.89% documented
|
|
51
|
+
|
|
52
|
+
### Added
|
|
53
|
+
|
|
54
|
+
- Handle custom dependencies in Gemfiles gracefully
|
|
55
|
+
- Intelligent templating of Appraisals
|
|
56
|
+
|
|
57
|
+
### Fixed
|
|
58
|
+
|
|
59
|
+
- Typos in funding links
|
|
60
|
+
|
|
61
|
+
## [1.1.46] - 2025-11-04
|
|
62
|
+
|
|
63
|
+
- TAG: [v1.1.46][1.1.46t]
|
|
64
|
+
- COVERAGE: 96.25% -- 3958/4112 lines in 26 files
|
|
65
|
+
- BRANCH COVERAGE: 80.95% -- 1636/2021 branches in 26 files
|
|
66
|
+
- 79.68% documented
|
|
67
|
+
|
|
68
|
+
### Added
|
|
69
|
+
|
|
70
|
+
- Validate RBS Types within style workflow
|
|
71
|
+
|
|
72
|
+
### Fixed
|
|
73
|
+
|
|
74
|
+
- typos in README.md
|
|
75
|
+
|
|
33
76
|
## [1.1.45] - 2025-10-31
|
|
34
77
|
|
|
35
78
|
- TAG: [v1.1.45][1.1.45t]
|
|
@@ -1252,7 +1295,13 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
1252
1295
|
- Selecting will run the selected workflow via `act`
|
|
1253
1296
|
- This may move to its own gem in the future.
|
|
1254
1297
|
|
|
1255
|
-
[Unreleased]: https://github.com/kettle-rb/kettle-dev/compare/v1.1.
|
|
1298
|
+
[Unreleased]: https://github.com/kettle-rb/kettle-dev/compare/v1.1.48...HEAD
|
|
1299
|
+
[1.1.48]: https://github.com/kettle-rb/kettle-dev/compare/v1.1.47...v1.1.48
|
|
1300
|
+
[1.1.48t]: https://github.com/kettle-rb/kettle-dev/releases/tag/v1.1.48
|
|
1301
|
+
[1.1.47]: https://github.com/kettle-rb/kettle-dev/compare/v1.1.46...v1.1.47
|
|
1302
|
+
[1.1.47t]: https://github.com/kettle-rb/kettle-dev/releases/tag/v1.1.47
|
|
1303
|
+
[1.1.46]: https://github.com/kettle-rb/kettle-dev/compare/v1.1.45...v1.1.46
|
|
1304
|
+
[1.1.46t]: https://github.com/kettle-rb/kettle-dev/releases/tag/v1.1.46
|
|
1256
1305
|
[1.1.45]: https://github.com/kettle-rb/kettle-dev/compare/v1.1.44...v1.1.45
|
|
1257
1306
|
[1.1.45t]: https://github.com/kettle-rb/kettle-dev/releases/tag/v1.1.45
|
|
1258
1307
|
[1.1.44]: https://github.com/kettle-rb/kettle-dev/compare/v1.1.43...v1.1.44
|
data/FUNDING.md
CHANGED
|
@@ -6,7 +6,7 @@ Many paths lead to being a sponsor or a backer of this project. Are you on such
|
|
|
6
6
|
|
|
7
7
|
[![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]
|
|
8
8
|
|
|
9
|
-
[![Buy me a coffee][🖇buyme-small-img]][🖇buyme] [![Donate on Polar][🖇polar-img]][🖇polar] [![Donate to my FLOSS
|
|
9
|
+
[![Buy me a coffee][🖇buyme-small-img]][🖇buyme] [![Donate on Polar][🖇polar-img]][🖇polar] [![Donate to my FLOSS efforts at ko-fi.com][🖇kofi-img]][🖇kofi] [![Donate to my FLOSS efforts using Patreon][🖇patreon-img]][🖇patreon]
|
|
10
10
|
|
|
11
11
|
[⛳liberapay-img]: https://img.shields.io/liberapay/goal/pboling.svg?logo=liberapay&color=a51611&style=flat
|
|
12
12
|
[⛳liberapay]: https://liberapay.com/pboling/donate
|
|
@@ -46,7 +46,7 @@ To join the community or get help 👇️ Join the Discord.
|
|
|
46
46
|
|
|
47
47
|
To say "thanks for maintaining such a great tool" ☝️ Join the Discord or 👇️ send money.
|
|
48
48
|
|
|
49
|
-
[![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
|
|
49
|
+
[![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]
|
|
50
50
|
|
|
51
51
|
# Another Way to Support Open Source Software
|
|
52
52
|
|
data/FUNDING.md.no-osc.example
CHANGED
|
@@ -6,7 +6,7 @@ Many paths lead to being a sponsor or a backer of this project. Are you on such
|
|
|
6
6
|
|
|
7
7
|
[![Sponsor Me on Github][🖇sponsor-img]][🖇sponsor] [![Liberapay Goal Progress][⛳liberapay-img]][⛳liberapay] [![Donate on PayPal][🖇paypal-img]][🖇paypal]
|
|
8
8
|
|
|
9
|
-
[![Buy me a coffee][🖇buyme-small-img]][🖇buyme] [![Donate on Polar][🖇polar-img]][🖇polar] [![Donate to my FLOSS
|
|
9
|
+
[![Buy me a coffee][🖇buyme-small-img]][🖇buyme] [![Donate on Polar][🖇polar-img]][🖇polar] [![Donate to my FLOSS efforts at ko-fi.com][🖇kofi-img]][🖇kofi] [![Donate to my FLOSS efforts using Patreon][🖇patreon-img]][🖇patreon]
|
|
10
10
|
|
|
11
11
|
[⛳liberapay-img]: https://img.shields.io/liberapay/goal/pboling.svg?logo=liberapay&color=a51611&style=flat
|
|
12
12
|
[⛳liberapay]: https://liberapay.com/pboling/donate
|
data/README.md
CHANGED
|
@@ -652,7 +652,7 @@ I’m developing a new library, [floss_funding][🖇floss-funding-gem], designed
|
|
|
652
652
|
|
|
653
653
|
**[Floss-Funding.dev][🖇floss-funding.dev]: 👉️ No network calls. 👉️ No tracking. 👉️ No oversight. 👉️ Minimal crypto hashing. 💡 Easily disabled nags**
|
|
654
654
|
|
|
655
|
-
[![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 to my FLOSS
|
|
655
|
+
[![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 to my FLOSS efforts at ko-fi.com][🖇kofi-img]][🖇kofi] [![Donate to my FLOSS efforts using Patreon][🖇patreon-img]][🖇patreon]
|
|
656
656
|
|
|
657
657
|
## 🔐 Security
|
|
658
658
|
|
|
@@ -779,7 +779,7 @@ To join the community or get help 👇️ Join the Discord.
|
|
|
779
779
|
|
|
780
780
|
To say "thanks!" ☝️ Join the Discord or 👇️ send money.
|
|
781
781
|
|
|
782
|
-
[![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
|
|
782
|
+
[![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]
|
|
783
783
|
|
|
784
784
|
### Please give the project a star ⭐ ♥.
|
|
785
785
|
|
|
@@ -964,10 +964,10 @@ Thanks for RTFM. ☺️
|
|
|
964
964
|
[📌changelog]: CHANGELOG.md
|
|
965
965
|
[📗keep-changelog]: https://keepachangelog.com/en/1.0.0/
|
|
966
966
|
[📗keep-changelog-img]: https://img.shields.io/badge/keep--a--changelog-1.0.0-34495e.svg?style=flat
|
|
967
|
-
[📌gitmoji]:https://gitmoji.dev
|
|
968
|
-
[📌gitmoji-img]:https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
967
|
+
[📌gitmoji]: https://gitmoji.dev
|
|
968
|
+
[📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
969
969
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
970
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-4.
|
|
970
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-4.278-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
|
971
971
|
[🔐security]: SECURITY.md
|
|
972
972
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
|
973
973
|
[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
|
data/README.md.example
CHANGED
|
@@ -225,7 +225,7 @@ I’m developing a new library, [floss_funding][🖇floss-funding-gem], designed
|
|
|
225
225
|
|
|
226
226
|
**[Floss-Funding.dev][🖇floss-funding.dev]: 👉️ No network calls. 👉️ No tracking. 👉️ No oversight. 👉️ Minimal crypto hashing. 💡 Easily disabled nags**
|
|
227
227
|
|
|
228
|
-
[![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 to my FLOSS
|
|
228
|
+
[![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 to my FLOSS efforts at ko-fi.com][🖇kofi-img]][🖇kofi] [![Donate to my FLOSS efforts using Patreon][🖇patreon-img]][🖇patreon]
|
|
229
229
|
|
|
230
230
|
## 🔐 Security
|
|
231
231
|
|
|
@@ -352,7 +352,7 @@ To join the community or get help 👇️ Join the Discord.
|
|
|
352
352
|
|
|
353
353
|
To say "thanks!" ☝️ Join the Discord or 👇️ send money.
|
|
354
354
|
|
|
355
|
-
[![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
|
|
355
|
+
[![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]
|
|
356
356
|
|
|
357
357
|
### Please give the project a star ⭐ ♥.
|
|
358
358
|
|
|
@@ -542,10 +542,10 @@ Thanks for RTFM. ☺️
|
|
|
542
542
|
[📌changelog]: CHANGELOG.md
|
|
543
543
|
[📗keep-changelog]: https://keepachangelog.com/en/1.0.0/
|
|
544
544
|
[📗keep-changelog-img]: https://img.shields.io/badge/keep--a--changelog-1.0.0-34495e.svg?style=flat
|
|
545
|
-
[📌gitmoji]:https://gitmoji.dev
|
|
546
|
-
[📌gitmoji-img]:https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
545
|
+
[📌gitmoji]: https://gitmoji.dev
|
|
546
|
+
[📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
547
547
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
548
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-4.
|
|
548
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-4.278-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
|
549
549
|
[🔐security]: SECURITY.md
|
|
550
550
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
|
551
551
|
[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
|
data/README.md.no-osc.example
CHANGED
|
@@ -202,7 +202,7 @@ I’m developing a new library, [floss_funding][🖇floss-funding-gem], designed
|
|
|
202
202
|
|
|
203
203
|
**[Floss-Funding.dev][🖇floss-funding.dev]: 👉️ No network calls. 👉️ No tracking. 👉️ No oversight. 👉️ Minimal crypto hashing. 💡 Easily disabled nags**
|
|
204
204
|
|
|
205
|
-
[![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 to my FLOSS
|
|
205
|
+
[![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 to my FLOSS efforts at ko-fi.com][🖇kofi-img]][🖇kofi] [![Donate to my FLOSS efforts using Patreon][🖇patreon-img]][🖇patreon]
|
|
206
206
|
|
|
207
207
|
## 🔐 Security
|
|
208
208
|
|
|
@@ -329,7 +329,7 @@ To join the community or get help 👇️ Join the Discord.
|
|
|
329
329
|
|
|
330
330
|
To say "thanks!" ☝️ Join the Discord or 👇️ send money.
|
|
331
331
|
|
|
332
|
-
[![Sponsor me on GitHub Sponsors][🖇sponsor-bottom-img]][🖇sponsor] 💌 [![Sponsor me on Liberapay][⛳liberapay-bottom-img]][⛳liberapay
|
|
332
|
+
[![Sponsor me on GitHub Sponsors][🖇sponsor-bottom-img]][🖇sponsor] 💌 [![Sponsor me on Liberapay][⛳liberapay-bottom-img]][⛳liberapay] 💌 [![Donate on PayPal][🖇paypal-bottom-img]][🖇paypal]
|
|
333
333
|
|
|
334
334
|
### Please give the project a star ⭐ ♥.
|
|
335
335
|
|
|
@@ -508,8 +508,8 @@ Thanks for RTFM. ☺️
|
|
|
508
508
|
[📌changelog]: CHANGELOG.md
|
|
509
509
|
[📗keep-changelog]: https://keepachangelog.com/en/1.0.0/
|
|
510
510
|
[📗keep-changelog-img]: https://img.shields.io/badge/keep--a--changelog-1.0.0-34495e.svg?style=flat
|
|
511
|
-
[📌gitmoji]:https://gitmoji.dev
|
|
512
|
-
[📌gitmoji-img]:https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
511
|
+
[📌gitmoji]: https://gitmoji.dev
|
|
512
|
+
[📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
513
513
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
514
514
|
[🧮kloc-img]: https://img.shields.io/badge/KLOC-4.076-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
|
515
515
|
[🔐security]: SECURITY.md
|
data/Rakefile.example
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# External stdlibs
|
|
4
4
|
require "find"
|
|
5
|
+
require "set"
|
|
5
6
|
|
|
6
7
|
module Kettle
|
|
7
8
|
module Dev
|
|
@@ -277,6 +278,46 @@ module Kettle
|
|
|
277
278
|
Kettle::Dev.debug_error(e, __method__)
|
|
278
279
|
# If replacement fails unexpectedly, proceed with content as-is
|
|
279
280
|
end
|
|
281
|
+
|
|
282
|
+
# If updating the Appraisals file and a destination already exists,
|
|
283
|
+
# merge appraise blocks: augment matching blocks with missing gem/eval_gemfile lines,
|
|
284
|
+
# preserve destination-only blocks and comments/preamble.
|
|
285
|
+
begin
|
|
286
|
+
if dest_exists && File.basename(dest_path.to_s) == "Appraisals" && File.file?(dest_path.to_s)
|
|
287
|
+
existing = begin
|
|
288
|
+
File.read(dest_path)
|
|
289
|
+
rescue
|
|
290
|
+
""
|
|
291
|
+
end
|
|
292
|
+
content = merge_appraisals(content, existing)
|
|
293
|
+
end
|
|
294
|
+
rescue StandardError => e
|
|
295
|
+
Kettle::Dev.debug_error(e, __method__)
|
|
296
|
+
# On any error, fall back to generated content
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
# If updating a Gemfile or modular .gemfile and the destination already exists,
|
|
300
|
+
# merge dependency lines from the source into the destination to preserve any
|
|
301
|
+
# user-defined gem entries. We append missing `gem "name"` lines; we never
|
|
302
|
+
# alter or remove existing gem lines in the destination.
|
|
303
|
+
begin
|
|
304
|
+
if dest_exists
|
|
305
|
+
dest_str = dest_path.to_s
|
|
306
|
+
is_gemfile_like = File.basename(dest_str) == "Gemfile" || dest_str.end_with?(".gemfile")
|
|
307
|
+
if is_gemfile_like && File.file?(dest_str)
|
|
308
|
+
begin
|
|
309
|
+
existing = File.read(dest_str)
|
|
310
|
+
content = merge_gemfile_dependencies(content, existing)
|
|
311
|
+
rescue StandardError => e
|
|
312
|
+
Kettle::Dev.debug_error(e, __method__)
|
|
313
|
+
# If merging fails, fall back to writing generated content
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
rescue StandardError => e
|
|
318
|
+
Kettle::Dev.debug_error(e, __method__)
|
|
319
|
+
end
|
|
320
|
+
|
|
280
321
|
write_file(dest_path, content)
|
|
281
322
|
begin
|
|
282
323
|
# Ensure executable bit for git hook scripts when writing under .git-hooks
|
|
@@ -291,6 +332,272 @@ module Kettle
|
|
|
291
332
|
puts "Wrote #{dest_path}"
|
|
292
333
|
end
|
|
293
334
|
|
|
335
|
+
# Merge gem dependency lines from a source Gemfile-like content into an existing
|
|
336
|
+
# destination Gemfile-like content. Existing gem lines in the destination win;
|
|
337
|
+
# we only append missing gem declarations from the source at the end of the file.
|
|
338
|
+
# This is deliberately conservative and avoids attempting to relocate gems inside
|
|
339
|
+
# group/platform blocks or reconcile version constraints.
|
|
340
|
+
# @param src_content [String]
|
|
341
|
+
# @param dest_content [String]
|
|
342
|
+
# @return [String] merged content
|
|
343
|
+
def merge_gemfile_dependencies(src_content, dest_content)
|
|
344
|
+
begin
|
|
345
|
+
gem_re = /^\s*gem\s+['"]([^'"\s]+)['"].*$/
|
|
346
|
+
# Collect first occurrence of each gem line in source
|
|
347
|
+
src_gems = {}
|
|
348
|
+
src_content.each_line do |ln|
|
|
349
|
+
next if ln.strip.start_with?("#")
|
|
350
|
+
if (m = ln.match(gem_re))
|
|
351
|
+
name = m[1]
|
|
352
|
+
src_gems[name] ||= ln.rstrip
|
|
353
|
+
end
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
# --- Handle `source` replacement/insertion ---
|
|
357
|
+
src_source_line = nil
|
|
358
|
+
src_content.each_line do |ln|
|
|
359
|
+
next if ln.strip.start_with?("#")
|
|
360
|
+
if ln =~ /^\s*source\s+['"][^'"]+['"]\s*$/
|
|
361
|
+
src_source_line = ln.rstrip + "\n"
|
|
362
|
+
break
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
dest_lines = dest_content.lines.dup
|
|
367
|
+
|
|
368
|
+
if src_source_line
|
|
369
|
+
dest_source_idx = dest_lines.index do |ln|
|
|
370
|
+
!ln.strip.start_with?("#") && ln =~ /^\s*source\s+['"][^'"]+['"]\s*$/
|
|
371
|
+
end
|
|
372
|
+
if dest_source_idx
|
|
373
|
+
dest_lines[dest_source_idx] = src_source_line
|
|
374
|
+
else
|
|
375
|
+
# Insert after any leading contiguous comment/blank block at top of file
|
|
376
|
+
insert_idx = 0
|
|
377
|
+
while insert_idx < dest_lines.length && (dest_lines[insert_idx].strip.empty? || dest_lines[insert_idx].lstrip.start_with?("#"))
|
|
378
|
+
insert_idx += 1
|
|
379
|
+
end
|
|
380
|
+
dest_lines.insert(insert_idx, src_source_line)
|
|
381
|
+
end
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
# --- Handle `git_source` replacement/insertion ---
|
|
385
|
+
# Collect non-comment git_source lines from source (preserve order)
|
|
386
|
+
src_git_lines = src_content.each_line.select { |ln| !ln.strip.start_with?("#") && ln =~ /^\s*git_source\s*\(/ }
|
|
387
|
+
if src_git_lines.any?
|
|
388
|
+
# Insert new git_source lines in the same order as they appear in the source
|
|
389
|
+
# When inserting (not replacing), place them immediately after the source line if present
|
|
390
|
+
insert_after_source_idx = dest_lines.index { |ln| !ln.strip.start_with?("#") && ln =~ /^\s*source\s+['"][^'"]+['"]\s*$/ }
|
|
391
|
+
|
|
392
|
+
# Iterate source git lines in reverse for insertion so order is preserved when inserting at same index
|
|
393
|
+
src_git_lines.reverse_each do |gln|
|
|
394
|
+
# Attempt to extract the git_source "name" (handles forms like git_source(:github) or git_source :github)
|
|
395
|
+
name_match = gln.match(/^\s*git_source\s*\(?\s*:?(\w+)\b/)
|
|
396
|
+
name = name_match ? name_match[1].to_s : nil
|
|
397
|
+
|
|
398
|
+
replaced = false
|
|
399
|
+
if name
|
|
400
|
+
# Try to find a git_source in destination with the same name
|
|
401
|
+
dest_same_idx = dest_lines.index do |dln|
|
|
402
|
+
!dln.strip.start_with?("#") && dln =~ /^\s*git_source\s*\(?\s*:?#{Regexp.escape(name)}\b/
|
|
403
|
+
end
|
|
404
|
+
if dest_same_idx
|
|
405
|
+
dest_lines[dest_same_idx] = gln.rstrip + "\n"
|
|
406
|
+
replaced = true
|
|
407
|
+
end
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
unless replaced
|
|
411
|
+
# If destination has a github git_source, replace that
|
|
412
|
+
dest_github_idx = dest_lines.index do |dln|
|
|
413
|
+
!dln.strip.start_with?("#") && dln =~ /^\s*git_source\s*\(?\s*:?github\b/
|
|
414
|
+
end
|
|
415
|
+
if dest_github_idx
|
|
416
|
+
dest_lines[dest_github_idx] = gln.rstrip + "\n"
|
|
417
|
+
else
|
|
418
|
+
# Insert below the source line if present, otherwise at top (after comments)
|
|
419
|
+
insert_idx =
|
|
420
|
+
if insert_after_source_idx
|
|
421
|
+
insert_after_source_idx + 1
|
|
422
|
+
else
|
|
423
|
+
0
|
|
424
|
+
end
|
|
425
|
+
dest_lines.insert(insert_idx, gln.rstrip + "\n")
|
|
426
|
+
end
|
|
427
|
+
end
|
|
428
|
+
end
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
# Index existing gems in destination (after potential source/git_source changes)
|
|
432
|
+
dest_gems = {}
|
|
433
|
+
dest_lines.join.each_line do |ln|
|
|
434
|
+
next if ln.strip.start_with?("#")
|
|
435
|
+
if (m = ln.match(gem_re))
|
|
436
|
+
dest_gems[m[1]] = true
|
|
437
|
+
end
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
missing = src_gems.keys.reject { |n| dest_gems.key?(n) }
|
|
441
|
+
# If nothing to change, return original destination content
|
|
442
|
+
if missing.empty? && src_source_line.nil? && src_git_lines.empty?
|
|
443
|
+
return dest_content
|
|
444
|
+
end
|
|
445
|
+
|
|
446
|
+
out = dest_lines.join
|
|
447
|
+
out << "\n" unless out.end_with?("\n") || out.empty?
|
|
448
|
+
if missing.any?
|
|
449
|
+
out << missing.map { |n| src_gems[n] }.join("\n")
|
|
450
|
+
out << "\n"
|
|
451
|
+
end
|
|
452
|
+
out
|
|
453
|
+
rescue StandardError => e
|
|
454
|
+
Kettle::Dev.debug_error(e, __method__)
|
|
455
|
+
dest_content
|
|
456
|
+
end
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
# Merge Appraisals template into existing Appraisals file.
|
|
460
|
+
# Rules:
|
|
461
|
+
# - For each appraise "name" block in template:
|
|
462
|
+
# * If destination has same block, ensure all gem/ eval_gemfile lines from template
|
|
463
|
+
# exist in destination (append missing just before end), keep other dest lines.
|
|
464
|
+
# Use template's contiguous header comment lines (immediately preceding the appraise line)
|
|
465
|
+
# if any; otherwise retain destination's header comments.
|
|
466
|
+
# * If destination lacks the block, add the full template block (with its header).
|
|
467
|
+
# - Preserve destination-only blocks (not present in template) unchanged and after
|
|
468
|
+
# the merged template-ordered blocks.
|
|
469
|
+
# - Preamble (content before first appraise) comes from template when present, else destination.
|
|
470
|
+
def merge_appraisals(template_content, dest_content)
|
|
471
|
+
begin
|
|
472
|
+
parse_blocks = lambda do |text|
|
|
473
|
+
lines = text.lines
|
|
474
|
+
blocks = []
|
|
475
|
+
i = 0
|
|
476
|
+
while i < lines.length
|
|
477
|
+
line = lines[i]
|
|
478
|
+
if line =~ /^\s*appraise\s+["']([^"']+)["']\s+do\s*$/
|
|
479
|
+
name = $1
|
|
480
|
+
# collect header comment lines immediately preceding (contiguous, no blank between comment group and appraise line)
|
|
481
|
+
header_lines = []
|
|
482
|
+
j = i - 1
|
|
483
|
+
while j >= 0
|
|
484
|
+
prev = lines[j]
|
|
485
|
+
break if prev.strip.empty?
|
|
486
|
+
if prev.lstrip.start_with?("#")
|
|
487
|
+
header_lines.unshift(prev)
|
|
488
|
+
j -= 1
|
|
489
|
+
else
|
|
490
|
+
break
|
|
491
|
+
end
|
|
492
|
+
end
|
|
493
|
+
body_lines = []
|
|
494
|
+
i += 1
|
|
495
|
+
while i < lines.length
|
|
496
|
+
l2 = lines[i]
|
|
497
|
+
if l2 =~ /^\s*end\s*$/
|
|
498
|
+
end_line = l2
|
|
499
|
+
blocks << {
|
|
500
|
+
name: name,
|
|
501
|
+
header: header_lines.dup,
|
|
502
|
+
body: body_lines.dup,
|
|
503
|
+
end_line: end_line,
|
|
504
|
+
raw_order: blocks.length,
|
|
505
|
+
original_indices: (j ? (j + 1)..i : i),
|
|
506
|
+
}
|
|
507
|
+
break
|
|
508
|
+
else
|
|
509
|
+
body_lines << l2
|
|
510
|
+
end
|
|
511
|
+
i += 1
|
|
512
|
+
end
|
|
513
|
+
end
|
|
514
|
+
i += 1
|
|
515
|
+
end
|
|
516
|
+
preamble = if blocks.empty?
|
|
517
|
+
text
|
|
518
|
+
else
|
|
519
|
+
# preamble = lines from start up to first block start (exclusive)
|
|
520
|
+
first_block = blocks.first
|
|
521
|
+
# Take lines up to first occurrence of the appraise line (supports either quote type)
|
|
522
|
+
re = /^\s*appraise\s+["']#{Regexp.escape(first_block[:name])}["']\s+do\s*$/
|
|
523
|
+
idx = lines.index { |l| l =~ re } || 0
|
|
524
|
+
lines[0...idx].join
|
|
525
|
+
end
|
|
526
|
+
{blocks: blocks, preamble: preamble}
|
|
527
|
+
end
|
|
528
|
+
|
|
529
|
+
tmpl = parse_blocks.call(template_content)
|
|
530
|
+
dest = parse_blocks.call(dest_content)
|
|
531
|
+
tmpl_blocks = tmpl[:blocks]
|
|
532
|
+
dest_blocks = dest[:blocks]
|
|
533
|
+
dest_by_name = dest_blocks.map { |b| [b[:name], b] }.to_h
|
|
534
|
+
|
|
535
|
+
merged_blocks_strings = []
|
|
536
|
+
gem_or_eval_re = /^\s*(?:gem|eval_gemfile)\b/
|
|
537
|
+
|
|
538
|
+
tmpl_blocks.each do |tb|
|
|
539
|
+
if (db = dest_by_name[tb[:name]])
|
|
540
|
+
# Merge lines
|
|
541
|
+
existing_lines = db[:body].map(&:rstrip)
|
|
542
|
+
existing_set = existing_lines.to_set
|
|
543
|
+
# Collect template gem/eval lines
|
|
544
|
+
tmpl_needed = tb[:body].select { |l| gem_or_eval_re =~ l }
|
|
545
|
+
additions = []
|
|
546
|
+
tmpl_needed.each do |l|
|
|
547
|
+
line_key = l.rstrip
|
|
548
|
+
additions << l unless existing_set.include?(line_key)
|
|
549
|
+
end
|
|
550
|
+
merged_body = db[:body].dup
|
|
551
|
+
unless additions.empty?
|
|
552
|
+
# insert before end (just append; body excludes 'end')
|
|
553
|
+
merged_body += additions
|
|
554
|
+
end
|
|
555
|
+
header = tb[:header].any? ? tb[:header] : db[:header]
|
|
556
|
+
block_text = +""
|
|
557
|
+
block_text << "\n" unless merged_blocks_strings.empty?
|
|
558
|
+
header.each { |hl| block_text << hl } if header.any?
|
|
559
|
+
block_text << "appraise \"#{tb[:name]}\" do\n"
|
|
560
|
+
merged_body.each { |bl| block_text << bl }
|
|
561
|
+
block_text << db[:end_line]
|
|
562
|
+
merged_blocks_strings << block_text
|
|
563
|
+
dest_by_name.delete(tb[:name])
|
|
564
|
+
else
|
|
565
|
+
# New block from template
|
|
566
|
+
block_text = +""
|
|
567
|
+
block_text << "\n" unless merged_blocks_strings.empty?
|
|
568
|
+
tb[:header].each { |hl| block_text << hl } if tb[:header].any?
|
|
569
|
+
block_text << "appraise \"#{tb[:name]}\" do\n"
|
|
570
|
+
tb[:body].each { |bl| block_text << bl }
|
|
571
|
+
block_text << tb[:end_line]
|
|
572
|
+
merged_blocks_strings << block_text
|
|
573
|
+
end
|
|
574
|
+
end
|
|
575
|
+
# Append destination-only blocks preserving their original text
|
|
576
|
+
dest_remaining_order = dest_blocks.select { |b| dest_by_name.key?(b[:name]) }
|
|
577
|
+
dest_remaining_order.each do |b|
|
|
578
|
+
block_text = +""
|
|
579
|
+
block_text << "\n" unless merged_blocks_strings.empty?
|
|
580
|
+
b[:header].each { |hl| block_text << hl } if b[:header].any?
|
|
581
|
+
block_text << "appraise \"#{b[:name]}\" do\n"
|
|
582
|
+
b[:body].each { |bl| block_text << bl }
|
|
583
|
+
block_text << b[:end_line]
|
|
584
|
+
merged_blocks_strings << block_text
|
|
585
|
+
end
|
|
586
|
+
|
|
587
|
+
preamble = tmpl[:preamble].to_s.strip.empty? ? dest[:preamble] : tmpl[:preamble]
|
|
588
|
+
out = +""
|
|
589
|
+
out << preamble unless preamble.nil? || preamble.empty?
|
|
590
|
+
out << "\n" unless out.end_with?("\n")
|
|
591
|
+
out << merged_blocks_strings.join
|
|
592
|
+
out << "\n" unless out.end_with?("\n")
|
|
593
|
+
out
|
|
594
|
+
rescue StandardError => e
|
|
595
|
+
Kettle::Dev.debug_error(e, __method__)
|
|
596
|
+
# Fallback: prefer destination (user changes) and append template content to allow manual reconciliation
|
|
597
|
+
dest_content + "\n# --- TEMPLATE APPRAISALS (unmerged) ---\n" + template_content
|
|
598
|
+
end
|
|
599
|
+
end
|
|
600
|
+
|
|
294
601
|
# Copy a directory tree, prompting before creating or overwriting.
|
|
295
602
|
# @return [void]
|
|
296
603
|
def copy_dir_with_prompt(src_dir, dest_dir)
|
data/lib/kettle/dev/version.rb
CHANGED
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kettle-dev
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.1.
|
|
4
|
+
version: 1.1.48
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter H. Boling
|
|
@@ -396,10 +396,10 @@ licenses:
|
|
|
396
396
|
- MIT
|
|
397
397
|
metadata:
|
|
398
398
|
homepage_uri: https://kettle-dev.galtzo.com/
|
|
399
|
-
source_code_uri: https://github.com/kettle-rb/kettle-dev/tree/v1.1.
|
|
400
|
-
changelog_uri: https://github.com/kettle-rb/kettle-dev/blob/v1.1.
|
|
399
|
+
source_code_uri: https://github.com/kettle-rb/kettle-dev/tree/v1.1.48
|
|
400
|
+
changelog_uri: https://github.com/kettle-rb/kettle-dev/blob/v1.1.48/CHANGELOG.md
|
|
401
401
|
bug_tracker_uri: https://github.com/kettle-rb/kettle-dev/issues
|
|
402
|
-
documentation_uri: https://www.rubydoc.info/gems/kettle-dev/1.1.
|
|
402
|
+
documentation_uri: https://www.rubydoc.info/gems/kettle-dev/1.1.48
|
|
403
403
|
funding_uri: https://github.com/sponsors/pboling
|
|
404
404
|
wiki_uri: https://github.com/kettle-rb/kettle-dev/wiki
|
|
405
405
|
news_uri: https://www.railsbling.com/tags/kettle-dev
|
metadata.gz.sig
CHANGED
|
Binary file
|