kettle-dev 1.1.18 → 1.1.20
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/license-eye.yml +40 -0
- data/.licenserc.yaml +7 -0
- data/Appraisals.example +2 -0
- data/CHANGELOG.md +32 -1
- data/README.md +10 -3
- data/README.md.example +8 -4
- data/Rakefile.example +1 -1
- data/exe/kettle-dev-setup +1 -0
- data/kettle-dev.gemspec.example +8 -5
- data/lib/kettle/dev/changelog_cli.rb +84 -3
- data/lib/kettle/dev/gem_spec_reader.rb +14 -8
- data/lib/kettle/dev/setup_cli.rb +1 -0
- data/lib/kettle/dev/tasks/template_task.rb +214 -18
- data/lib/kettle/dev/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +7 -5
- metadata.gz.sig +0 -0
- /data/.github/workflows/{discord-notifier.yml → discord-notifier.yml.example} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 898754550e179a5b5757c58d45a2dd50a61de0334051ab4947769cc4a33c6624
|
4
|
+
data.tar.gz: f2b3cb209b23f9074086cb22e52e674e2b0ba84788241b2222bdca9bf26d5699
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 73108e8b6bc65bd2b11e04b0a0cb20ac2fa0f7c5f3b83533c469ece206af419e1c1033bb61253815e1c98b84f21122176825e16abbb2121478c6154647812d33
|
7
|
+
data.tar.gz: 53cf04abaea992d6a6c4047e7be8292c4eb8d452614755aeb368b37d7d8f950bc42271556a39b873cf683950f49db3325b5a2245cb4687f07776044f4f562a78
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
@@ -0,0 +1,40 @@
|
|
1
|
+
name: Apache SkyWalking Eyes
|
2
|
+
|
3
|
+
permissions:
|
4
|
+
contents: read
|
5
|
+
|
6
|
+
on:
|
7
|
+
push:
|
8
|
+
branches:
|
9
|
+
- 'main'
|
10
|
+
- '*-stable'
|
11
|
+
tags:
|
12
|
+
- '!*' # Do not execute on tags
|
13
|
+
pull_request:
|
14
|
+
branches:
|
15
|
+
- '*'
|
16
|
+
# Allow manually triggering the workflow.
|
17
|
+
workflow_dispatch:
|
18
|
+
|
19
|
+
# Cancels all previous workflow runs for the same branch that have not yet completed.
|
20
|
+
concurrency:
|
21
|
+
# The concurrency group contains the workflow name and the branch name.
|
22
|
+
group: "${{ github.workflow }}-${{ github.ref }}"
|
23
|
+
cancel-in-progress: true
|
24
|
+
|
25
|
+
jobs:
|
26
|
+
license-check:
|
27
|
+
if: "!contains(github.event.commits[0].message, '[ci skip]') && !contains(github.event.commits[0].message, '[skip ci]')"
|
28
|
+
runs-on: ubuntu-latest
|
29
|
+
steps:
|
30
|
+
- name: Checkout
|
31
|
+
uses: actions/checkout@v5
|
32
|
+
|
33
|
+
- name: Check Dependencies' License
|
34
|
+
uses: apache/skywalking-eyes/dependency@main
|
35
|
+
with:
|
36
|
+
config: .licenserc.yaml
|
37
|
+
# Ruby packages declared as dependencies in gemspecs or Gemfiles are
|
38
|
+
# typically consumed as binaries; enable weak-compatibility
|
39
|
+
# so permissive and weak-copyleft combinations are treated as compatible.
|
40
|
+
flags: --weak-compatible
|
data/.licenserc.yaml
ADDED
data/Appraisals.example
CHANGED
@@ -30,6 +30,8 @@ end
|
|
30
30
|
# Used for head (nightly) releases of ruby, truffleruby, and jruby.
|
31
31
|
# Split into discrete appraisals if one of them needs a dependency locked discretely.
|
32
32
|
appraise "head" do
|
33
|
+
# Why is gem "cgi" here? See: https://github.com/vcr/vcr/issues/1057
|
34
|
+
# gem "cgi", ">= 0.5"
|
33
35
|
gem "benchmark", "~> 0.4", ">= 0.4.1"
|
34
36
|
eval_gemfile "modular/x_std_libs.gemfile"
|
35
37
|
end
|
data/CHANGELOG.md
CHANGED
@@ -24,6 +24,33 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
24
24
|
### Fixed
|
25
25
|
### Security
|
26
26
|
|
27
|
+
## [1.1.20] - 2025-09-15
|
28
|
+
- TAG: [v1.1.20][1.1.20t]
|
29
|
+
- COVERAGE: 96.80% -- 3660/3781 lines in 25 files
|
30
|
+
- BRANCH COVERAGE: 81.65% -- 1504/1842 branches in 25 files
|
31
|
+
- 77.01% documented
|
32
|
+
### Added
|
33
|
+
- Allow reformating of CHANGELOG.md without version bump
|
34
|
+
- `--include=GLOB` includes files not otherwise included in default template
|
35
|
+
- more test coverage
|
36
|
+
### Fixed
|
37
|
+
- Add .licenserc.yaml to gem package
|
38
|
+
- Handling of GFM fenced code blocks in CHANGELOG.md
|
39
|
+
- Handling of nested list items in CHANGELOG.md
|
40
|
+
- Handling of blank lines around all headings in CHANGELOG.md
|
41
|
+
|
42
|
+
## [1.1.19] - 2025-09-14
|
43
|
+
- TAG: [v1.1.19][1.1.19t]
|
44
|
+
- COVERAGE: 96.58% -- 3531/3656 lines in 25 files
|
45
|
+
- BRANCH COVERAGE: 81.11% -- 1443/1779 branches in 25 files
|
46
|
+
- 76.88% documented
|
47
|
+
### Added
|
48
|
+
- documentation of vcr on Ruby 2.4
|
49
|
+
- Apache SkyWalking Eyes dependency license check
|
50
|
+
- Added to template
|
51
|
+
### Fixed
|
52
|
+
- fix duplicate headings in CHANGELOG.md Unreleased section
|
53
|
+
|
27
54
|
## [1.1.18] - 2025-09-12
|
28
55
|
- TAG: [v1.1.18][1.1.18t]
|
29
56
|
- COVERAGE: 96.24% -- 3477/3613 lines in 25 files
|
@@ -648,7 +675,11 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
648
675
|
- Selecting will run the selected workflow via `act`
|
649
676
|
- This may move to its own gem in the future.
|
650
677
|
|
651
|
-
[Unreleased]: https://github.com/kettle-rb/kettle-dev/compare/v1.1.
|
678
|
+
[Unreleased]: https://github.com/kettle-rb/kettle-dev/compare/v1.1.20...HEAD
|
679
|
+
[1.1.20]: https://github.com/kettle-rb/kettle-dev/compare/v1.1.19...v1.1.20
|
680
|
+
[1.1.20t]: https://github.com/kettle-rb/kettle-dev/releases/tag/v1.1.20
|
681
|
+
[1.1.19]: https://github.com/kettle-rb/kettle-dev/compare/v1.1.18...v1.1.19
|
682
|
+
[1.1.19t]: https://github.com/kettle-rb/kettle-dev/releases/tag/v1.1.19
|
652
683
|
[1.1.18]: https://github.com/kettle-rb/kettle-dev/compare/v1.1.17...v1.1.18
|
653
684
|
[1.1.18t]: https://github.com/kettle-rb/kettle-dev/releases/tag/v1.1.18
|
654
685
|
[1.1.17]: https://github.com/kettle-rb/kettle-dev/compare/v1.1.16...v1.1.17
|
data/README.md
CHANGED
@@ -9,7 +9,7 @@
|
|
9
9
|
|
10
10
|
# 🍲 Kettle::Dev
|
11
11
|
|
12
|
-
[![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]
|
12
|
+
[![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]
|
13
13
|
|
14
14
|
`if ci_badges.map(&:color).detect { it != "green"}` ☝️ [let me know][🖼️galtzo-discord], as I may have missed the [discord notification][🖼️galtzo-discord].
|
15
15
|
|
@@ -62,7 +62,7 @@ bin/kettle-release
|
|
62
62
|
| 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] |
|
63
63
|
| 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] |
|
64
64
|
| 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] [![Wiki][📜wiki-img]][📜wiki] |
|
65
|
-
| Compliance | [![License: MIT][📄license-img]][📄license-ref] [![📄ilo-declaration-img]][📄ilo-declaration] [![Security Policy][🔐security-img]][🔐security] [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct] [![SemVer 2.0.0][📌semver-img]][📌semver]
|
65
|
+
| 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] |
|
66
66
|
| 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] |
|
67
67
|
| 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] |
|
68
68
|
| `...` 💖 | [![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] |
|
@@ -241,10 +241,12 @@ That’s it. Once installed, kettle-dev:
|
|
241
241
|
- 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`
|
242
242
|
- 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`
|
243
243
|
- 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"`.
|
244
|
+
- 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"`).
|
244
245
|
- `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.
|
245
246
|
- 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`
|
246
247
|
- 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`
|
247
248
|
- option: only: Same as for install; limits which destination files are written based on glob patterns relative to the project root.
|
249
|
+
- option: include: Same as for install; opts into optional files (e.g., `.github/workflows/discord-notifier.yml`).
|
248
250
|
|
249
251
|
Recommended one-time setup in your project:
|
250
252
|
- Install binstubs so kettle-dev executables are available under `./bin`:
|
@@ -506,6 +508,7 @@ What it does:
|
|
506
508
|
- `--force` Pass `force=true` to accept prompts non-interactively.
|
507
509
|
- `--hook_templates=VAL` Pass `hook_templates=VAL` to control git hook templating.
|
508
510
|
- `--only=VAL` Pass `only=VAL` to restrict install scope.
|
511
|
+
- `--include=VAL` Pass `include=VAL` to include optional files by glob (see notes below).
|
509
512
|
- `-h`, `--help` Show help.
|
510
513
|
- Behavior:
|
511
514
|
- Verifies a clean git working tree, presence of a Gemfile and a gemspec.
|
@@ -861,6 +864,8 @@ Thanks for RTFM. ☺️
|
|
861
864
|
[🚎13-🔒️-wfi]: https://github.com/kettle-rb/kettle-dev/actions/workflows/locked_deps.yml/badge.svg
|
862
865
|
[🚎14-🔓️-wf]: https://github.com/kettle-rb/kettle-dev/actions/workflows/unlocked_deps.yml
|
863
866
|
[🚎14-🔓️-wfi]: https://github.com/kettle-rb/kettle-dev/actions/workflows/unlocked_deps.yml/badge.svg
|
867
|
+
[🚎15-🪪-wf]: https://github.com/kettle-rb/kettle-dev/actions/workflows/license-eye.yml
|
868
|
+
[🚎15-🪪-wfi]: https://github.com/kettle-rb/kettle-dev/actions/workflows/license-eye.yml/badge.svg
|
864
869
|
[💎ruby-2.3i]: https://img.shields.io/badge/Ruby-2.3-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
|
865
870
|
[💎ruby-2.4i]: https://img.shields.io/badge/Ruby-2.4-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
|
866
871
|
[💎ruby-2.5i]: https://img.shields.io/badge/Ruby-2.5-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
|
@@ -909,13 +914,15 @@ Thanks for RTFM. ☺️
|
|
909
914
|
[📌gitmoji]:https://gitmoji.dev
|
910
915
|
[📌gitmoji-img]:https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
911
916
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
912
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-3.
|
917
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-3.781-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
913
918
|
[🔐security]: SECURITY.md
|
914
919
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
915
920
|
[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
|
916
921
|
[📄license]: LICENSE.txt
|
917
922
|
[📄license-ref]: https://opensource.org/licenses/MIT
|
918
923
|
[📄license-img]: https://img.shields.io/badge/License-MIT-259D6C.svg
|
924
|
+
[📄license-compat]: https://dev.to/galtzo/how-to-check-license-compatibility-41h0
|
925
|
+
[📄license-compat-img]: https://img.shields.io/badge/Apache_Compatible:_Category_A-%E2%9C%93-259D6C.svg?style=flat&logo=Apache
|
919
926
|
[📄ilo-declaration]: https://www.ilo.org/declaration/lang--en/index.htm
|
920
927
|
[📄ilo-declaration-img]: https://img.shields.io/badge/ILO_Fundamental_Principles-✓-259D6C.svg?style=flat
|
921
928
|
[🚎yard-current]: http://rubydoc.info/gems/kettle-dev
|
data/README.md.example
CHANGED
@@ -9,7 +9,7 @@
|
|
9
9
|
|
10
10
|
# 🍲 Kettle::Dev
|
11
11
|
|
12
|
-
[![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]
|
12
|
+
[![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]
|
13
13
|
|
14
14
|
`if ci_badges.map(&:color).detect { it != "green"}` ☝️ [let me know][🖼️galtzo-discord], as I may have missed the [discord notification][🖼️galtzo-discord].
|
15
15
|
|
@@ -31,10 +31,10 @@
|
|
31
31
|
| 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] |
|
32
32
|
| Works with MRI Ruby 2 | ![Ruby 2.0 Compat][💎ruby-2.0i] ![Ruby 2.1 Compat][💎ruby-2.1i] ![Ruby 2.2 Compat][💎ruby-2.2i] <br/> [![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] |
|
33
33
|
| Works with MRI Ruby 1 | ![Ruby 1.8 Compat][💎ruby-1.8i] ![Ruby 1.9 Compat][💎ruby-1.9i] |
|
34
|
-
| Support
|
34
|
+
| 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] |
|
35
35
|
| 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] |
|
36
36
|
| 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] [![Wiki][📜wiki-img]][📜wiki] |
|
37
|
-
| Compliance | [![License: MIT][📄license-img]][📄license-ref] [![📄ilo-declaration-img]][📄ilo-declaration] [![Security Policy][🔐security-img]][🔐security] [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct] [![SemVer 2.0.0][📌semver-img]][📌semver] |
|
37
|
+
| 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] |
|
38
38
|
| 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] |
|
39
39
|
| 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] |
|
40
40
|
| `...` 💖 | [![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] |
|
@@ -456,6 +456,8 @@ Thanks for RTFM. ☺️
|
|
456
456
|
[🚎13-🔒️-wfi]: https://github.com/kettle-rb/kettle-dev/actions/workflows/locked_deps.yml/badge.svg
|
457
457
|
[🚎14-🔓️-wf]: https://github.com/kettle-rb/kettle-dev/actions/workflows/unlocked_deps.yml
|
458
458
|
[🚎14-🔓️-wfi]: https://github.com/kettle-rb/kettle-dev/actions/workflows/unlocked_deps.yml/badge.svg
|
459
|
+
[🚎15-🪪-wf]: https://github.com/kettle-rb/kettle-dev/actions/workflows/license-eye.yml
|
460
|
+
[🚎15-🪪-wfi]: https://github.com/kettle-rb/kettle-dev/actions/workflows/license-eye.yml/badge.svg
|
459
461
|
[💎ruby-1.8i]: https://img.shields.io/badge/Ruby-1.8_(%F0%9F%9A%ABCI)-AABBCC?style=for-the-badge&logo=ruby&logoColor=white
|
460
462
|
[💎ruby-1.9i]: https://img.shields.io/badge/Ruby-1.9_(%F0%9F%9A%ABCI)-AABBCC?style=for-the-badge&logo=ruby&logoColor=white
|
461
463
|
[💎ruby-2.0i]: https://img.shields.io/badge/Ruby-2.0_(%F0%9F%9A%ABCI)-AABBCC?style=for-the-badge&logo=ruby&logoColor=white
|
@@ -509,13 +511,15 @@ Thanks for RTFM. ☺️
|
|
509
511
|
[📌gitmoji]:https://gitmoji.dev
|
510
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
513
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
512
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-3.
|
514
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-3.781-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
513
515
|
[🔐security]: SECURITY.md
|
514
516
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
515
517
|
[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
|
516
518
|
[📄license]: LICENSE.txt
|
517
519
|
[📄license-ref]: https://opensource.org/licenses/MIT
|
518
520
|
[📄license-img]: https://img.shields.io/badge/License-MIT-259D6C.svg
|
521
|
+
[📄license-compat]: https://dev.to/galtzo/how-to-check-license-compatibility-41h0
|
522
|
+
[📄license-compat-img]: https://img.shields.io/badge/Apache_Compatible:_Category_A-%E2%9C%93-259D6C.svg?style=flat&logo=Apache
|
519
523
|
[📄ilo-declaration]: https://www.ilo.org/declaration/lang--en/index.htm
|
520
524
|
[📄ilo-declaration-img]: https://img.shields.io/badge/ILO_Fundamental_Principles-✓-259D6C.svg?style=flat
|
521
525
|
[🚎yard-current]: http://rubydoc.info/gems/kettle-dev
|
data/Rakefile.example
CHANGED
data/exe/kettle-dev-setup
CHANGED
data/kettle-dev.gemspec.example
CHANGED
@@ -149,9 +149,7 @@ Gem::Specification.new do |spec|
|
|
149
149
|
spec.add_development_dependency("gitmoji-regex", "~> 1.0", ">= 1.0.3") # ruby >= 2.3.0
|
150
150
|
|
151
151
|
# HTTP recording for deterministic specs
|
152
|
-
#
|
153
|
-
# Ruby 2.3 and 2.4 even if their bundle specifies an older version,
|
154
|
-
# and as a result it can only be a dependency in the appraisals.
|
152
|
+
# Ruby 2.3 / 2.4 can fail with:
|
155
153
|
# | An error occurred while loading spec_helper.
|
156
154
|
# | Failure/Error: require "vcr"
|
157
155
|
# |
|
@@ -161,6 +159,11 @@ Gem::Specification.new do |spec|
|
|
161
159
|
# | # ./spec/config/vcr.rb:3:in `<top (required)>'
|
162
160
|
# | # ./spec/spec_helper.rb:8:in `require_relative'
|
163
161
|
# | # ./spec/spec_helper.rb:8:in `<top (required)>'
|
164
|
-
#
|
165
|
-
# spec.add_development_dependency("
|
162
|
+
# So that's why we need backports.
|
163
|
+
# spec.add_development_dependency("backports", "~> 3.25", ">= 3.25.1") # ruby >= 0
|
164
|
+
# In Ruby 3.5 (HEAD) the CGI library has been pared down, so we also need to depend on gem "cgi" for ruby@head
|
165
|
+
# This is done in the "head" appraisal.
|
166
|
+
# See: https://github.com/vcr/vcr/issues/1057
|
167
|
+
# spec.add_development_dependency("vcr", ">= 4") # 6.0 claims to support ruby >= 2.3, but fails on ruby 2.4
|
168
|
+
# spec.add_development_dependency("webmock", ">= 3") # Last version to support ruby >= 2.3
|
166
169
|
end
|
@@ -24,9 +24,22 @@ module Kettle
|
|
24
24
|
|
25
25
|
changelog = File.read(@changelog_path)
|
26
26
|
|
27
|
-
# If the detected version already exists in the changelog,
|
27
|
+
# If the detected version already exists in the changelog, offer reformat-only mode
|
28
28
|
if changelog =~ /^## \[#{Regexp.escape(version)}\]/
|
29
|
-
|
29
|
+
warn("CHANGELOG.md already has a section for version #{version}.")
|
30
|
+
warn("It appears the version has not been bumped. You can reformat CHANGELOG.md without adding a new release section.")
|
31
|
+
print("Proceed with reformat only? [y/N]: ")
|
32
|
+
ans = Kettle::Dev::InputAdapter.gets&.strip&.downcase
|
33
|
+
if ans == "y" || ans == "yes"
|
34
|
+
updated = normalize_heading_spacing(changelog)
|
35
|
+
updated = ensure_footer_spacing(updated)
|
36
|
+
updated = updated.rstrip + "\n"
|
37
|
+
File.write(@changelog_path, updated)
|
38
|
+
puts "CHANGELOG.md reformatted. No new version section added."
|
39
|
+
return
|
40
|
+
else
|
41
|
+
abort("Aborting: version not bumped. Re-run after bumping version or answer 'y' to reformat-only.")
|
42
|
+
end
|
30
43
|
end
|
31
44
|
|
32
45
|
unreleased_block, before, after = extract_unreleased(changelog)
|
@@ -86,6 +99,9 @@ module Kettle
|
|
86
99
|
|
87
100
|
updated = update_link_refs(updated, owner, repo, prev_version, version)
|
88
101
|
|
102
|
+
# Normalize spacing around headings to aid Markdown renderers
|
103
|
+
updated = normalize_heading_spacing(updated)
|
104
|
+
|
89
105
|
# Ensure exactly one trailing newline at EOF
|
90
106
|
updated = updated.rstrip + "\n"
|
91
107
|
|
@@ -160,6 +176,10 @@ module Kettle
|
|
160
176
|
# Determine if chunk has any content (non-blank)
|
161
177
|
content_present = chunk.any? { |l| l.strip != "" }
|
162
178
|
if content_present
|
179
|
+
# Trim leading blank lines so there is no blank line after the header
|
180
|
+
while chunk.any? && chunk.first.strip == ""
|
181
|
+
chunk.shift
|
182
|
+
end
|
163
183
|
# Trim trailing blank lines
|
164
184
|
while chunk.any? && chunk.last.strip == ""
|
165
185
|
chunk.pop
|
@@ -336,10 +356,71 @@ module Kettle
|
|
336
356
|
new_ref_block << tags[v] if tags[v]
|
337
357
|
end
|
338
358
|
# Replace the old block
|
339
|
-
|
359
|
+
head = lines[0...first_ref]
|
360
|
+
# Ensure exactly one blank line separating body content from the reference block
|
361
|
+
if head.any? && head.last.to_s.strip != ""
|
362
|
+
head << "\n"
|
363
|
+
end
|
364
|
+
rebuilt = head + new_ref_block + ["\n"]
|
340
365
|
rebuilt.join
|
341
366
|
end
|
342
367
|
|
368
|
+
# Ensure every Markdown atx-style heading line (e.g., "# ", "## ") has exactly one blank line
|
369
|
+
# before and after it, skipping content inside fenced code blocks.
|
370
|
+
def normalize_heading_spacing(text)
|
371
|
+
lines = text.split("\n", -1)
|
372
|
+
out = []
|
373
|
+
in_fence = false
|
374
|
+
fence_re = /^\s*```/
|
375
|
+
heading_re = /^\s*#+\s+.+/
|
376
|
+
lines.each_with_index do |ln, idx|
|
377
|
+
if ln =~ fence_re
|
378
|
+
in_fence = !in_fence
|
379
|
+
out << ln
|
380
|
+
next
|
381
|
+
end
|
382
|
+
if !in_fence && ln =~ heading_re
|
383
|
+
# Ensure previous line is blank (unless start of file or already blank)
|
384
|
+
prev_blank = out.empty? ? false : out.last.to_s.strip == ""
|
385
|
+
out << "" unless out.empty? || prev_blank
|
386
|
+
out << ln
|
387
|
+
# Peek at next line in source to decide if we need to inject a blank now.
|
388
|
+
nxt = lines[idx + 1]
|
389
|
+
out << "" unless nxt.to_s.strip == ""
|
390
|
+
else
|
391
|
+
out << ln
|
392
|
+
end
|
393
|
+
end
|
394
|
+
# Collapse multiple consecutive blank lines down to a single between regions that our logic might have doubled
|
395
|
+
collapsed = []
|
396
|
+
lines_enum = out
|
397
|
+
lines_enum.each do |l|
|
398
|
+
if l.strip == "" && collapsed.last.to_s.strip == ""
|
399
|
+
next
|
400
|
+
end
|
401
|
+
collapsed << l
|
402
|
+
end
|
403
|
+
collapsed.join("\n")
|
404
|
+
end
|
405
|
+
|
406
|
+
def ensure_footer_spacing(text)
|
407
|
+
lines = text.split("\n", -1)
|
408
|
+
# Find the Unreleased link-ref which denotes start of footer refs
|
409
|
+
idx = lines.index { |l| l.start_with?(UNRELEASED_SECTION_HEADING) }
|
410
|
+
return text unless idx
|
411
|
+
head = lines[0...idx]
|
412
|
+
tail = lines[idx..-1]
|
413
|
+
# Ensure exactly one blank line between body and refs
|
414
|
+
if head.any? && head.last.to_s.strip != ""
|
415
|
+
head << ""
|
416
|
+
elsif head.any? && head.last.to_s.strip == "" && head[-2].to_s.strip == ""
|
417
|
+
# Collapse multiple blanks before footer to a single
|
418
|
+
head.pop while head.any? && head.last.to_s.strip == ""
|
419
|
+
head << ""
|
420
|
+
end
|
421
|
+
(head + tail).join("\n")
|
422
|
+
end
|
423
|
+
|
343
424
|
def detect_initial_compare_base(lines)
|
344
425
|
# Fallback when prev_version is unknown: try to find the first compare base used historically
|
345
426
|
# e.g., for 1.0.0 it may be a commit SHA instead of a tag
|
@@ -106,16 +106,22 @@ module Kettle
|
|
106
106
|
if funding_org_env && funding_org_env.to_s.strip.casecmp("false").zero?
|
107
107
|
funding_org = nil
|
108
108
|
else
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
109
|
+
# Prefer .opencollective.yml when present so that specs forcing the file path are stable
|
110
|
+
oc_path = File.join(root.to_s, ".opencollective.yml")
|
111
|
+
if File.file?(oc_path)
|
112
|
+
txt = File.read(oc_path)
|
113
|
+
funding_org = if (m = txt.match(/\borg:\s*([\w\-]+)/i))
|
114
|
+
m[1].to_s
|
115
|
+
else
|
116
|
+
""
|
117
117
|
end
|
118
118
|
end
|
119
|
+
|
120
|
+
# Fallback to ENV when file not present or did not contain an org
|
121
|
+
if funding_org.to_s.strip.empty?
|
122
|
+
funding_org = ENV["OPENCOLLECTIVE_HANDLE"].to_s.strip if funding_org.empty?
|
123
|
+
end
|
124
|
+
|
119
125
|
# Be lenient: if funding_org cannot be determined, do not raise — leave it nil and warn.
|
120
126
|
if funding_org.to_s.empty?
|
121
127
|
Kernel.warn("kettle-dev: Could not determine funding org.\n - Options:\n * Set ENV['FUNDING_ORG'] to your funding handle (e.g., 'opencollective-handle').\n * Or set ENV['OPENCOLLECTIVE_HANDLE'].\n * Or add .opencollective.yml with: org: <handle>\n * Or bypass by setting ENV['FUNDING_ORG']=false for gems without funding.")
|
data/lib/kettle/dev/setup_cli.rb
CHANGED
@@ -114,6 +114,7 @@ module Kettle
|
|
114
114
|
end
|
115
115
|
opts.on("--hook_templates=VAL", "Pass through to kettle:dev:install") { |v| @passthrough << "hook_templates=#{v}" }
|
116
116
|
opts.on("--only=VAL", "Pass through to kettle:dev:install") { |v| @passthrough << "only=#{v}" }
|
117
|
+
opts.on("--include=VAL", "Pass through to kettle:dev:install") { |v| @passthrough << "include=#{v}" }
|
117
118
|
opts.on("-h", "--help", "Show help") do
|
118
119
|
puts opts
|
119
120
|
Kettle::Dev::ExitAdapter.exit(0)
|
@@ -10,6 +10,41 @@ module Kettle
|
|
10
10
|
|
11
11
|
module_function
|
12
12
|
|
13
|
+
# Ensure every Markdown atx-style heading line has exactly one blank line
|
14
|
+
# before and after, skipping content inside fenced code blocks.
|
15
|
+
def normalize_heading_spacing(text)
|
16
|
+
lines = text.split("\n", -1)
|
17
|
+
out = []
|
18
|
+
in_fence = false
|
19
|
+
fence_re = /^\s*```/
|
20
|
+
heading_re = /^\s*#+\s+.+/
|
21
|
+
lines.each_with_index do |ln, idx|
|
22
|
+
if ln =~ fence_re
|
23
|
+
in_fence = !in_fence
|
24
|
+
out << ln
|
25
|
+
next
|
26
|
+
end
|
27
|
+
if !in_fence && ln =~ heading_re
|
28
|
+
prev_blank = out.empty? ? false : out.last.to_s.strip == ""
|
29
|
+
out << "" unless out.empty? || prev_blank
|
30
|
+
out << ln
|
31
|
+
nxt = lines[idx + 1]
|
32
|
+
out << "" unless nxt.to_s.strip == ""
|
33
|
+
else
|
34
|
+
out << ln
|
35
|
+
end
|
36
|
+
end
|
37
|
+
# Collapse accidental multiple blanks
|
38
|
+
collapsed = []
|
39
|
+
out.each do |l|
|
40
|
+
if l.strip == "" && collapsed.last.to_s.strip == ""
|
41
|
+
next
|
42
|
+
end
|
43
|
+
collapsed << l
|
44
|
+
end
|
45
|
+
collapsed.join("\n")
|
46
|
+
end
|
47
|
+
|
13
48
|
# Abort wrapper that avoids terminating the entire process during specs
|
14
49
|
def task_abort(msg)
|
15
50
|
raise Kettle::Dev::Error, msg
|
@@ -57,11 +92,48 @@ module Kettle
|
|
57
92
|
selected[key] ||= path
|
58
93
|
end
|
59
94
|
end
|
95
|
+
# Parse optional include patterns (comma-separated globs relative to project root)
|
96
|
+
include_raw = ENV["include"].to_s
|
97
|
+
include_patterns = include_raw.split(",").map { |s| s.strip }.reject(&:empty?)
|
98
|
+
matches_include = lambda do |abs_dest|
|
99
|
+
return false if include_patterns.empty?
|
100
|
+
begin
|
101
|
+
rel_dest = abs_dest.to_s
|
102
|
+
proj = project_root.to_s
|
103
|
+
if rel_dest.start_with?(proj + "/")
|
104
|
+
rel_dest = rel_dest[(proj.length + 1)..-1]
|
105
|
+
elsif rel_dest == proj
|
106
|
+
rel_dest = ""
|
107
|
+
end
|
108
|
+
include_patterns.any? do |pat|
|
109
|
+
if pat.end_with?("/**")
|
110
|
+
base = pat[0..-4]
|
111
|
+
rel_dest == base || rel_dest.start_with?(base + "/")
|
112
|
+
else
|
113
|
+
File.fnmatch?(pat, rel_dest, File::FNM_PATHNAME | File::FNM_EXTGLOB | File::FNM_DOTMATCH)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
rescue StandardError => e
|
117
|
+
Kettle::Dev.debug_error(e, __method__)
|
118
|
+
false
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
60
122
|
selected.values.each do |orig_src|
|
61
123
|
src = helpers.prefer_example(orig_src)
|
62
124
|
# Destination path should never include the .example suffix.
|
63
125
|
rel = orig_src.sub(/^#{Regexp.escape(gem_checkout_root)}\/?/, "").sub(/\.example\z/, "")
|
64
126
|
dest = File.join(project_root, rel)
|
127
|
+
|
128
|
+
# Optional file: .github/workflows/discord-notifier.yml should NOT be copied by default.
|
129
|
+
# Only copy when --include matches it.
|
130
|
+
if rel == ".github/workflows/discord-notifier.yml"
|
131
|
+
unless matches_include.call(dest)
|
132
|
+
# Explicitly skip without prompting
|
133
|
+
next
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
65
137
|
if File.basename(rel) == "FUNDING.yml"
|
66
138
|
helpers.copy_file_with_prompt(src, dest, allow_create: true, allow_replace: true) do |content|
|
67
139
|
c = content.dup
|
@@ -314,6 +386,7 @@ module Kettle
|
|
314
386
|
.gitlab-ci.yml
|
315
387
|
.junie/guidelines-rbs.md
|
316
388
|
.junie/guidelines.md
|
389
|
+
.licenserc.yaml
|
317
390
|
.opencollective.yml
|
318
391
|
.rspec
|
319
392
|
.rubocop.yml
|
@@ -548,31 +621,152 @@ module Kettle
|
|
548
621
|
)
|
549
622
|
if File.basename(rel) == "CHANGELOG.md"
|
550
623
|
begin
|
551
|
-
# Special handling
|
624
|
+
# Special handling for CHANGELOG.md
|
625
|
+
# 1) Take template header through Unreleased section (inclusive)
|
552
626
|
src_lines = c.split("\n", -1)
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
j = unreleased_idx + 1
|
627
|
+
tpl_unrel_idx = src_lines.index { |ln| ln =~ /^##\s*\[\s*Unreleased\s*\]/i }
|
628
|
+
if tpl_unrel_idx
|
629
|
+
# Find end of Unreleased in template (next ## or # heading)
|
630
|
+
tpl_end_idx = src_lines.length - 1
|
631
|
+
j = tpl_unrel_idx + 1
|
559
632
|
while j < src_lines.length
|
560
633
|
if src_lines[j] =~ /^##\s+\[/ || src_lines[j] =~ /^#\s+/ || src_lines[j] =~ /^##\s+[^\[]/
|
561
|
-
|
634
|
+
tpl_end_idx = j - 1
|
562
635
|
break
|
563
636
|
end
|
564
637
|
j += 1
|
565
638
|
end
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
#
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
639
|
+
tpl_header_pre = src_lines[0...tpl_unrel_idx] # lines before Unreleased heading
|
640
|
+
tpl_unrel_heading = src_lines[tpl_unrel_idx]
|
641
|
+
src_lines[(tpl_unrel_idx + 1)..tpl_end_idx] || []
|
642
|
+
|
643
|
+
# 2) Extract destination Unreleased content, preserving list items under any standard headings
|
644
|
+
dest_content = File.file?(dest) ? File.read(dest) : ""
|
645
|
+
dest_lines = dest_content.split("\n", -1)
|
646
|
+
dest_unrel_idx = dest_lines.index { |ln| ln =~ /^##\s*\[\s*Unreleased\s*\]/i }
|
647
|
+
dest_end_idx = if dest_unrel_idx
|
648
|
+
k = dest_unrel_idx + 1
|
649
|
+
e = dest_lines.length - 1
|
650
|
+
while k < dest_lines.length
|
651
|
+
if dest_lines[k] =~ /^##\s+\[/ || dest_lines[k] =~ /^#\s+/ || dest_lines[k] =~ /^##\s+[^\[]/
|
652
|
+
e = k - 1
|
653
|
+
break
|
654
|
+
end
|
655
|
+
k += 1
|
656
|
+
end
|
657
|
+
e
|
658
|
+
end
|
659
|
+
dest_unrel_body = dest_unrel_idx ? (dest_lines[(dest_unrel_idx + 1)..dest_end_idx] || []) : []
|
660
|
+
|
661
|
+
# Helper: parse body into map of heading=>items (only '- ' markdown items)
|
662
|
+
std_heads = [
|
663
|
+
"### Added",
|
664
|
+
"### Changed",
|
665
|
+
"### Deprecated",
|
666
|
+
"### Removed",
|
667
|
+
"### Fixed",
|
668
|
+
"### Security",
|
669
|
+
]
|
670
|
+
|
671
|
+
parse_items = lambda do |body_lines|
|
672
|
+
result = {}
|
673
|
+
cur = nil
|
674
|
+
i = 0
|
675
|
+
while i < body_lines.length
|
676
|
+
ln = body_lines[i]
|
677
|
+
if ln.start_with?("### ")
|
678
|
+
cur = ln.strip
|
679
|
+
result[cur] ||= []
|
680
|
+
i += 1
|
681
|
+
next
|
682
|
+
end
|
683
|
+
|
684
|
+
# Detect a list item bullet (allow optional indentation)
|
685
|
+
if (m = ln.match(/^(\s*)[-*]\s/))
|
686
|
+
result[cur] ||= []
|
687
|
+
base_indent = m[1].length
|
688
|
+
# Start a new item: include the bullet line
|
689
|
+
result[cur] << ln.rstrip
|
690
|
+
i += 1
|
691
|
+
|
692
|
+
# Include subsequent lines that belong to this list item:
|
693
|
+
# - blank lines
|
694
|
+
# - lines with indentation greater than the bullet's indentation
|
695
|
+
# - any lines inside fenced code blocks (```), regardless of indentation until fence closes
|
696
|
+
in_fence = false
|
697
|
+
fence_re = /^\s*```/
|
698
|
+
while i < body_lines.length
|
699
|
+
l2 = body_lines[i]
|
700
|
+
# Stop if next sibling/top-level bullet of same or smaller indent and not inside a fence
|
701
|
+
if !in_fence && l2 =~ /^(\s*)[-*]\s/
|
702
|
+
ind = Regexp.last_match(1).length
|
703
|
+
break if ind <= base_indent
|
704
|
+
end
|
705
|
+
# Break if a new section heading appears and we're not in a fence
|
706
|
+
break if !in_fence && l2.start_with?("### ")
|
707
|
+
|
708
|
+
if l2 =~ fence_re
|
709
|
+
in_fence = !in_fence
|
710
|
+
result[cur] << l2.rstrip
|
711
|
+
i += 1
|
712
|
+
next
|
713
|
+
end
|
714
|
+
|
715
|
+
# Include blanks and lines indented more than base indent, or anything while in fence
|
716
|
+
if in_fence || l2.strip.empty? || (l2[/^\s*/].length > base_indent)
|
717
|
+
result[cur] << l2.rstrip
|
718
|
+
i += 1
|
719
|
+
next
|
720
|
+
end
|
721
|
+
|
722
|
+
# Otherwise, this line does not belong to the current list item
|
723
|
+
break
|
724
|
+
end
|
725
|
+
|
726
|
+
next
|
727
|
+
end
|
728
|
+
|
729
|
+
# Non-bullet, non-heading line: just advance
|
730
|
+
i += 1
|
731
|
+
end
|
732
|
+
result
|
733
|
+
end
|
734
|
+
|
735
|
+
dest_items = parse_items.call(dest_unrel_body)
|
736
|
+
|
737
|
+
# 3) Build a single canonical Unreleased section: heading + the six standard subheads in order
|
738
|
+
new_unrel_block = []
|
739
|
+
new_unrel_block << tpl_unrel_heading
|
740
|
+
std_heads.each do |h|
|
741
|
+
new_unrel_block << h
|
742
|
+
if dest_items[h] && !dest_items[h].empty?
|
743
|
+
new_unrel_block.concat(dest_items[h])
|
744
|
+
end
|
745
|
+
end
|
746
|
+
|
747
|
+
# 4) Compose final content: template preface + new unreleased + rest of destination (after its unreleased)
|
748
|
+
tail_after_unrel = []
|
749
|
+
if dest_unrel_idx
|
750
|
+
tail_after_unrel = dest_lines[(dest_end_idx + 1)..-1] || []
|
751
|
+
end
|
752
|
+
|
753
|
+
# Ensure exactly one blank line between the Unreleased chunk and the next version chunk
|
754
|
+
# - Strip trailing blanks from the newly built Unreleased block
|
755
|
+
while new_unrel_block.any? && new_unrel_block.last.to_s.strip == ""
|
756
|
+
new_unrel_block.pop
|
757
|
+
end
|
758
|
+
# - Strip leading blanks from the tail
|
759
|
+
while tail_after_unrel.any? && tail_after_unrel.first.to_s.strip == ""
|
760
|
+
tail_after_unrel.shift
|
761
|
+
end
|
762
|
+
merged_lines = tpl_header_pre + new_unrel_block
|
763
|
+
# Insert a single separator blank line if there is any tail content
|
764
|
+
merged_lines << "" if tail_after_unrel.any?
|
765
|
+
merged_lines.concat(tail_after_unrel)
|
766
|
+
|
767
|
+
c = merged_lines.join("\n")
|
575
768
|
end
|
769
|
+
|
576
770
|
# Collapse repeated whitespace in release headers only
|
577
771
|
lines = c.split("\n", -1)
|
578
772
|
lines.map! do |ln|
|
@@ -585,12 +779,14 @@ module Kettle
|
|
585
779
|
c = lines.join("\n")
|
586
780
|
rescue StandardError => e
|
587
781
|
Kettle::Dev.debug_error(e, __method__)
|
588
|
-
#
|
782
|
+
# Fallback: whitespace normalization
|
589
783
|
lines = c.split("\n", -1)
|
590
784
|
lines.map! { |ln| (ln =~ /^##\s+\[.*\]/) ? ln.gsub(/[ \t]+/, " ") : ln }
|
591
785
|
c = lines.join("\n")
|
592
786
|
end
|
593
787
|
end
|
788
|
+
# Normalize spacing around Markdown headings for broad renderer compatibility
|
789
|
+
c = normalize_heading_spacing(c)
|
594
790
|
c
|
595
791
|
end
|
596
792
|
else
|
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.20
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter H. Boling
|
@@ -235,12 +235,13 @@ files:
|
|
235
235
|
- ".github/workflows/current.yml"
|
236
236
|
- ".github/workflows/dep-heads.yml"
|
237
237
|
- ".github/workflows/dependency-review.yml"
|
238
|
-
- ".github/workflows/discord-notifier.yml"
|
238
|
+
- ".github/workflows/discord-notifier.yml.example"
|
239
239
|
- ".github/workflows/heads.yml"
|
240
240
|
- ".github/workflows/heads.yml.example"
|
241
241
|
- ".github/workflows/jruby.yml"
|
242
242
|
- ".github/workflows/jruby.yml.example"
|
243
243
|
- ".github/workflows/legacy.yml"
|
244
|
+
- ".github/workflows/license-eye.yml"
|
244
245
|
- ".github/workflows/locked_deps.yml"
|
245
246
|
- ".github/workflows/opencollective.yml"
|
246
247
|
- ".github/workflows/style.yml"
|
@@ -252,6 +253,7 @@ files:
|
|
252
253
|
- ".gitlab-ci.yml.example"
|
253
254
|
- ".junie/guidelines-rbs.md"
|
254
255
|
- ".junie/guidelines.md"
|
256
|
+
- ".licenserc.yaml"
|
255
257
|
- ".opencollective.yml"
|
256
258
|
- ".opencollective.yml.example"
|
257
259
|
- ".qlty/qlty.toml"
|
@@ -386,10 +388,10 @@ licenses:
|
|
386
388
|
- MIT
|
387
389
|
metadata:
|
388
390
|
homepage_uri: https://kettle-dev.galtzo.com/
|
389
|
-
source_code_uri: https://github.com/kettle-rb/kettle-dev/tree/v1.1.
|
390
|
-
changelog_uri: https://github.com/kettle-rb/kettle-dev/blob/v1.1.
|
391
|
+
source_code_uri: https://github.com/kettle-rb/kettle-dev/tree/v1.1.20
|
392
|
+
changelog_uri: https://github.com/kettle-rb/kettle-dev/blob/v1.1.20/CHANGELOG.md
|
391
393
|
bug_tracker_uri: https://github.com/kettle-rb/kettle-dev/issues
|
392
|
-
documentation_uri: https://www.rubydoc.info/gems/kettle-dev/1.1.
|
394
|
+
documentation_uri: https://www.rubydoc.info/gems/kettle-dev/1.1.20
|
393
395
|
funding_uri: https://github.com/sponsors/pboling
|
394
396
|
wiki_uri: https://github.com/kettle-rb/kettle-dev/wiki
|
395
397
|
news_uri: https://www.railsbling.com/tags/kettle-dev
|
metadata.gz.sig
CHANGED
Binary file
|
File without changes
|