kettle-family 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +34 -1
- data/LICENSE.md +3 -1
- data/README.md +13 -70
- data/lib/kettle/family/cli.rb +6 -5
- data/lib/kettle/family/config.rb +10 -1
- data/lib/kettle/family/discovery.rb +24 -2
- data/lib/kettle/family/member.rb +8 -2
- data/lib/kettle/family/release_state_check.rb +109 -11
- data/lib/kettle/family/release_state_result.rb +4 -2
- data/lib/kettle/family/report.rb +37 -2
- data/lib/kettle/family/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +7 -7
- 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: 2db11fe0f0487d5a8d9b7413b680997f63b65ba2e025e5b6dbeef9e2a4f0b6c8
|
|
4
|
+
data.tar.gz: fcd754360608f5791e7c3372f37cd9e8a073ce1f9a8b1c883e457740d2bf12d5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8a92079c7ba5f0b0ce6d6cae83ee1625c592270260079643e6f988b3a8e95f839173e6b70c21326eae93a3e1888c49b59f402fdbae12a295a7e903f0e1f2c790
|
|
7
|
+
data.tar.gz: 56112e0a206756aa3c9b885029d5ed5c1a555cde829ea56cfbc335df405c3c9bfa54badfc29eebf76b9be339ef55b5999c0250e4db14aa755157de3ff0de2195
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/CHANGELOG.md
CHANGED
|
@@ -30,6 +30,37 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
30
30
|
|
|
31
31
|
### Security
|
|
32
32
|
|
|
33
|
+
## [0.1.3] - 2026-06-14
|
|
34
|
+
|
|
35
|
+
- TAG: [v0.1.3][0.1.3t]
|
|
36
|
+
- COVERAGE: 94.34% -- 917/972 lines in 19 files
|
|
37
|
+
- BRANCH COVERAGE: 78.36% -- 268/342 branches in 19 files
|
|
38
|
+
- 44.00% documented
|
|
39
|
+
|
|
40
|
+
### Changed
|
|
41
|
+
|
|
42
|
+
- Runtime dependency `kettle-dev` now requires 2.2.8 or newer.
|
|
43
|
+
- `kettle-family release-state` now expands configured
|
|
44
|
+
`release.target_branches` and reports release state for each branch
|
|
45
|
+
independently.
|
|
46
|
+
|
|
47
|
+
- Project licensing changed from MIT to AGPL-3.0-only.
|
|
48
|
+
- `kettle-family release-state` now invokes `kettle-changelog` from the active
|
|
49
|
+
toolchain instead of depending on `kettle-dev` as a published runtime
|
|
50
|
+
dependency.
|
|
51
|
+
|
|
52
|
+
### Fixed
|
|
53
|
+
|
|
54
|
+
- Fixed release-state checks to use the active `kettle-dev` API instead of each
|
|
55
|
+
member's potentially stale bundle.
|
|
56
|
+
- Fixed default discovery excludes so top-level `vendor/`, `tmp/`, `spec/`, and
|
|
57
|
+
`test/` directories are ignored.
|
|
58
|
+
|
|
59
|
+
### Added
|
|
60
|
+
|
|
61
|
+
- Added `kettle-family metadata` to report each family member's version, Ruby
|
|
62
|
+
requirement, licenses, and authors.
|
|
63
|
+
|
|
33
64
|
## [0.1.2] - 2026-06-13
|
|
34
65
|
|
|
35
66
|
- TAG: [v0.1.2][0.1.2t]
|
|
@@ -91,7 +122,9 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
91
122
|
- Fixed CI load failures on engines without compatible `pty` support by falling back to Open3 for interactive release commands.
|
|
92
123
|
- Fixed Ruby 3.2 version-bump support by loading Prism lazily and wiring the Prism gem only for MRI versions that need it.
|
|
93
124
|
|
|
94
|
-
[Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v0.1.
|
|
125
|
+
[Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v0.1.3...HEAD
|
|
126
|
+
[0.1.3]: https://github.com/kettle-dev/kettle-family/compare/v0.1.2...v0.1.3
|
|
127
|
+
[0.1.3t]: https://github.com/kettle-dev/kettle-family/releases/tag/v0.1.3
|
|
95
128
|
[0.1.2]: https://github.com/kettle-dev/kettle-family/compare/v0.1.1...v0.1.2
|
|
96
129
|
[0.1.2t]: https://github.com/kettle-dev/kettle-family/releases/tag/v0.1.2
|
|
97
130
|
[0.1.1]: https://github.com/kettle-dev/kettle-family/compare/v0.1.0...v0.1.1
|
data/LICENSE.md
CHANGED
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
This project is made available under the following license.
|
|
4
4
|
Choose the option that best fits your use case:
|
|
5
5
|
|
|
6
|
-
- [
|
|
6
|
+
- [AGPL-3.0-only](AGPL-3.0-only.md)
|
|
7
|
+
|
|
8
|
+
If none of the above licenses fit your use case, please [contact us](mailto:floss@galtzo.com) to discuss a custom commercial license.
|
|
7
9
|
|
|
8
10
|
## Copyright Notice
|
|
9
11
|
|
data/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# 👩👩👧👧 Kettle::Family
|
|
4
4
|
|
|
5
|
-
[![Version][👽versioni]][👽version] [![GitHub tag (latest SemVer)][⛳️tag-img]][⛳️tag] [![License:
|
|
5
|
+
[![Version][👽versioni]][👽version] [![GitHub tag (latest SemVer)][⛳️tag-img]][⛳️tag] [![License: AGPL-3.0-only][📄license-img]][📄license] [![Downloads Rank][👽dl-ranki]][👽dl-rank] [![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 Test Coverage][🚎2-cov-wfi]][🚎2-cov-wf] [![CI Style][🚎5-st-wfi]][🚎5-st-wf]
|
|
6
6
|
|
|
7
7
|
`if ci_badges.map(&:color).detect { it != "green"}` ☝️ [let me know][✉️discord-invite], as I may have missed the [discord notification][✉️discord-invite].
|
|
8
8
|
|
|
@@ -51,7 +51,7 @@ while RubyGems MFA prompts remain interactive.
|
|
|
51
51
|
| 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] |
|
|
52
52
|
| 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] |
|
|
53
53
|
| Documentation | [![Current release on RubyDoc.info][📜docs-cr-rd-img]][🚎yard-current] [![YARD on Galtzo.com][📜docs-head-rd-img]][🚎yard-head] [![Maintainer Blog][🚂maint-blog-img]][🚂maint-blog] [![GitLab Wiki][📜gl-wiki-img]][📜gl-wiki] [![GitHub Wiki][📜gh-wiki-img]][📜gh-wiki] |
|
|
54
|
-
| Compliance | [![License:
|
|
54
|
+
| Compliance | [![License: AGPL-3.0-only][📄license-img]][📄license] [![Apache license compatibility: Category X][📄license-compat-img]][📄license-compat] [![📄ilo-declaration-img]][📄ilo-declaration] [![Security Policy][🔐security-img]][🔐security] [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct] [![SemVer 2.0.0][📌semver-img]][📌semver] |
|
|
55
55
|
| 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] |
|
|
56
56
|
| 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] |
|
|
57
57
|
| `...` 💖 | [![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] |
|
|
@@ -232,63 +232,6 @@ If you intentionally need to continue after CI failures, opt in explicitly:
|
|
|
232
232
|
kettle-family release --publish --execute --continue-ci-failures
|
|
233
233
|
```
|
|
234
234
|
|
|
235
|
-
## 🦷 FLOSS Funding
|
|
236
|
-
|
|
237
|
-
While kettle-dev tools are free software and will always be, the project would benefit immensely from some funding.
|
|
238
|
-
Raising a monthly budget of... "dollars" would make the project more sustainable.
|
|
239
|
-
|
|
240
|
-
We welcome both individual and corporate sponsors! We also offer a
|
|
241
|
-
wide array of funding channels to account for your preferences.
|
|
242
|
-
Currently, [Open Collective][🖇osc] is our preferred funding platform.
|
|
243
|
-
|
|
244
|
-
**If you're working in a company that's making significant use of kettle-dev tools we'd
|
|
245
|
-
appreciate it if you suggest to your company to become a kettle-dev sponsor.**
|
|
246
|
-
|
|
247
|
-
You can support the development of kettle-dev tools via
|
|
248
|
-
[GitHub Sponsors][🖇sponsor],
|
|
249
|
-
[Liberapay][⛳liberapay],
|
|
250
|
-
[PayPal][🖇paypal],
|
|
251
|
-
[Open Collective][🖇osc]
|
|
252
|
-
and [Tidelift][🏙️entsup-tidelift].
|
|
253
|
-
|
|
254
|
-
| 📍 NOTE |
|
|
255
|
-
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
256
|
-
| If doing a sponsorship in the form of donation is problematic for your company <br/> from an accounting standpoint, we'd recommend the use of Tidelift, <br/> where you can get a support-like subscription instead. |
|
|
257
|
-
|
|
258
|
-
### Open Collective for Individuals
|
|
259
|
-
|
|
260
|
-
Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/kettle-dev#backer)]
|
|
261
|
-
|
|
262
|
-
NOTE: [kettle-readme-backers][kettle-readme-backers] updates this list every day, automatically.
|
|
263
|
-
|
|
264
|
-
<!-- OPENCOLLECTIVE-INDIVIDUALS:START -->
|
|
265
|
-
No backers yet. Be the first!
|
|
266
|
-
<!-- OPENCOLLECTIVE-INDIVIDUALS:END -->
|
|
267
|
-
|
|
268
|
-
### Open Collective for Organizations
|
|
269
|
-
|
|
270
|
-
Become a sponsor and get your logo on our README on GitHub with a link to your site. [[Become a sponsor](https://opencollective.com/kettle-dev#sponsor)]
|
|
271
|
-
|
|
272
|
-
NOTE: [kettle-readme-backers][kettle-readme-backers] updates this list every day, automatically.
|
|
273
|
-
|
|
274
|
-
<!-- OPENCOLLECTIVE-ORGANIZATIONS:START -->
|
|
275
|
-
No sponsors yet. Be the first!
|
|
276
|
-
<!-- OPENCOLLECTIVE-ORGANIZATIONS:END -->
|
|
277
|
-
|
|
278
|
-
[kettle-readme-backers]: https://github.com/kettle-dev/kettle-family/blob/main/exe/kettle-readme-backers
|
|
279
|
-
|
|
280
|
-
### Another way to support open-source
|
|
281
|
-
|
|
282
|
-
I’m driven by a passion to foster a thriving open-source community – a space where people can tackle complex problems, no matter how small. Revitalizing libraries that have fallen into disrepair, and building new libraries focused on solving real-world challenges, are my passions. I was recently affected by layoffs, and the tech jobs market is unwelcoming. I’m reaching out here because your support would significantly aid my efforts to provide for my family, and my farm (11 🐔 chickens, 2 🐶 dogs, 3 🐰 rabbits, 8 🐈 cats).
|
|
283
|
-
|
|
284
|
-
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`.
|
|
285
|
-
|
|
286
|
-
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.
|
|
287
|
-
|
|
288
|
-
**[Floss-Funding.dev][🖇floss-funding.dev]: 👉️ No network calls. 👉️ No tracking. 👉️ No oversight. 👉️ Minimal crypto hashing. 💡 Easily disabled nags**
|
|
289
|
-
|
|
290
|
-
[![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]
|
|
291
|
-
|
|
292
235
|
## 🔐 Security
|
|
293
236
|
|
|
294
237
|
See [SECURITY.md][🔐security].
|
|
@@ -374,8 +317,10 @@ See [CHANGELOG.md][📌changelog] for a list of releases.
|
|
|
374
317
|
|
|
375
318
|
## 📄 License
|
|
376
319
|
|
|
377
|
-
The gem is available
|
|
378
|
-
|
|
320
|
+
The gem is available under the following license: [AGPL-3.0-only](AGPL-3.0-only.md).
|
|
321
|
+
See [LICENSE.md][📄license] for details.
|
|
322
|
+
|
|
323
|
+
If none of the available licenses suit your use case, please [contact us](mailto:floss@galtzo.com) to discuss a custom commercial license.
|
|
379
324
|
|
|
380
325
|
### © Copyright
|
|
381
326
|
|
|
@@ -534,8 +479,6 @@ Thanks for RTFM. ☺️
|
|
|
534
479
|
[🚎13-🔒️-wfi]: https://github.com/kettle-dev/kettle-family/actions/workflows/locked_deps.yml/badge.svg
|
|
535
480
|
[🚎14-🔓️-wf]: https://github.com/kettle-dev/kettle-family/actions/workflows/unlocked_deps.yml
|
|
536
481
|
[🚎14-🔓️-wfi]: https://github.com/kettle-dev/kettle-family/actions/workflows/unlocked_deps.yml/badge.svg
|
|
537
|
-
[🚎15-🪪-wf]: https://github.com/kettle-dev/kettle-family/actions/workflows/license-eye.yml
|
|
538
|
-
[🚎15-🪪-wfi]: https://github.com/kettle-dev/kettle-family/actions/workflows/license-eye.yml/badge.svg
|
|
539
482
|
[💎ruby-3.2i]: https://img.shields.io/badge/Ruby-3.2-CC342D?style=for-the-badge&logo=ruby&logoColor=white
|
|
540
483
|
[💎ruby-3.3i]: https://img.shields.io/badge/Ruby-3.3-CC342D?style=for-the-badge&logo=ruby&logoColor=white
|
|
541
484
|
[💎ruby-3.4i]: https://img.shields.io/badge/Ruby-3.4-CC342D?style=for-the-badge&logo=ruby&logoColor=white
|
|
@@ -573,15 +516,15 @@ Thanks for RTFM. ☺️
|
|
|
573
516
|
[📌gitmoji]: https://gitmoji.dev
|
|
574
517
|
[📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
575
518
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
576
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-0.
|
|
519
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-0.972-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
|
577
520
|
[🔐security]: https://github.com/kettle-dev/kettle-family/blob/main/SECURITY.md
|
|
578
521
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
|
579
522
|
[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
|
|
580
523
|
[📄license]: LICENSE.md
|
|
581
|
-
[📄license-ref]:
|
|
582
|
-
[📄license-img]: https://img.shields.io/badge/License-
|
|
583
|
-
[📄license-compat]: https://www.apache.org/legal/resolved.html#category-
|
|
584
|
-
[📄license-compat-img]: https://img.shields.io/badge/
|
|
524
|
+
[📄license-ref]: AGPL-3.0-only.md
|
|
525
|
+
[📄license-img]: https://img.shields.io/badge/License-AGPL--3.0--only-259D6C.svg
|
|
526
|
+
[📄license-compat]: https://www.apache.org/legal/resolved.html#category-x
|
|
527
|
+
[📄license-compat-img]: https://img.shields.io/badge/Apache_Incompatible:_Category_X-%E2%9C%97-C0392B.svg?style=flat&logo=Apache
|
|
585
528
|
|
|
586
529
|
[📄ilo-declaration]: https://www.ilo.org/declaration/lang--en/index.htm
|
|
587
530
|
[📄ilo-declaration-img]: https://img.shields.io/badge/ILO_Fundamental_Principles-✓-259D6C.svg?style=flat
|
|
@@ -601,7 +544,7 @@ Thanks for RTFM. ☺️
|
|
|
601
544
|
| Package | kettle-family |
|
|
602
545
|
| Description | 👩👩👧👧 Kettle::Family provides scripts and conventions for coordinating related Ruby gems as one family. |
|
|
603
546
|
| Homepage | https://github.com/kettle-dev/kettle-family |
|
|
604
|
-
| Source | https://github.com/kettle-dev/kettle-family/tree/v0.1.
|
|
605
|
-
| License | `
|
|
547
|
+
| Source | https://github.com/kettle-dev/kettle-family/tree/v0.1.3 |
|
|
548
|
+
| License | `AGPL-3.0-only` |
|
|
606
549
|
| Funding | https://github.com/sponsors/pboling, https://issuehunt.io/u/pboling, https://ko-fi.com/pboling, https://liberapay.com/pboling/donate, https://opencollective.com/kettle-dev, https://opencollective.com/kettle-rb, https://patreon.com/galtzo, https://polar.sh/pboling, https://thanks.dev/u/gh/pboling, https://tidelift.com/funding/github/rubygems/kettle-family, https://www.buymeacoffee.com/pboling |
|
|
607
550
|
<!-- kettle-jem:metadata:end -->
|
data/lib/kettle/family/cli.rb
CHANGED
|
@@ -6,7 +6,7 @@ require "optparse"
|
|
|
6
6
|
module Kettle
|
|
7
7
|
module Family
|
|
8
8
|
class CLI
|
|
9
|
-
COMMANDS = %w[discover plan report check test lint docs template bump-version release branch-lanes release-state].freeze
|
|
9
|
+
COMMANDS = %w[discover plan report metadata check test lint docs template bump-version release branch-lanes release-state].freeze
|
|
10
10
|
WORKFLOW_COMMANDS = %w[check test lint docs template release].freeze
|
|
11
11
|
|
|
12
12
|
def self.call(argv, out: $stdout, err: $stderr)
|
|
@@ -53,6 +53,7 @@ module Kettle
|
|
|
53
53
|
discover Discover family members and print selected order
|
|
54
54
|
plan Alias for discover while execution workflows are built
|
|
55
55
|
report Print family discovery and configuration report
|
|
56
|
+
metadata Print version, Ruby floor, license, and author metadata
|
|
56
57
|
check Run internal read-only readiness checks
|
|
57
58
|
test Plan or execute configured test command per member
|
|
58
59
|
lint Plan or execute configured lint command per member
|
|
@@ -139,7 +140,7 @@ module Kettle
|
|
|
139
140
|
def build_report(command, options)
|
|
140
141
|
config = Config.load(root: options[:root], path: options[:config])
|
|
141
142
|
members = Discovery.new(config: config).members
|
|
142
|
-
ordered = if
|
|
143
|
+
ordered = if %w[metadata release-state].include?(command)
|
|
143
144
|
members.sort_by(&:name)
|
|
144
145
|
else
|
|
145
146
|
Orderer.new(members: members, mode: config.order_mode, hints: config.order_hints).ordered
|
|
@@ -168,7 +169,7 @@ module Kettle
|
|
|
168
169
|
def command_results(command:, config:, members:, options:)
|
|
169
170
|
return bump_version_results(members: members, options: options) if command == "bump-version"
|
|
170
171
|
return branch_lane_results(config: config, members: members) if command == "branch-lanes"
|
|
171
|
-
return release_state_results(members: members) if command == "release-state"
|
|
172
|
+
return release_state_results(config: config, members: members) if command == "release-state"
|
|
172
173
|
return [] unless WORKFLOW_COMMANDS.include?(command)
|
|
173
174
|
|
|
174
175
|
Workflow.new(
|
|
@@ -207,8 +208,8 @@ module Kettle
|
|
|
207
208
|
BranchLaneAudit.new(config: config, members: members).results
|
|
208
209
|
end
|
|
209
210
|
|
|
210
|
-
def release_state_results(members:)
|
|
211
|
-
ReleaseStateCheck.new(members: members).results
|
|
211
|
+
def release_state_results(config:, members:)
|
|
212
|
+
ReleaseStateCheck.new(config: config, members: members).results
|
|
212
213
|
end
|
|
213
214
|
|
|
214
215
|
def write_report(report, options)
|
data/lib/kettle/family/config.rb
CHANGED
|
@@ -6,7 +6,16 @@ module Kettle
|
|
|
6
6
|
module Family
|
|
7
7
|
class Config
|
|
8
8
|
DEFAULT_PATHS = [".kettle-family.yml", ".structuredmerge/kettle-family.yml"].freeze
|
|
9
|
-
DEFAULT_MEMBER_EXCLUDES = [
|
|
9
|
+
DEFAULT_MEMBER_EXCLUDES = [
|
|
10
|
+
"vendor/**",
|
|
11
|
+
"**/vendor/**",
|
|
12
|
+
"tmp/**",
|
|
13
|
+
"**/tmp/**",
|
|
14
|
+
"spec/**",
|
|
15
|
+
"**/spec/**",
|
|
16
|
+
"test/**",
|
|
17
|
+
"**/test/**"
|
|
18
|
+
].freeze
|
|
10
19
|
|
|
11
20
|
attr_reader :data, :path, :root
|
|
12
21
|
|
|
@@ -63,17 +63,39 @@ module Kettle
|
|
|
63
63
|
gemspec_path: path,
|
|
64
64
|
version_file: version_file(File.dirname(path)),
|
|
65
65
|
version: spec.version.to_s,
|
|
66
|
-
dependencies: spec.dependencies.map(&:name).sort
|
|
66
|
+
dependencies: spec.dependencies.map(&:name).sort,
|
|
67
|
+
required_ruby_version: required_ruby_version(spec),
|
|
68
|
+
licenses: licenses(spec),
|
|
69
|
+
authors: authors(spec)
|
|
67
70
|
)
|
|
68
71
|
end
|
|
69
72
|
|
|
73
|
+
def required_ruby_version(spec)
|
|
74
|
+
value = spec.required_ruby_version&.to_s&.strip
|
|
75
|
+
value.empty? ? nil : value
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def licenses(spec)
|
|
79
|
+
values = Array(spec.licenses).compact.map(&:to_s).map(&:strip).reject(&:empty?)
|
|
80
|
+
values = [spec.license.to_s.strip] if values.empty? && spec.respond_to?(:license) && !spec.license.to_s.strip.empty?
|
|
81
|
+
values
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def authors(spec)
|
|
85
|
+
Array(spec.authors).compact.map(&:to_s).map(&:strip).reject(&:empty?)
|
|
86
|
+
end
|
|
87
|
+
|
|
70
88
|
def version_file(root)
|
|
71
89
|
candidates = Dir.glob(File.join(root, "lib", "**", "version.rb"))
|
|
72
90
|
candidates.min
|
|
73
91
|
end
|
|
74
92
|
|
|
75
93
|
def load_gemspec(path)
|
|
76
|
-
|
|
94
|
+
# Some legacy gemspecs use root-relative Kernel.load calls, and RubyGems
|
|
95
|
+
# evaluates gemspecs relative to the current process directory.
|
|
96
|
+
# rubocop:disable ThreadSafety/DirChdir
|
|
97
|
+
spec = Dir.chdir(File.dirname(path)) { Gem::Specification.load(path) }
|
|
98
|
+
# rubocop:enable ThreadSafety/DirChdir
|
|
77
99
|
raise Error, "could not load gemspec #{path}" unless spec
|
|
78
100
|
|
|
79
101
|
spec
|
data/lib/kettle/family/member.rb
CHANGED
|
@@ -8,7 +8,10 @@ module Kettle
|
|
|
8
8
|
:gemspec_path,
|
|
9
9
|
:version_file,
|
|
10
10
|
:version,
|
|
11
|
-
:dependencies
|
|
11
|
+
:dependencies,
|
|
12
|
+
:required_ruby_version,
|
|
13
|
+
:licenses,
|
|
14
|
+
:authors
|
|
12
15
|
) do
|
|
13
16
|
def to_h
|
|
14
17
|
{
|
|
@@ -17,7 +20,10 @@ module Kettle
|
|
|
17
20
|
"gemspec_path" => gemspec_path,
|
|
18
21
|
"version_file" => version_file,
|
|
19
22
|
"version" => version,
|
|
20
|
-
"dependencies" => dependencies
|
|
23
|
+
"dependencies" => dependencies,
|
|
24
|
+
"required_ruby_version" => required_ruby_version,
|
|
25
|
+
"licenses" => Array(licenses),
|
|
26
|
+
"authors" => Array(authors)
|
|
21
27
|
}
|
|
22
28
|
end
|
|
23
29
|
end
|
|
@@ -1,40 +1,62 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "json"
|
|
4
|
+
require "fileutils"
|
|
4
5
|
require "open3"
|
|
6
|
+
require "rbconfig"
|
|
7
|
+
require "securerandom"
|
|
5
8
|
|
|
6
9
|
module Kettle
|
|
7
10
|
module Family
|
|
8
11
|
class ReleaseStateCheck
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def initialize(members:)
|
|
12
|
+
def initialize(members:, config: nil)
|
|
12
13
|
@members = members
|
|
14
|
+
@config = config
|
|
13
15
|
end
|
|
14
16
|
|
|
15
17
|
def results
|
|
18
|
+
return branch_results unless release_target_branches.empty?
|
|
19
|
+
|
|
16
20
|
members.map { |member| check_member(member) }
|
|
17
21
|
end
|
|
18
22
|
|
|
19
23
|
private
|
|
20
24
|
|
|
21
|
-
attr_reader :members
|
|
25
|
+
attr_reader :members, :config
|
|
26
|
+
|
|
27
|
+
def branch_results
|
|
28
|
+
root = git_root
|
|
29
|
+
selected_names = members.map(&:name)
|
|
30
|
+
release_target_branches.each_with_object([]) do |branch, memo|
|
|
31
|
+
with_branch_worktree(root: root, branch: branch) do |worktree_root|
|
|
32
|
+
branch_members = discover_branch_members(worktree_root: worktree_root, selected_names: selected_names)
|
|
33
|
+
memo.concat(branch_members.map { |member| check_member(member, branch: branch) })
|
|
34
|
+
end
|
|
35
|
+
rescue Error => error
|
|
36
|
+
memo << error_result(branch: branch, error: error)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
22
39
|
|
|
23
|
-
def check_member(member)
|
|
40
|
+
def check_member(member, branch: nil)
|
|
24
41
|
started = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
25
|
-
|
|
42
|
+
command = release_state_command
|
|
43
|
+
stdout, stderr, status = Open3.capture3(*command, chdir: member.root)
|
|
26
44
|
elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - started
|
|
27
45
|
success = status.success?
|
|
28
46
|
state = success ? JSON.parse(stdout) : {}
|
|
29
|
-
result(member: member, stdout: stdout, stderr: stderr, status: status.exitstatus, elapsed: elapsed, success: success, state: state)
|
|
47
|
+
result(member: member, command: command, stdout: stdout, stderr: stderr, status: status.exitstatus, elapsed: elapsed, success: success, state: state, branch: branch)
|
|
30
48
|
rescue JSON::ParserError => error
|
|
31
|
-
result(member: member, stdout: stdout, stderr: stderr, status: 1, elapsed: elapsed || 0.0, success: false, state: {}, reason: "invalid release-state JSON: #{error.message}")
|
|
49
|
+
result(member: member, command: command || release_state_command, stdout: stdout, stderr: stderr, status: 1, elapsed: elapsed || 0.0, success: false, state: {}, reason: "invalid release-state JSON: #{error.message}", branch: branch)
|
|
32
50
|
end
|
|
33
51
|
|
|
34
|
-
def
|
|
52
|
+
def release_state_command
|
|
53
|
+
[RbConfig.ruby, "-S", "kettle-changelog", "--release-state", "--json"]
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def result(member:, command:, stdout:, stderr:, status:, elapsed:, success:, state:, reason: nil, branch: nil)
|
|
35
57
|
ReleaseStateResult.new(
|
|
36
58
|
member_name: member.name,
|
|
37
|
-
command:
|
|
59
|
+
command: command,
|
|
38
60
|
workdir: member.root,
|
|
39
61
|
status: status,
|
|
40
62
|
success: success,
|
|
@@ -42,9 +64,85 @@ module Kettle
|
|
|
42
64
|
stderr: stderr,
|
|
43
65
|
elapsed_seconds: elapsed,
|
|
44
66
|
state: state,
|
|
45
|
-
reason: reason || (success ? nil : "release state check failed")
|
|
67
|
+
reason: reason || (success ? nil : "release state check failed"),
|
|
68
|
+
branch: branch
|
|
46
69
|
)
|
|
47
70
|
end
|
|
71
|
+
|
|
72
|
+
def error_result(branch:, error:)
|
|
73
|
+
ReleaseStateResult.new(
|
|
74
|
+
member_name: branch,
|
|
75
|
+
command: ["internal", "release-state", branch],
|
|
76
|
+
workdir: config.root,
|
|
77
|
+
status: 1,
|
|
78
|
+
success: false,
|
|
79
|
+
stdout: "",
|
|
80
|
+
stderr: error.message,
|
|
81
|
+
elapsed_seconds: 0.0,
|
|
82
|
+
state: {},
|
|
83
|
+
reason: "branch release state failed",
|
|
84
|
+
branch: branch
|
|
85
|
+
)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def release_target_branches
|
|
89
|
+
return [] unless config
|
|
90
|
+
|
|
91
|
+
config.release_target_branches
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def git_root
|
|
95
|
+
stdout, stderr, status = Open3.capture3("git", "rev-parse", "--show-toplevel", chdir: config.root)
|
|
96
|
+
raise Error, "could not determine git root for #{config.root}: #{stderr}" unless status.success?
|
|
97
|
+
|
|
98
|
+
File.realpath(stdout.strip)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def with_branch_worktree(root:, branch:)
|
|
102
|
+
base = File.join(root, "tmp", "kettle-family-release-state")
|
|
103
|
+
FileUtils.mkdir_p(base)
|
|
104
|
+
worktree_root = File.join(base, "worktree-#{Process.pid}-#{SecureRandom.hex(8)}")
|
|
105
|
+
add_branch_worktree(root: root, branch: branch, worktree_root: worktree_root)
|
|
106
|
+
yield worktree_root
|
|
107
|
+
ensure
|
|
108
|
+
remove_branch_worktree(root: root, worktree_root: worktree_root)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def add_branch_worktree(root:, branch:, worktree_root:)
|
|
112
|
+
_stdout, stderr, status = Open3.capture3("git", "worktree", "add", "--detach", worktree_root, branch, chdir: root)
|
|
113
|
+
raise Error, "could not add worktree for #{branch}: #{stderr}" unless status.success?
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def remove_branch_worktree(root:, worktree_root:)
|
|
117
|
+
return unless worktree_root && Dir.exist?(worktree_root)
|
|
118
|
+
|
|
119
|
+
Open3.capture3("git", "worktree", "remove", "--force", worktree_root, chdir: root)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def discover_branch_members(worktree_root:, selected_names:)
|
|
123
|
+
branch_config = Config.load(root: branch_config_root(worktree_root))
|
|
124
|
+
Discovery.new(config: branch_config).members
|
|
125
|
+
.sort_by(&:name)
|
|
126
|
+
.select { |member| selected_names.include?(member.name) }
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def branch_config_root(worktree_root)
|
|
130
|
+
File.join(worktree_root, relative_config_root)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def relative_config_root
|
|
134
|
+
@relative_config_root ||= begin
|
|
135
|
+
root = git_root
|
|
136
|
+
config_root = File.realpath(config.root)
|
|
137
|
+
if config_root == root
|
|
138
|
+
"."
|
|
139
|
+
elsif config_root.start_with?("#{root}/")
|
|
140
|
+
config_root.delete_prefix("#{root}/")
|
|
141
|
+
else
|
|
142
|
+
raise Error, "configured root #{config.root} is outside git root #{root}"
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
48
146
|
end
|
|
49
147
|
end
|
|
50
148
|
end
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
module Kettle
|
|
4
4
|
module Family
|
|
5
5
|
class ReleaseStateResult
|
|
6
|
-
attr_reader :member_name, :phase, :command, :workdir, :status, :success, :stdout, :stderr, :elapsed_seconds, :skipped, :reason, :state
|
|
6
|
+
attr_reader :member_name, :phase, :command, :workdir, :status, :success, :stdout, :stderr, :elapsed_seconds, :skipped, :reason, :state, :branch
|
|
7
7
|
|
|
8
|
-
def initialize(member_name:, command:, workdir:, status:, success:, stdout:, stderr:, elapsed_seconds:, state:, reason: nil)
|
|
8
|
+
def initialize(member_name:, command:, workdir:, status:, success:, stdout:, stderr:, elapsed_seconds:, state:, reason: nil, branch: nil)
|
|
9
9
|
@member_name = member_name
|
|
10
10
|
@phase = "release_state"
|
|
11
11
|
@command = command
|
|
@@ -18,6 +18,7 @@ module Kettle
|
|
|
18
18
|
@skipped = false
|
|
19
19
|
@reason = reason
|
|
20
20
|
@state = state
|
|
21
|
+
@branch = branch
|
|
21
22
|
end
|
|
22
23
|
|
|
23
24
|
def ok?
|
|
@@ -37,6 +38,7 @@ module Kettle
|
|
|
37
38
|
"elapsed_seconds" => elapsed_seconds,
|
|
38
39
|
"skipped" => skipped,
|
|
39
40
|
"reason" => reason,
|
|
41
|
+
"branch" => branch,
|
|
40
42
|
"release_state" => state
|
|
41
43
|
}
|
|
42
44
|
end
|
data/lib/kettle/family/report.rb
CHANGED
|
@@ -64,6 +64,7 @@ module Kettle
|
|
|
64
64
|
private
|
|
65
65
|
|
|
66
66
|
def append_results(lines)
|
|
67
|
+
return append_metadata_results(lines) if command == "metadata"
|
|
67
68
|
return if results.empty?
|
|
68
69
|
return append_release_state_results(lines) if command == "release-state"
|
|
69
70
|
|
|
@@ -82,9 +83,24 @@ module Kettle
|
|
|
82
83
|
"failed"
|
|
83
84
|
end
|
|
84
85
|
|
|
86
|
+
def append_metadata_results(lines)
|
|
87
|
+
lines << "metadata:"
|
|
88
|
+
rows = [["gem", "version", "ruby", "licenses", "authors"]]
|
|
89
|
+
selected_members.each do |member|
|
|
90
|
+
rows << [
|
|
91
|
+
member.name.to_s,
|
|
92
|
+
member.version.to_s,
|
|
93
|
+
blank_as_none(member.required_ruby_version),
|
|
94
|
+
blank_as_none(Array(member.licenses).join(", ")),
|
|
95
|
+
blank_as_none(Array(member.authors).join(", "))
|
|
96
|
+
]
|
|
97
|
+
end
|
|
98
|
+
lines.concat(format_table(rows).map { |line| " #{line}" })
|
|
99
|
+
end
|
|
100
|
+
|
|
85
101
|
def append_release_state_results(lines)
|
|
86
102
|
lines << "release state:"
|
|
87
|
-
rows =
|
|
103
|
+
rows = release_state_header
|
|
88
104
|
results.each do |result|
|
|
89
105
|
rows << release_state_row(result)
|
|
90
106
|
end
|
|
@@ -101,7 +117,7 @@ module Kettle
|
|
|
101
117
|
|
|
102
118
|
def release_state_row(result)
|
|
103
119
|
state = result.state || {}
|
|
104
|
-
[
|
|
120
|
+
row = [
|
|
105
121
|
state.fetch("gem_name", result.member_name).to_s,
|
|
106
122
|
state.fetch("version", "unknown").to_s,
|
|
107
123
|
state.fetch("latest_released", nil).to_s.empty? ? "unknown" : state.fetch("latest_released").to_s,
|
|
@@ -110,6 +126,20 @@ module Kettle
|
|
|
110
126
|
yes_no(state.fetch("prepared_release_pending", nil)),
|
|
111
127
|
yes_no(state.fetch("pending_release", nil))
|
|
112
128
|
]
|
|
129
|
+
return row unless release_state_has_branches?
|
|
130
|
+
|
|
131
|
+
[result.branch.to_s.empty? ? "current" : result.branch.to_s, *row]
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def release_state_header
|
|
135
|
+
header = [["gem", "version.rb", "latest released", "latest changelog", "unreleased", "prepared", "pending"]]
|
|
136
|
+
return header unless release_state_has_branches?
|
|
137
|
+
|
|
138
|
+
[["branch", *header.first]]
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def release_state_has_branches?
|
|
142
|
+
results.any? { |result| !result.branch.to_s.empty? }
|
|
113
143
|
end
|
|
114
144
|
|
|
115
145
|
def format_table(rows)
|
|
@@ -131,6 +161,11 @@ module Kettle
|
|
|
131
161
|
end
|
|
132
162
|
end
|
|
133
163
|
|
|
164
|
+
def blank_as_none(value)
|
|
165
|
+
text = value.to_s.strip
|
|
166
|
+
text.empty? ? "(none)" : text
|
|
167
|
+
end
|
|
168
|
+
|
|
134
169
|
def resume_hint
|
|
135
170
|
failed = results.find { |result| !result.ok? }
|
|
136
171
|
resume_hint_for(failed) if failed
|
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kettle-family
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter H. Boling
|
|
@@ -80,7 +80,7 @@ dependencies:
|
|
|
80
80
|
version: '2.2'
|
|
81
81
|
- - ">="
|
|
82
82
|
- !ruby/object:Gem::Version
|
|
83
|
-
version: 2.2.
|
|
83
|
+
version: 2.2.8
|
|
84
84
|
type: :development
|
|
85
85
|
prerelease: false
|
|
86
86
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -90,7 +90,7 @@ dependencies:
|
|
|
90
90
|
version: '2.2'
|
|
91
91
|
- - ">="
|
|
92
92
|
- !ruby/object:Gem::Version
|
|
93
|
-
version: 2.2.
|
|
93
|
+
version: 2.2.8
|
|
94
94
|
- !ruby/object:Gem::Dependency
|
|
95
95
|
name: bundler-audit
|
|
96
96
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -305,13 +305,13 @@ files:
|
|
|
305
305
|
- sig/kettle/family/version.rbs
|
|
306
306
|
homepage: https://github.com/kettle-dev/kettle-family
|
|
307
307
|
licenses:
|
|
308
|
-
-
|
|
308
|
+
- AGPL-3.0-only
|
|
309
309
|
metadata:
|
|
310
310
|
homepage_uri: https://kettle-family.galtzo.com
|
|
311
|
-
source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v0.1.
|
|
312
|
-
changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v0.1.
|
|
311
|
+
source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v0.1.3
|
|
312
|
+
changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v0.1.3/CHANGELOG.md
|
|
313
313
|
bug_tracker_uri: https://github.com/kettle-dev/kettle-family/issues
|
|
314
|
-
documentation_uri: https://www.rubydoc.info/gems/kettle-family/0.1.
|
|
314
|
+
documentation_uri: https://www.rubydoc.info/gems/kettle-family/0.1.3
|
|
315
315
|
funding_uri: https://github.com/sponsors/pboling
|
|
316
316
|
wiki_uri: https://github.com/kettle-dev/kettle-family/wiki
|
|
317
317
|
news_uri: https://www.railsbling.com/tags/kettle-family
|
metadata.gz.sig
CHANGED
|
Binary file
|