kettle-dev 1.0.21 → 1.0.23
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/.github/workflows/heads.yml +14 -2
- data/.github/workflows/heads.yml.example +97 -0
- data/Appraisals +2 -0
- data/CHANGELOG.md +28 -1
- data/FUNDING.md +77 -0
- data/README.md +1 -1
- data/README.md.example +1 -1
- data/Rakefile.example +1 -1
- data/kettle-dev.gemspec.example +3 -2
- data/lib/kettle/dev/gem_spec_reader.rb +129 -0
- data/lib/kettle/dev/tasks/install_task.rb +80 -89
- data/lib/kettle/dev/tasks/template_task.rb +102 -5
- data/lib/kettle/dev/template_helpers.rb +1 -77
- data/lib/kettle/dev/version.rb +1 -1
- data/lib/kettle/dev.rb +1 -0
- data/lib/kettle/emoji_regex.rb +1 -1
- data/sig/kettle/dev/gem_spec_reader.rbs +30 -0
- data/sig/kettle/dev/template_helpers.rbs +10 -0
- data.tar.gz.sig +0 -0
- metadata +9 -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: adce6d5a19e8f845c579e554910e6a0fbb1c8ad36447128a4d19029109dde152
|
4
|
+
data.tar.gz: b7bc5ec30e0427a941de9bff8b1fc859aa36f0f0d5ff30a21480f156f78943d1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 137aeb6d2e1fd6a8856093119abd2c6540df36cc1b3863a5e2ba63b959592d919521fd73e9618323b18aed4c77791925721826d4be3f9af69b39cd3d6089d838
|
7
|
+
data.tar.gz: fb2396ed69522155e4fe03f0e763b75ae6fd187ec34975c0fda67a90ad4167cbff38c86233ac4fc95352fa8f96da191272f98a66d23ecec4abb3e0263b05f095
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/.github/workflows/heads.yml
CHANGED
@@ -77,9 +77,21 @@ jobs:
|
|
77
77
|
# Raw `bundle` will use the BUNDLE_GEMFILE set to matrix.gemfile (i.e. Appraisal.root)
|
78
78
|
# We need to do this first to get appraisal installed.
|
79
79
|
# NOTE: This does not use the primary Gemfile at all.
|
80
|
-
- name: Install Root Appraisal
|
80
|
+
- name: "Install Root Appraisal"
|
81
81
|
run: bundle
|
82
|
-
|
82
|
+
|
83
|
+
- name: "[Attempt 1] Appraisal for ${{ matrix.ruby }}@${{ matrix.appraisal }}"
|
84
|
+
id: bundleAttempt1
|
85
|
+
run: bundle exec appraisal ${{ matrix.appraisal }} bundle
|
86
|
+
# Continue to the next step on failure
|
87
|
+
continue-on-error: true
|
88
|
+
|
89
|
+
# Effectively an automatic retry of the previous step.
|
90
|
+
- name: "[Attempt 2] Appraisal for ${{ matrix.ruby }}@${{ matrix.appraisal }}"
|
91
|
+
id: bundleAttempt2
|
92
|
+
# If bundleAttempt1 failed, try again here; Otherwise skip.
|
93
|
+
if: steps.bundleAttempt1.outcome == 'failure'
|
83
94
|
run: bundle exec appraisal ${{ matrix.appraisal }} bundle
|
95
|
+
|
84
96
|
- name: Tests for ${{ matrix.ruby }}@${{ matrix.appraisal }} via ${{ matrix.exec_cmd }}
|
85
97
|
run: bundle exec appraisal ${{ matrix.appraisal }} bundle exec ${{ matrix.exec_cmd }}
|
@@ -0,0 +1,97 @@
|
|
1
|
+
name: Heads
|
2
|
+
|
3
|
+
permissions:
|
4
|
+
contents: read
|
5
|
+
|
6
|
+
env:
|
7
|
+
K_SOUP_COV_DO: false
|
8
|
+
|
9
|
+
on:
|
10
|
+
push:
|
11
|
+
branches:
|
12
|
+
- 'main'
|
13
|
+
- '*-stable'
|
14
|
+
tags:
|
15
|
+
- '!*' # Do not execute on tags
|
16
|
+
pull_request:
|
17
|
+
branches:
|
18
|
+
- '*'
|
19
|
+
# Allow manually triggering the workflow.
|
20
|
+
workflow_dispatch:
|
21
|
+
|
22
|
+
# Cancels all previous workflow runs for the same branch that have not yet completed.
|
23
|
+
concurrency:
|
24
|
+
# The concurrency group contains the workflow name and the branch name.
|
25
|
+
group: "${{ github.workflow }}-${{ github.ref }}"
|
26
|
+
cancel-in-progress: true
|
27
|
+
|
28
|
+
jobs:
|
29
|
+
test:
|
30
|
+
if: "!contains(github.event.commits[0].message, '[ci skip]') && !contains(github.event.commits[0].message, '[skip ci]')"
|
31
|
+
name: Specs ${{ matrix.ruby }}@${{ matrix.appraisal }}${{ matrix.name_extra || '' }}
|
32
|
+
runs-on: ubuntu-latest
|
33
|
+
continue-on-error: ${{ matrix.experimental || endsWith(matrix.ruby, 'head') }}
|
34
|
+
env: # $BUNDLE_GEMFILE must be set at job level, so it is set for all steps
|
35
|
+
BUNDLE_GEMFILE: ${{ github.workspace }}/${{ matrix.gemfile }}.gemfile
|
36
|
+
strategy:
|
37
|
+
fail-fast: true
|
38
|
+
matrix:
|
39
|
+
include:
|
40
|
+
# NOTE: Heads use default rubygems / bundler; their defaults are custom, unreleased, and from the future!
|
41
|
+
# ruby-head
|
42
|
+
- ruby: "ruby-head"
|
43
|
+
appraisal: "head"
|
44
|
+
exec_cmd: "rake test"
|
45
|
+
gemfile: "Appraisal.root"
|
46
|
+
rubygems: default
|
47
|
+
bundler: default
|
48
|
+
|
49
|
+
# truffleruby-head
|
50
|
+
- ruby: "truffleruby-head"
|
51
|
+
appraisal: "head"
|
52
|
+
exec_cmd: "rake test"
|
53
|
+
gemfile: "Appraisal.root"
|
54
|
+
rubygems: default
|
55
|
+
bundler: default
|
56
|
+
|
57
|
+
# jruby-head
|
58
|
+
- ruby: "jruby-head"
|
59
|
+
appraisal: "head"
|
60
|
+
exec_cmd: "rake test"
|
61
|
+
gemfile: "Appraisal.root"
|
62
|
+
rubygems: default
|
63
|
+
bundler: default
|
64
|
+
|
65
|
+
steps:
|
66
|
+
- name: Checkout
|
67
|
+
uses: actions/checkout@v5
|
68
|
+
|
69
|
+
- name: Setup Ruby & RubyGems
|
70
|
+
uses: ruby/setup-ruby@v1
|
71
|
+
with:
|
72
|
+
ruby-version: ${{ matrix.ruby }}
|
73
|
+
rubygems: ${{ matrix.rubygems }}
|
74
|
+
bundler: ${{ matrix.bundler }}
|
75
|
+
bundler-cache: false
|
76
|
+
|
77
|
+
# Raw `bundle` will use the BUNDLE_GEMFILE set to matrix.gemfile (i.e. Appraisal.root)
|
78
|
+
# We need to do this first to get appraisal installed.
|
79
|
+
# NOTE: This does not use the primary Gemfile at all.
|
80
|
+
- name: "Install Root Appraisal"
|
81
|
+
run: bundle
|
82
|
+
|
83
|
+
- name: "[Attempt 1] Appraisal for ${{ matrix.ruby }}@${{ matrix.appraisal }}"
|
84
|
+
id: bundleAttempt1
|
85
|
+
run: bundle exec appraisal ${{ matrix.appraisal }} bundle
|
86
|
+
# Continue to the next step on failure
|
87
|
+
continue-on-error: true
|
88
|
+
|
89
|
+
# Effectively an automatic retry of the previous step.
|
90
|
+
- name: "[Attempt 2] Appraisal for ${{ matrix.ruby }}@${{ matrix.appraisal }}"
|
91
|
+
id: bundleAttempt2
|
92
|
+
# If bundleAttempt1 failed, try again here; Otherwise skip.
|
93
|
+
if: steps.bundleAttempt1.outcome == 'failure'
|
94
|
+
run: bundle exec appraisal ${{ matrix.appraisal }} bundle
|
95
|
+
|
96
|
+
- name: Tests for ${{ matrix.ruby }}@${{ matrix.appraisal }} via ${{ matrix.exec_cmd }}
|
97
|
+
run: bundle exec appraisal ${{ matrix.appraisal }} bundle exec ${{ matrix.exec_cmd }}
|
data/Appraisals
CHANGED
@@ -32,6 +32,8 @@ end
|
|
32
32
|
# Split into discrete appraisals if one of them needs a dependency locked discretely.
|
33
33
|
appraise "head" do
|
34
34
|
gem "erb"
|
35
|
+
# See: https://github.com/vcr/vcr/issues/1057
|
36
|
+
gem "cgi", ">= 0.5"
|
35
37
|
gem "mutex_m", ">= 0.2"
|
36
38
|
gem "stringio", ">= 3.0"
|
37
39
|
gem "benchmark", "~> 0.4", ">= 0.4.1"
|
data/CHANGELOG.md
CHANGED
@@ -24,6 +24,29 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
24
24
|
### Fixed
|
25
25
|
### Security
|
26
26
|
|
27
|
+
## [1.0.23] - 2025-08-30
|
28
|
+
- TAG: [v1.0.23][1.0.23t]
|
29
|
+
- COVERAGE: 97.75% -- 2428/2484 lines in 21 files
|
30
|
+
- BRANCH COVERAGE: 81.76% -- 1013/1239 branches in 21 files
|
31
|
+
- 76.00% documented
|
32
|
+
### Added
|
33
|
+
- Carryover important fields from the original gemspec during templating
|
34
|
+
- refactor gemspec parsing
|
35
|
+
- normalize template gemspec data
|
36
|
+
### Fixed
|
37
|
+
- include FUNDING.md in the released gem package
|
38
|
+
- typo of required_ruby_version
|
39
|
+
|
40
|
+
## [1.0.22] - 2025-08-30
|
41
|
+
- TAG: [v1.0.22][1.0.22t]
|
42
|
+
- COVERAGE: 97.82% -- 2375/2428 lines in 20 files
|
43
|
+
- BRANCH COVERAGE: 81.34% -- 972/1195 branches in 20 files
|
44
|
+
- 76.23% documented
|
45
|
+
### Added
|
46
|
+
- improved documentation
|
47
|
+
- example version of heads workflow
|
48
|
+
- give heads two attempts to succeed
|
49
|
+
|
27
50
|
## [1.0.21] - 2025-08-30
|
28
51
|
- TAG: [v1.0.21][1.0.21t]
|
29
52
|
- COVERAGE: 97.82% -- 2375/2428 lines in 20 files
|
@@ -328,7 +351,7 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
328
351
|
- Selecting will run the selected workflow via `act`
|
329
352
|
- This may move to its own gem in the future.
|
330
353
|
|
331
|
-
[Unreleased]: https://github.com/kettle-rb/kettle-dev/compare/v1.0.
|
354
|
+
[Unreleased]: https://github.com/kettle-rb/kettle-dev/compare/v1.0.23...HEAD
|
332
355
|
[1.0.0]: https://github.com/kettle-rb/kettle-dev/compare/a427c302df09cfe4253a7c8d400333f9a4c1a208...v1.0.0
|
333
356
|
[1.0.0t]: https://github.com/kettle-rb/kettle-dev/releases/tag/v1.0.0
|
334
357
|
[1.0.1]: https://gitlab.com/kettle-rb/kettle-dev/-/compare/v1.0.0...v1.0.1
|
@@ -373,3 +396,7 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
373
396
|
[1.0.20t]: https://github.com/kettle-rb/kettle-dev/releases/tag/v1.0.20
|
374
397
|
[1.0.21]: https://github.com/kettle-rb/kettle-dev/compare/v1.0.20...v1.0.21
|
375
398
|
[1.0.21t]: https://github.com/kettle-rb/kettle-dev/releases/tag/v1.0.21
|
399
|
+
[1.0.22]: https://github.com/kettle-rb/kettle-dev/compare/v1.0.21...v1.0.22
|
400
|
+
[1.0.22t]: https://github.com/kettle-rb/kettle-dev/releases/tag/v1.0.22
|
401
|
+
[1.0.23]: https://github.com/kettle-rb/kettle-dev/compare/v1.0.22...v1.0.23
|
402
|
+
[1.0.23t]: https://github.com/kettle-rb/kettle-dev/releases/tag/v1.0.23
|
data/FUNDING.md
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
<!-- RELEASE-NOTES-FOOTER-START -->
|
2
|
+
|
3
|
+
Official Discord 👉️ [![Live Chat on Discord][✉️discord-invite-img]][✉️discord-invite]
|
4
|
+
|
5
|
+
Many paths lead to being a sponsor or a backer of this project. Are you on such a path?
|
6
|
+
|
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
|
+
|
9
|
+
[![Buy me a coffee][🖇buyme-small-img]][🖇buyme] [![Donate on Polar][🖇polar-img]][🖇polar] [![Donate to my FLOSS or refugee efforts at ko-fi.com][🖇kofi-img]][🖇kofi] [![Donate to my FLOSS or refugee efforts using Patreon][🖇patreon-img]][🖇patreon]
|
10
|
+
|
11
|
+
[⛳liberapay-img]: https://img.shields.io/liberapay/goal/pboling.svg?logo=liberapay&color=a51611&style=flat
|
12
|
+
[⛳liberapay]: https://liberapay.com/pboling/donate
|
13
|
+
[🖇osc-backers]: https://opencollective.com/kettle-rb#backer
|
14
|
+
[🖇osc-backers-i]: https://opencollective.com/kettle-rb/backers/badge.svg?style=flat
|
15
|
+
[🖇osc-sponsors]: https://opencollective.com/kettle-rb#sponsor
|
16
|
+
[🖇osc-sponsors-i]: https://opencollective.com/kettle-rb/sponsors/badge.svg?style=flat
|
17
|
+
[🖇sponsor-img]: https://img.shields.io/badge/Sponsor_Me!-pboling.svg?style=social&logo=github
|
18
|
+
[🖇sponsor]: https://github.com/sponsors/pboling
|
19
|
+
[🖇polar-img]: https://img.shields.io/badge/polar-donate-a51611.svg?style=flat
|
20
|
+
[🖇polar]: https://polar.sh/pboling
|
21
|
+
[🖇kofi-img]: https://img.shields.io/badge/ko--fi-✓-a51611.svg?style=flat
|
22
|
+
[🖇kofi]: https://ko-fi.com/O5O86SNP4
|
23
|
+
[🖇patreon-img]: https://img.shields.io/badge/patreon-donate-a51611.svg?style=flat
|
24
|
+
[🖇patreon]: https://patreon.com/galtzo
|
25
|
+
[🖇buyme-small-img]: https://img.shields.io/badge/buy_me_a_coffee-✓-a51611.svg?style=flat
|
26
|
+
[🖇buyme]: https://www.buymeacoffee.com/pboling
|
27
|
+
[🖇paypal-img]: https://img.shields.io/badge/donate-paypal-a51611.svg?style=flat&logo=paypal
|
28
|
+
[🖇paypal]: https://www.paypal.com/paypalme/peterboling
|
29
|
+
[✉️discord-invite]: https://discord.gg/3qme4XHNKN
|
30
|
+
[✉️discord-invite-img]: https://img.shields.io/discord/1373797679469170758?style=flat
|
31
|
+
|
32
|
+
<!-- RELEASE-NOTES-FOOTER-END -->
|
33
|
+
|
34
|
+
# 🤑 Request for Help
|
35
|
+
|
36
|
+
Maintainers have teeth and need to pay their dentists.
|
37
|
+
After getting laid off in an RIF in March and filled with many dozens of rejections,
|
38
|
+
I'm now spending ~60+ hours a week building open source tools.
|
39
|
+
I'm hoping to be able to pay for my kids' health insurance this month,
|
40
|
+
so if you value the work I am doing, I need your support.
|
41
|
+
Please consider sponsoring me or the project.
|
42
|
+
|
43
|
+
To join the community or get help 👇️ Join the Discord.
|
44
|
+
|
45
|
+
[![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite]
|
46
|
+
|
47
|
+
To say "thanks for maintaining such a great tool" ☝️ Join the Discord or 👇️ send money.
|
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-img] 💌 [![Donate on PayPal][🖇paypal-bottom-img]][🖇paypal-img]
|
50
|
+
|
51
|
+
# Another Way to Support Open Source Software
|
52
|
+
|
53
|
+
> How wonderful it is that nobody need wait a single moment before starting to improve the world.<br/>
|
54
|
+
>—Anne Frank
|
55
|
+
|
56
|
+
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 — totaling 79 hours of FLOSS coding over just the past seven days, a pretty regular week for me. 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).
|
57
|
+
|
58
|
+
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`.
|
59
|
+
|
60
|
+
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.
|
61
|
+
|
62
|
+
**[Floss-Funding.dev][🖇floss-funding.dev]: 👉️ No network calls. 👉️ No tracking. 👉️ No oversight. 👉️ Minimal crypto hashing. 💡 Easily disabled nags**
|
63
|
+
|
64
|
+
[⛳liberapay-bottom-img]: https://img.shields.io/liberapay/goal/pboling.svg?style=for-the-badge&logo=liberapay&color=a51611
|
65
|
+
[🖇osc-all-img]: https://img.shields.io/opencollective/all/kettle-rb
|
66
|
+
[🖇osc-sponsors-img]: https://img.shields.io/opencollective/sponsors/kettle-rb
|
67
|
+
[🖇osc-backers-img]: https://img.shields.io/opencollective/backers/kettle-rb
|
68
|
+
[🖇osc-all-bottom-img]: https://img.shields.io/opencollective/all/kettle-rb?style=for-the-badge
|
69
|
+
[🖇osc-sponsors-bottom-img]: https://img.shields.io/opencollective/sponsors/kettle-rb?style=for-the-badge
|
70
|
+
[🖇osc-backers-bottom-img]: https://img.shields.io/opencollective/backers/kettle-rb?style=for-the-badge
|
71
|
+
[🖇osc]: https://opencollective.com/kettle-rb
|
72
|
+
[🖇sponsor-bottom-img]: https://img.shields.io/badge/Sponsor_Me!-pboling-blue?style=for-the-badge&logo=github
|
73
|
+
[🖇buyme-img]: https://img.buymeacoffee.com/button-api/?text=Buy%20me%20a%20latte&emoji=&slug=pboling&button_colour=FFDD00&font_colour=000000&font_family=Cookie&outline_colour=000000&coffee_colour=ffffff
|
74
|
+
[🖇paypal-bottom-img]: https://img.shields.io/badge/donate-paypal-a51611.svg?style=for-the-badge&logo=paypal&color=0A0A0A
|
75
|
+
[🖇floss-funding.dev]: https://floss-funding.dev
|
76
|
+
[🖇floss-funding-gem]: https://github.com/galtzo-floss/floss_funding
|
77
|
+
[✉️discord-invite-img-ftb]: https://img.shields.io/discord/1373797679469170758?style=for-the-badge
|
data/README.md
CHANGED
@@ -735,7 +735,7 @@ Thanks for RTFM. ☺️
|
|
735
735
|
[📌gitmoji]:https://gitmoji.dev
|
736
736
|
[📌gitmoji-img]:https://img.shields.io/badge/gitmoji_commits-%20😜%20😍-34495e.svg?style=flat-square
|
737
737
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
738
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-2.
|
738
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-2.484-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
739
739
|
[🔐security]: SECURITY.md
|
740
740
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
741
741
|
[📄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
@@ -501,7 +501,7 @@ Thanks for RTFM. ☺️
|
|
501
501
|
[📌gitmoji]:https://gitmoji.dev
|
502
502
|
[📌gitmoji-img]:https://img.shields.io/badge/gitmoji_commits-%20😜%20😍-34495e.svg?style=flat-square
|
503
503
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
504
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-2.
|
504
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-2.484-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
505
505
|
[🔐security]: SECURITY.md
|
506
506
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
507
507
|
[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
|
data/Rakefile.example
CHANGED
data/kettle-dev.gemspec.example
CHANGED
@@ -26,12 +26,12 @@ Gem::Specification.new do |spec|
|
|
26
26
|
spec.summary = "🍲 "
|
27
27
|
spec.description = "🍲 "
|
28
28
|
spec.homepage = "https://github.com/kettle-rb/kettle-dev"
|
29
|
-
spec.
|
29
|
+
spec.licenses = ["MIT"]
|
30
30
|
spec.required_ruby_version = ">= 2.3.0"
|
31
31
|
|
32
32
|
# Linux distros often package gems and securely certify them independent
|
33
33
|
# of the official RubyGem certification process. Allowed via ENV["SKIP_GEM_SIGNING"]
|
34
|
-
# Ref: https://gitlab.com/oauth
|
34
|
+
# Ref: https://gitlab.com/ruby-oauth/version_gem/-/issues/3
|
35
35
|
# Hence, only enable signing if `SKIP_GEM_SIGNING` is not set in ENV.
|
36
36
|
# See CONTRIBUTING.md
|
37
37
|
unless ENV.include?("SKIP_GEM_SIGNING")
|
@@ -75,6 +75,7 @@ Gem::Specification.new do |spec|
|
|
75
75
|
"CITATION.cff",
|
76
76
|
"CODE_OF_CONDUCT.md",
|
77
77
|
"CONTRIBUTING.md",
|
78
|
+
"FUNDING.md",
|
78
79
|
"LICENSE.txt",
|
79
80
|
"README.md",
|
80
81
|
"REEK",
|
@@ -0,0 +1,129 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rubygems"
|
4
|
+
|
5
|
+
module Kettle
|
6
|
+
module Dev
|
7
|
+
# Unified gemspec reader using RubyGems loader instead of regex parsing.
|
8
|
+
# Returns a Hash with all data used by this project from gemspecs.
|
9
|
+
# Cache within the process to avoid repeated loads.
|
10
|
+
class GemSpecReader
|
11
|
+
DEFAULT_MINIMUM_RUBY = Gem::Version.new("1.8").freeze
|
12
|
+
class << self
|
13
|
+
# Load gemspec data for the project at root.
|
14
|
+
# @param root [String]
|
15
|
+
# @return [Hash]
|
16
|
+
def load(root)
|
17
|
+
gemspec_path = Dir.glob(File.join(root.to_s, "*.gemspec")).first
|
18
|
+
spec = nil
|
19
|
+
if gemspec_path && File.file?(gemspec_path)
|
20
|
+
begin
|
21
|
+
spec = Gem::Specification.load(gemspec_path)
|
22
|
+
rescue StandardError
|
23
|
+
spec = nil
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
gem_name = spec&.name.to_s
|
28
|
+
# minimum ruby version: derived from spec.required_ruby_version
|
29
|
+
# Always an instance of Gem::Version
|
30
|
+
min_ruby =
|
31
|
+
begin
|
32
|
+
# irb(main):004> Gem::Requirement.parse(spec.required_ruby_version)
|
33
|
+
# => [">=", Gem::Version.new("2.3.0")]
|
34
|
+
requirement = spec&.required_ruby_version
|
35
|
+
if requirement
|
36
|
+
tuple = Gem::Requirement.parse(requirement)
|
37
|
+
tuple[1] # an instance of Gem::Version
|
38
|
+
else
|
39
|
+
# Default to a minimum of Ruby 1.8
|
40
|
+
puts "WARNING: Minimum Ruby not detected"
|
41
|
+
DEFAULT_MINIMUM_RUBY
|
42
|
+
end
|
43
|
+
rescue StandardError => e
|
44
|
+
# Default to a minimum of Ruby 1.8
|
45
|
+
puts "WARNING: Minimum Ruby detection failed: #{e.class}: #{e.message}"
|
46
|
+
DEFAULT_MINIMUM_RUBY
|
47
|
+
end
|
48
|
+
|
49
|
+
homepage_val = spec&.homepage.to_s
|
50
|
+
|
51
|
+
# Derive org/repo from homepage or git remote
|
52
|
+
forge_org = nil
|
53
|
+
gh_repo = nil
|
54
|
+
if homepage_val && !homepage_val.empty?
|
55
|
+
if (m = homepage_val.match(%r{github\.com[/:]([^/]+)/([^/]+)}i))
|
56
|
+
forge_org = m[1]
|
57
|
+
gh_repo = m[2].to_s.sub(/\.git\z/, "")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
if forge_org.nil?
|
61
|
+
begin
|
62
|
+
origin_out = IO.popen(["git", "-C", root.to_s, "remote", "get-url", "origin"], &:read)
|
63
|
+
origin_out = origin_out.read if origin_out.respond_to?(:read)
|
64
|
+
origin_url = origin_out.to_s.strip
|
65
|
+
if (m = origin_url.match(%r{github\.com[/:]([^/]+)/([^/]+)}i))
|
66
|
+
forge_org = m[1]
|
67
|
+
gh_repo = m[2].to_s.sub(/\.git\z/, "")
|
68
|
+
end
|
69
|
+
rescue StandardError
|
70
|
+
# ignore
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
camel = lambda do |s|
|
75
|
+
s.to_s.split(/[_-]/).map { |p| p.gsub(/\b([a-z])/) { Regexp.last_match(1).upcase } }.join
|
76
|
+
end
|
77
|
+
namespace = gem_name.to_s.split("-").map { |seg| camel.call(seg) }.join("::")
|
78
|
+
namespace_shield = namespace.gsub("::", "%3A%3A")
|
79
|
+
entrypoint_require = gem_name.to_s.tr("-", "/")
|
80
|
+
gem_shield = gem_name.to_s.gsub("-", "--").gsub("_", "__")
|
81
|
+
|
82
|
+
# Funding org detection (ENV, .opencollective.yml, fallback to forge_org)
|
83
|
+
funding_org = ENV["FUNDING_ORG"].to_s.strip
|
84
|
+
funding_org = ENV["OPENCOLLECTIVE_ORG"].to_s.strip if funding_org.empty?
|
85
|
+
funding_org = ENV["OPENCOLLECTIVE_HANDLE"].to_s.strip if funding_org.empty?
|
86
|
+
if funding_org.empty?
|
87
|
+
begin
|
88
|
+
oc_path = File.join(root.to_s, ".opencollective.yml")
|
89
|
+
if File.file?(oc_path)
|
90
|
+
txt = File.read(oc_path)
|
91
|
+
if (m = txt.match(/\borg:\s*([\w\-]+)/i))
|
92
|
+
funding_org = m[1].to_s
|
93
|
+
end
|
94
|
+
end
|
95
|
+
rescue StandardError
|
96
|
+
# ignore
|
97
|
+
end
|
98
|
+
end
|
99
|
+
funding_org = forge_org.to_s if funding_org.to_s.empty?
|
100
|
+
|
101
|
+
{
|
102
|
+
gemspec_path: gemspec_path,
|
103
|
+
gem_name: gem_name,
|
104
|
+
min_ruby: min_ruby, # Gem::Version instance
|
105
|
+
homepage: homepage_val.to_s,
|
106
|
+
gh_org: forge_org, # Might allow divergence from forge_org someday
|
107
|
+
forge_org: forge_org,
|
108
|
+
funding_org: funding_org,
|
109
|
+
gh_repo: gh_repo,
|
110
|
+
namespace: namespace,
|
111
|
+
namespace_shield: namespace_shield,
|
112
|
+
entrypoint_require: entrypoint_require,
|
113
|
+
gem_shield: gem_shield,
|
114
|
+
# Additional fields sourced from the gemspec for templating carry-over
|
115
|
+
authors: Array(spec&.authors).compact.uniq,
|
116
|
+
email: Array(spec&.email).compact.uniq,
|
117
|
+
summary: spec&.summary.to_s,
|
118
|
+
description: spec&.description.to_s,
|
119
|
+
licenses: Array(spec&.licenses), # licenses will include any specified as license (singular)
|
120
|
+
required_ruby_version: spec&.required_ruby_version, # Gem::Requirement instance
|
121
|
+
require_paths: Array(spec&.require_paths),
|
122
|
+
bindir: (spec&.bindir || "").to_s,
|
123
|
+
executables: Array(spec&.executables),
|
124
|
+
}
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -44,107 +44,98 @@ module Kettle
|
|
44
44
|
readme_path = File.join(project_root, "README.md")
|
45
45
|
if File.file?(readme_path)
|
46
46
|
md = helpers.gemspec_metadata(project_root)
|
47
|
-
min_ruby = md[:min_ruby]
|
48
|
-
if
|
49
|
-
|
50
|
-
require "rubygems"
|
51
|
-
min_ver = begin
|
52
|
-
Gem::Version.new(min_ruby.sub(/\A(~>\s*|>=\s*)/, ""))
|
53
|
-
rescue
|
54
|
-
nil
|
55
|
-
end
|
56
|
-
if min_ver
|
57
|
-
content = File.read(readme_path)
|
47
|
+
min_ruby = md[:min_ruby] # an instance of Gem::Version
|
48
|
+
if min_ruby
|
49
|
+
content = File.read(readme_path)
|
58
50
|
|
59
|
-
|
60
|
-
|
51
|
+
# Detect all MRI ruby badge labels present
|
52
|
+
removed_labels = []
|
61
53
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
end
|
75
|
-
rescue StandardError
|
76
|
-
# ignore
|
54
|
+
content.scan(/\[(?<label>💎ruby-(?<ver>\d+\.\d+)i)\]/) do |arr|
|
55
|
+
label, ver_s = arr
|
56
|
+
begin
|
57
|
+
ver = Gem::Version.new(ver_s)
|
58
|
+
if ver < min_ruby
|
59
|
+
# Remove occurrences of badges using this label
|
60
|
+
label_re = Regexp.escape(label)
|
61
|
+
# Linked form: [![...][label]][...]
|
62
|
+
content = content.gsub(/\[!\[[^\]]*?\]\s*\[#{label_re}\]\s*\]\s*\[[^\]]+\]/, "")
|
63
|
+
# Unlinked form: ![...][label]
|
64
|
+
content = content.gsub(/!\[[^\]]*?\]\s*\[#{label_re}\]/, "")
|
65
|
+
removed_labels << label
|
77
66
|
end
|
67
|
+
rescue StandardError
|
68
|
+
# ignore
|
78
69
|
end
|
70
|
+
end
|
79
71
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
else
|
97
|
-
ln
|
98
|
-
end
|
72
|
+
# Fix leading <br/> in MRI rows and remove rows that end up empty
|
73
|
+
content = content.lines.map { |ln|
|
74
|
+
if ln.start_with?("| Works with MRI Ruby")
|
75
|
+
cells = ln.split("|", -1)
|
76
|
+
# cells[0] is empty (leading |), cells[1] = label cell, cells[2] = badges cell
|
77
|
+
badge_cell = cells[2] || ""
|
78
|
+
# If badge cell is only a <br/> (possibly with whitespace), treat as empty (row will be removed later)
|
79
|
+
if badge_cell.strip == "<br/>"
|
80
|
+
cells[2] = " "
|
81
|
+
cells.join("|")
|
82
|
+
elsif badge_cell =~ /\A\s*<br\/>/i
|
83
|
+
# If badge cell starts with <br/> and there are no badges before it, strip the leading <br/>
|
84
|
+
# We consider "no badges before" as any leading whitespace followed immediately by <br/>
|
85
|
+
cleaned = badge_cell.sub(/\A\s*<br\/>\s*/i, "")
|
86
|
+
cells[2] = " #{cleaned}" # prefix with a single space
|
87
|
+
cells.join("|")
|
99
88
|
else
|
100
89
|
ln
|
101
90
|
end
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
content = content.lines.map do |ln|
|
115
|
-
if ln.start_with?("|")
|
116
|
-
ln
|
117
|
-
else
|
118
|
-
# Squish only runs of spaces/tabs between word characters
|
119
|
-
ln.gsub(/(\w)[ \t]{2,}(\w)/u, "\\1 \\2")
|
120
|
-
end
|
121
|
-
end.join
|
122
|
-
|
123
|
-
# Remove reference definitions for removed labels that are no longer used
|
124
|
-
unless removed_labels.empty?
|
125
|
-
# Unique
|
126
|
-
removed_labels.uniq!
|
127
|
-
# Determine which labels are still referenced after edits
|
128
|
-
still_referenced = {}
|
129
|
-
removed_labels.each do |lbl|
|
130
|
-
lbl_re = Regexp.escape(lbl)
|
131
|
-
# Consider a label referenced only when it appears not as a definition (i.e., not followed by colon)
|
132
|
-
still_referenced[lbl] = !!(content =~ /\[#{lbl_re}\](?!:)/)
|
133
|
-
end
|
91
|
+
else
|
92
|
+
ln
|
93
|
+
end
|
94
|
+
}.reject { |ln|
|
95
|
+
if ln.start_with?("| Works with MRI Ruby")
|
96
|
+
cells = ln.split("|", -1)
|
97
|
+
badge_cell = cells[2] || ""
|
98
|
+
badge_cell.strip.empty?
|
99
|
+
else
|
100
|
+
false
|
101
|
+
end
|
102
|
+
}.join
|
134
103
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
104
|
+
# Clean up extra repeated whitespace only when it appears between word characters, and only for non-table lines.
|
105
|
+
# This preserves Markdown table alignment and spacing around punctuation/symbols.
|
106
|
+
content = content.lines.map do |ln|
|
107
|
+
if ln.start_with?("|")
|
108
|
+
ln
|
109
|
+
else
|
110
|
+
# Squish only runs of spaces/tabs between word characters
|
111
|
+
ln.gsub(/(\w)[ \t]{2,}(\w)/u, "\\1 \\2")
|
112
|
+
end
|
113
|
+
end.join
|
114
|
+
|
115
|
+
# Remove reference definitions for removed labels that are no longer used
|
116
|
+
unless removed_labels.empty?
|
117
|
+
# Unique
|
118
|
+
removed_labels.uniq!
|
119
|
+
# Determine which labels are still referenced after edits
|
120
|
+
still_referenced = {}
|
121
|
+
removed_labels.each do |lbl|
|
122
|
+
lbl_re = Regexp.escape(lbl)
|
123
|
+
# Consider a label referenced only when it appears not as a definition (i.e., not followed by colon)
|
124
|
+
still_referenced[lbl] = !!(content =~ /\[#{lbl_re}\](?!:)/)
|
144
125
|
end
|
145
126
|
|
146
|
-
|
127
|
+
new_lines = content.lines.map do |line|
|
128
|
+
if line =~ /^\[(?<lab>[^\]]+)\]:/ && removed_labels.include?(Regexp.last_match(:lab))
|
129
|
+
# Only drop if not referenced anymore
|
130
|
+
still_referenced[Regexp.last_match(:lab)] ? line : nil
|
131
|
+
else
|
132
|
+
line
|
133
|
+
end
|
134
|
+
end.compact
|
135
|
+
content = new_lines.join
|
147
136
|
end
|
137
|
+
|
138
|
+
File.open(readme_path, "w") { |f| f.write(content) }
|
148
139
|
end
|
149
140
|
end
|
150
141
|
rescue StandardError => e
|
@@ -123,10 +123,9 @@ module Kettle
|
|
123
123
|
rubocop_ruby_gem_version = nil
|
124
124
|
ruby1_8 = version_map.first
|
125
125
|
begin
|
126
|
-
if min_ruby
|
127
|
-
v = Gem::Version.new(min_ruby.split(".")[0, 2].join("."))
|
126
|
+
if min_ruby
|
128
127
|
version_map.reverse_each do |min, req|
|
129
|
-
if
|
128
|
+
if min_ruby >= min
|
130
129
|
new_constraint = req
|
131
130
|
rubocop_ruby_gem_version = min.segments.join("_")
|
132
131
|
break
|
@@ -205,8 +204,20 @@ module Kettle
|
|
205
204
|
File.join(project_root, fallback_name)
|
206
205
|
end
|
207
206
|
end
|
207
|
+
|
208
|
+
# If a destination gemspec already exists, get metadata from GemSpecReader via helpers
|
209
|
+
orig_meta = nil
|
210
|
+
if File.exist?(dest_gemspec)
|
211
|
+
begin
|
212
|
+
orig_meta = helpers.gemspec_metadata(File.dirname(dest_gemspec))
|
213
|
+
rescue StandardError
|
214
|
+
orig_meta = nil
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
208
218
|
helpers.copy_file_with_prompt(gemspec_template_src, dest_gemspec, allow_create: true, allow_replace: true) do |content|
|
209
|
-
|
219
|
+
# First apply standard replacements from the template example
|
220
|
+
c = helpers.apply_common_replacements(
|
210
221
|
content,
|
211
222
|
org: forge_org,
|
212
223
|
gem_name: gem_name,
|
@@ -214,6 +225,93 @@ module Kettle
|
|
214
225
|
namespace_shield: namespace_shield,
|
215
226
|
gem_shield: gem_shield,
|
216
227
|
)
|
228
|
+
|
229
|
+
if orig_meta
|
230
|
+
# Replace a scalar string assignment like: spec.field = "..."
|
231
|
+
replace_string_field = lambda do |txt, field, value|
|
232
|
+
v = value.to_s
|
233
|
+
txt.gsub(/(\bspec\.#{Regexp.escape(field)}\s*=\s*)(["']).*?(\2)/) do
|
234
|
+
pre = Regexp.last_match(1)
|
235
|
+
q = '"'
|
236
|
+
pre + q + v.gsub('"', '\\"') + q
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
# Replace an array assignment like: spec.field = ["a", "b"]
|
241
|
+
replace_array_field = lambda do |txt, field, ary|
|
242
|
+
ary = Array(ary).compact.map(&:to_s).reject(&:empty?).uniq
|
243
|
+
# literal = "[" + arr.map { |e| '"' + e.gsub('"', '\\"') + '"' }.join(", ") + "]"
|
244
|
+
literal = ary.inspect
|
245
|
+
if txt =~ /(\bspec\.#{Regexp.escape(field)}\s*=\s*)\[[^\]]*\]/
|
246
|
+
txt.gsub(/(\bspec\.#{Regexp.escape(field)}\s*=\s*)\[[^\]]*\]/, "\\1#{literal}")
|
247
|
+
else
|
248
|
+
# If no existing assignment, insert a new line after spec.version if possible
|
249
|
+
insert_after = (txt =~ /^\s*spec\.version\s*=.*$/) ? :version : nil
|
250
|
+
if insert_after == :version
|
251
|
+
txt.sub(/^(\s*spec\.version\s*=.*$)/) { |line| line + "\n spec.#{field} = #{literal}" }
|
252
|
+
else
|
253
|
+
txt + "\n spec.#{field} = #{literal}\n"
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
begin
|
259
|
+
# 1. spec.name — retain original
|
260
|
+
if (name = orig_meta[:gem_name]) && !name.to_s.empty?
|
261
|
+
c = replace_string_field.call(c, "name", name)
|
262
|
+
end
|
263
|
+
|
264
|
+
# 2. spec.authors — retain original, normalize to array
|
265
|
+
orig_auth = orig_meta[:authors]
|
266
|
+
c = replace_array_field.call(c, "authors", orig_auth)
|
267
|
+
|
268
|
+
# 3. spec.email — retain original, normalize to array
|
269
|
+
orig_email = orig_meta[:email]
|
270
|
+
c = replace_array_field.call(c, "email", orig_email)
|
271
|
+
|
272
|
+
# 4. spec.summary — retain original; grapheme emoji prefix handled by "install" task
|
273
|
+
if (sum = orig_meta[:summary]) && !sum.to_s.empty?
|
274
|
+
c = replace_string_field.call(c, "summary", sum)
|
275
|
+
end
|
276
|
+
|
277
|
+
# 5. spec.description — retain original; grapheme emoji prefix handled by "install" task
|
278
|
+
if (desc = orig_meta[:description]) && !desc.to_s.empty?
|
279
|
+
c = replace_string_field.call(c, "description", desc)
|
280
|
+
end
|
281
|
+
|
282
|
+
# 6. spec.licenses — retain original, normalize to array
|
283
|
+
lic = orig_meta[:licenses]
|
284
|
+
if lic && !lic.empty?
|
285
|
+
c = replace_array_field.call(c, "licenses", lic)
|
286
|
+
end
|
287
|
+
|
288
|
+
# 7. spec.required_ruby_version — retain original
|
289
|
+
if (rrv = orig_meta[:required_ruby_version].to_s) && !rrv.empty?
|
290
|
+
c = replace_string_field.call(c, "required_ruby_version", rrv)
|
291
|
+
end
|
292
|
+
|
293
|
+
# 8. spec.require_paths — retain original, normalize to array
|
294
|
+
req_paths = orig_meta[:require_paths]
|
295
|
+
unless req_paths.empty?
|
296
|
+
c = replace_array_field.call(c, "require_paths", req_paths)
|
297
|
+
end
|
298
|
+
|
299
|
+
# 9. spec.bindir — retain original
|
300
|
+
if (bd = orig_meta[:bindir]) && !bd.to_s.empty?
|
301
|
+
c = replace_string_field.call(c, "bindir", bd)
|
302
|
+
end
|
303
|
+
|
304
|
+
# 10. spec.executables — retain original, normalize to array
|
305
|
+
exes = orig_meta[:executables]
|
306
|
+
unless exes.empty?
|
307
|
+
c = replace_array_field.call(c, "executables", exes)
|
308
|
+
end
|
309
|
+
rescue StandardError
|
310
|
+
# Best-effort carry-over; ignore any individual failure
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
c
|
217
315
|
end
|
218
316
|
end
|
219
317
|
rescue StandardError
|
@@ -266,7 +364,6 @@ module Kettle
|
|
266
364
|
if prev_readme
|
267
365
|
first_h1_prev = prev_readme.lines.find { |ln| ln =~ /^#\s+/ }
|
268
366
|
if first_h1_prev
|
269
|
-
require "kettle/emoji_regex"
|
270
367
|
emoji_re = Kettle::EmojiRegex::REGEX
|
271
368
|
tail = first_h1_prev.sub(/^#\s+/, "")
|
272
369
|
# Extract consecutive leading emoji graphemes
|
@@ -362,83 +362,7 @@ module Kettle
|
|
362
362
|
# @param root [String] project root
|
363
363
|
# @return [Hash]
|
364
364
|
def gemspec_metadata(root = project_root)
|
365
|
-
|
366
|
-
gemspec_path = gemspecs.first
|
367
|
-
gemspec_text = (gemspec_path && File.file?(gemspec_path)) ? File.read(gemspec_path) : ""
|
368
|
-
gem_name = (gemspec_text[/\bspec\.name\s*=\s*["']([^"']+)["']/, 1] || "").strip
|
369
|
-
min_ruby = (
|
370
|
-
gemspec_text[/\bspec\.minimum_ruby_version\s*=\s*["'](?:>=\s*)?([0-9]+\.[0-9]+(?:\.[0-9]+)?)["']/i, 1] ||
|
371
|
-
gemspec_text[/\bspec\.required_ruby_version\s*=\s*["']>=\s*([0-9]+\.[0-9]+(?:\.[0-9]+)?)["']/i, 1] ||
|
372
|
-
gemspec_text[/\brequired_ruby_version\s*[:=]\s*["'](?:>=\s*)?([0-9]+\.[0-9]+(?:\.[0-9]+)?)["']/i, 1] ||
|
373
|
-
""
|
374
|
-
).strip
|
375
|
-
homepage_line = gemspec_text.lines.find { |l| l =~ /\bspec\.homepage\s*=\s*/ }
|
376
|
-
homepage_val = homepage_line ? homepage_line.split("=", 2).last.to_s.strip : ""
|
377
|
-
if (homepage_val.start_with?("\"") && homepage_val.end_with?("\"")) || (homepage_val.start_with?("'") && homepage_val.end_with?("'"))
|
378
|
-
homepage_val = begin
|
379
|
-
homepage_val[1..-2]
|
380
|
-
rescue
|
381
|
-
homepage_val
|
382
|
-
end
|
383
|
-
end
|
384
|
-
gh_match = homepage_val&.match(%r{github\.com/([^/]+)/([^/]+)}i)
|
385
|
-
forge_org = gh_match && gh_match[1]
|
386
|
-
gh_repo = gh_match && gh_match[2]&.sub(/\.git\z/, "")
|
387
|
-
if forge_org.nil?
|
388
|
-
begin
|
389
|
-
origin_out = IO.popen(["git", "-C", root.to_s, "remote", "get-url", "origin"], &:read)
|
390
|
-
origin_out = origin_out.read if origin_out.respond_to?(:read)
|
391
|
-
origin_url = origin_out.to_s.strip
|
392
|
-
if (m = origin_url.match(%r{github\.com[/:]([^/]+)/([^/]+)}i))
|
393
|
-
forge_org = m[1]
|
394
|
-
gh_repo = m[2]&.sub(/\.git\z/, "")
|
395
|
-
end
|
396
|
-
rescue StandardError
|
397
|
-
# ignore
|
398
|
-
end
|
399
|
-
end
|
400
|
-
|
401
|
-
camel = lambda do |s|
|
402
|
-
s.split(/[_-]/).map { |p| p.gsub(/\b([a-z])/) { Regexp.last_match(1).upcase } }.join
|
403
|
-
end
|
404
|
-
namespace = gem_name.to_s.split("-").map { |seg| camel.call(seg) }.join("::")
|
405
|
-
namespace_shield = namespace.gsub("::", "%3A%3A")
|
406
|
-
entrypoint_require = gem_name.to_s.tr("-", "/")
|
407
|
-
gem_shield = gem_name.to_s.gsub("-", "--").gsub("_", "__")
|
408
|
-
|
409
|
-
# Determine funding_org independently of forge_org (GitHub org)
|
410
|
-
funding_org = ENV["FUNDING_ORG"].to_s.strip
|
411
|
-
funding_org = ENV["OPENCOLLECTIVE_ORG"].to_s.strip if funding_org.empty?
|
412
|
-
funding_org = ENV["OPENCOLLECTIVE_HANDLE"].to_s.strip if funding_org.empty?
|
413
|
-
if funding_org.empty?
|
414
|
-
begin
|
415
|
-
oc_path = File.join(root.to_s, ".opencollective.yml")
|
416
|
-
if File.file?(oc_path)
|
417
|
-
txt = File.read(oc_path)
|
418
|
-
if (m = txt.match(/\borg:\s*([\w\-]+)/i))
|
419
|
-
funding_org = m[1].to_s
|
420
|
-
end
|
421
|
-
end
|
422
|
-
rescue StandardError
|
423
|
-
# ignore
|
424
|
-
end
|
425
|
-
end
|
426
|
-
funding_org = forge_org.to_s if funding_org.to_s.empty?
|
427
|
-
|
428
|
-
{
|
429
|
-
gemspec_path: gemspec_path,
|
430
|
-
gem_name: gem_name,
|
431
|
-
min_ruby: min_ruby,
|
432
|
-
homepage: homepage_val,
|
433
|
-
gh_org: forge_org, # Backward compat: keep old key synonymous with forge_org
|
434
|
-
forge_org: forge_org,
|
435
|
-
funding_org: funding_org,
|
436
|
-
gh_repo: gh_repo,
|
437
|
-
namespace: namespace,
|
438
|
-
namespace_shield: namespace_shield,
|
439
|
-
entrypoint_require: entrypoint_require,
|
440
|
-
gem_shield: gem_shield,
|
441
|
-
}
|
365
|
+
Kettle::Dev::GemSpecReader.load(root)
|
442
366
|
end
|
443
367
|
end
|
444
368
|
end
|
data/lib/kettle/dev/version.rb
CHANGED
data/lib/kettle/dev.rb
CHANGED
@@ -114,6 +114,7 @@ module Kettle
|
|
114
114
|
module Dev
|
115
115
|
autoload :CIHelpers, "kettle/dev/ci_helpers"
|
116
116
|
autoload :CommitMsg, "kettle/dev/commit_msg"
|
117
|
+
autoload :GemSpecReader, "kettle/dev/gem_spec_reader"
|
117
118
|
autoload :GitCommitFooter, "kettle/dev/git_commit_footer"
|
118
119
|
autoload :ReadmeBackers, "kettle/dev/readme_backers"
|
119
120
|
autoload :ReleaseCLI, "kettle/dev/release_cli"
|
data/lib/kettle/emoji_regex.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
# because that project is Ruby >= 2.4, and this project is Ruby >= 2.3.
|
4
4
|
# That project is under the MIT license, same as this project:
|
5
5
|
# https://github.com/ticky/ruby-emoji-regex/blob/develop/LICENSE.md
|
6
|
-
# If the
|
6
|
+
# If the required_ruby_version numbers align, will switch to a real dependency.
|
7
7
|
# Wrapping it in a namespace to avoid collisions with the real emoji_regex.
|
8
8
|
module Kettle
|
9
9
|
module EmojiRegex
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Kettle
|
2
|
+
module Dev
|
3
|
+
class GemSpecReader
|
4
|
+
def self.load: (String root) -> {
|
5
|
+
gemspec_path: String?,
|
6
|
+
gem_name: String,
|
7
|
+
min_ruby: String,
|
8
|
+
homepage: String,
|
9
|
+
gh_org: String?,
|
10
|
+
forge_org: String?,
|
11
|
+
funding_org: String?,
|
12
|
+
gh_repo: String?,
|
13
|
+
namespace: String,
|
14
|
+
namespace_shield: String,
|
15
|
+
entrypoint_require: String,
|
16
|
+
gem_shield: String,
|
17
|
+
authors: Array[String],
|
18
|
+
email: Array[String],
|
19
|
+
summary: String,
|
20
|
+
description: String,
|
21
|
+
license: String,
|
22
|
+
licenses: Array[String],
|
23
|
+
required_ruby_version: String,
|
24
|
+
require_paths: Array[String],
|
25
|
+
bindir: String,
|
26
|
+
executables: Array[String],
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -66,6 +66,16 @@ module Kettle
|
|
66
66
|
namespace_shield: String,
|
67
67
|
entrypoint_require: String,
|
68
68
|
gem_shield: String,
|
69
|
+
authors: Array[String],
|
70
|
+
email: Array[String],
|
71
|
+
summary: String,
|
72
|
+
description: String,
|
73
|
+
license: String,
|
74
|
+
licenses: Array[String],
|
75
|
+
required_ruby_version: String,
|
76
|
+
require_paths: Array[String],
|
77
|
+
bindir: String,
|
78
|
+
executables: Array[String],
|
69
79
|
}
|
70
80
|
end
|
71
81
|
end
|
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.0.
|
4
|
+
version: 1.0.23
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter H. Boling
|
@@ -219,6 +219,7 @@ extra_rdoc_files:
|
|
219
219
|
- CITATION.cff
|
220
220
|
- CODE_OF_CONDUCT.md
|
221
221
|
- CONTRIBUTING.md
|
222
|
+
- FUNDING.md
|
222
223
|
- LICENSE.txt
|
223
224
|
- README.md
|
224
225
|
- REEK
|
@@ -243,6 +244,7 @@ files:
|
|
243
244
|
- ".github/workflows/dependency-review.yml"
|
244
245
|
- ".github/workflows/discord-notifier.yml"
|
245
246
|
- ".github/workflows/heads.yml"
|
247
|
+
- ".github/workflows/heads.yml.example"
|
246
248
|
- ".github/workflows/jruby.yml"
|
247
249
|
- ".github/workflows/jruby.yml.example"
|
248
250
|
- ".github/workflows/legacy.yml"
|
@@ -272,6 +274,7 @@ files:
|
|
272
274
|
- CITATION.cff
|
273
275
|
- CODE_OF_CONDUCT.md
|
274
276
|
- CONTRIBUTING.md
|
277
|
+
- FUNDING.md
|
275
278
|
- Gemfile
|
276
279
|
- Gemfile.example
|
277
280
|
- LICENSE.txt
|
@@ -298,6 +301,7 @@ files:
|
|
298
301
|
- lib/kettle/dev/ci_monitor.rb
|
299
302
|
- lib/kettle/dev/commit_msg.rb
|
300
303
|
- lib/kettle/dev/exit_adapter.rb
|
304
|
+
- lib/kettle/dev/gem_spec_reader.rb
|
301
305
|
- lib/kettle/dev/git_adapter.rb
|
302
306
|
- lib/kettle/dev/git_commit_footer.rb
|
303
307
|
- lib/kettle/dev/input_adapter.rb
|
@@ -328,6 +332,7 @@ files:
|
|
328
332
|
- sig/kettle/dev/ci_monitor.rbs
|
329
333
|
- sig/kettle/dev/commit_msg.rbs
|
330
334
|
- sig/kettle/dev/exit_adapter.rbs
|
335
|
+
- sig/kettle/dev/gem_spec_reader.rbs
|
331
336
|
- sig/kettle/dev/git_adapter.rbs
|
332
337
|
- sig/kettle/dev/git_commit_footer.rbs
|
333
338
|
- sig/kettle/dev/input_adapter.rbs
|
@@ -345,10 +350,10 @@ licenses:
|
|
345
350
|
- MIT
|
346
351
|
metadata:
|
347
352
|
homepage_uri: https://kettle-dev.galtzo.com/
|
348
|
-
source_code_uri: https://github.com/kettle-rb/kettle-dev/tree/v1.0.
|
349
|
-
changelog_uri: https://github.com/kettle-rb/kettle-dev/blob/v1.0.
|
353
|
+
source_code_uri: https://github.com/kettle-rb/kettle-dev/tree/v1.0.23
|
354
|
+
changelog_uri: https://github.com/kettle-rb/kettle-dev/blob/v1.0.23/CHANGELOG.md
|
350
355
|
bug_tracker_uri: https://github.com/kettle-rb/kettle-dev/issues
|
351
|
-
documentation_uri: https://www.rubydoc.info/gems/kettle-dev/1.0.
|
356
|
+
documentation_uri: https://www.rubydoc.info/gems/kettle-dev/1.0.23
|
352
357
|
funding_uri: https://github.com/sponsors/pboling
|
353
358
|
wiki_uri: https://github.com/kettle-rb/kettle-dev/wiki
|
354
359
|
news_uri: https://www.railsbling.com/tags/kettle-dev
|
metadata.gz.sig
CHANGED
Binary file
|