kettle-family 1.0.0 → 1.0.1
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 +53 -1
- data/README.md +89 -5
- data/lib/kettle/family/cli.rb +50 -12
- data/lib/kettle/family/command_runner.rb +38 -1
- data/lib/kettle/family/config.rb +2 -2
- data/lib/kettle/family/release_state_check.rb +25 -1
- data/lib/kettle/family/report.rb +2 -1
- data/lib/kettle/family/selection.rb +48 -2
- data/lib/kettle/family/version.rb +1 -1
- data/lib/kettle/family/version_bump.rb +5 -4
- data/lib/kettle/family/workflow.rb +154 -8
- data/sig/kettle/family.rbs +0 -63
- data.tar.gz.sig +0 -0
- metadata +12 -12
- 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: ddbeefcf7d7d90e52b0fadb3f09358c14baaa3eade9b03685e36868bd608e810
|
|
4
|
+
data.tar.gz: a75ce0508f27ba21ee30cf7a23fb95b97479ce1f6f03242a0fcc3210b2d2092f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '02850c92673ac9c330561be7e9b7cba733683aa952312cdf17bab8a299e4dbcd002ee9f75c5f08cd68c4650dcfea57399e04713523890822a50ce6278bf0536a'
|
|
7
|
+
data.tar.gz: a4b1e30e093fb889d26755250bc035243436a2e272288575991b9fcb83003288b4cb665363633711b20e4c7e1ce13103c7cd038d1b0e721dbd78a805af3ec4c9
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/CHANGELOG.md
CHANGED
|
@@ -28,8 +28,58 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
28
28
|
|
|
29
29
|
### Fixed
|
|
30
30
|
|
|
31
|
+
- Generated HEAD and runtime dependency HEAD CI workflows no longer include
|
|
32
|
+
JRuby or TruffleRuby jobs for this MRI-only gem.
|
|
33
|
+
|
|
31
34
|
### Security
|
|
32
35
|
|
|
36
|
+
## [1.0.1] - 2026-07-20
|
|
37
|
+
|
|
38
|
+
- TAG: [v1.0.1][1.0.1t]
|
|
39
|
+
- COVERAGE: 95.44% -- 2534/2655 lines in 23 files
|
|
40
|
+
- BRANCH COVERAGE: 77.89% -- 877/1126 branches in 23 files
|
|
41
|
+
- 29.10% documented
|
|
42
|
+
|
|
43
|
+
### Added
|
|
44
|
+
|
|
45
|
+
- `kettle-family release-state` now includes an `ahead` column counting commits
|
|
46
|
+
from the latest release tag to the local default branch when available.
|
|
47
|
+
- `kettle-family release` now accepts `--skip-remotes` and forwards the
|
|
48
|
+
comma-separated remote skip list to member `kettle-release` runs.
|
|
49
|
+
- `kettle-family --only` now accepts release-state tokens `unreleased`,
|
|
50
|
+
`prepared`, and `pending`; multiple tokens are combined with logical AND.
|
|
51
|
+
- `kettle-family template` now accepts `--verbose` and forwards verbose mode to
|
|
52
|
+
member `kettle-jem` runs instead of forcing quiet JSON output.
|
|
53
|
+
|
|
54
|
+
- `kettle-family template` now runs `kettle-jem prepare` before full templating
|
|
55
|
+
for Kettle Jem-powered members so templating-only dependency bootstraps, such
|
|
56
|
+
as parser packages, are available before the full template command loads.
|
|
57
|
+
|
|
58
|
+
- `kettle-family template` now uses `kettle-jem --events` as its default
|
|
59
|
+
templating interface, including verbose and single-job runs, and streams
|
|
60
|
+
newline-delimited JSON template phase, recipe, post-apply, command-step,
|
|
61
|
+
diagnostic, and summary events as member-prefixed progress lines.
|
|
62
|
+
|
|
63
|
+
### Deprecated
|
|
64
|
+
|
|
65
|
+
- `kettle-family bump-version` is now deprecated in favor of `kettle-family bump`.
|
|
66
|
+
|
|
67
|
+
### Fixed
|
|
68
|
+
|
|
69
|
+
- The templating prepare phase now disables only the implicit family local path
|
|
70
|
+
environment variable unless it was explicitly provided, avoiding stale local
|
|
71
|
+
Gemfile activation failures before the prepare payload can refresh generated
|
|
72
|
+
modular Gemfiles.
|
|
73
|
+
- The templating prepare phase now runs outside each member's Bundler context so
|
|
74
|
+
it can repair stale generated Gemfiles before Bundler evaluates them.
|
|
75
|
+
|
|
76
|
+
- `kettle-family` template preparation now handles custom non-`kettle-jem`
|
|
77
|
+
template commands without treating no-op dependency preparation as failure.
|
|
78
|
+
- `kettle-family release-state` now counts `ahead` from the release tag to the
|
|
79
|
+
checked-out member `HEAD`.
|
|
80
|
+
- Generated docs now retain the YARD `_index.html` content wrapper after
|
|
81
|
+
regeneration with the shared YARD postprocessing stack.
|
|
82
|
+
|
|
33
83
|
## [1.0.0] - 2026-07-17
|
|
34
84
|
|
|
35
85
|
- TAG: [v1.0.0][1.0.0t]
|
|
@@ -736,7 +786,9 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
736
786
|
- Fixed CI load failures on engines without compatible `pty` support by falling back to Open3 for interactive release commands.
|
|
737
787
|
- Fixed Ruby 3.2 version-bump support by loading Prism lazily and wiring the Prism gem only for MRI versions that need it.
|
|
738
788
|
|
|
739
|
-
[Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.0.
|
|
789
|
+
[Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.0.1...HEAD
|
|
790
|
+
[1.0.1]: https://github.com/kettle-dev/kettle-family/compare/v1.0.0...v1.0.1
|
|
791
|
+
[1.0.1t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.0.1
|
|
740
792
|
[1.0.0]: https://github.com/kettle-dev/kettle-family/compare/v0.2.7...v1.0.0
|
|
741
793
|
[1.0.0t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.0.0
|
|
742
794
|
[0.2.7]: https://github.com/kettle-dev/kettle-family/compare/v0.2.6...v0.2.7
|
data/README.md
CHANGED
|
@@ -211,7 +211,7 @@ changelog:
|
|
|
211
211
|
|
|
212
212
|
release:
|
|
213
213
|
env:
|
|
214
|
-
|
|
214
|
+
KETTLE_DEV_DEV: false
|
|
215
215
|
family_changelog:
|
|
216
216
|
enabled: true
|
|
217
217
|
command: bundle exec kettle-changelog
|
|
@@ -273,8 +273,28 @@ kettle-family release-state
|
|
|
273
273
|
```
|
|
274
274
|
|
|
275
275
|
The release-state report lists each gem's current `version.rb`, latest published
|
|
276
|
-
release, latest versioned `CHANGELOG.md` section,
|
|
277
|
-
|
|
276
|
+
release, latest versioned `CHANGELOG.md` section, whether pending changelog work
|
|
277
|
+
exists in either `Unreleased` or an unpublished prepared release section, and
|
|
278
|
+
how many commits the current branch is ahead of the latest release tag.
|
|
279
|
+
|
|
280
|
+
Use release-state tokens with `--only` to select gems by state instead of by
|
|
281
|
+
name. Multiple tokens are combined with logical AND, so this selects only gems
|
|
282
|
+
that are both unreleased and pending. Status tokens cannot be mixed with member
|
|
283
|
+
names in the same `--only` value.
|
|
284
|
+
|
|
285
|
+
```console
|
|
286
|
+
kettle-family release-state --only pending
|
|
287
|
+
kettle-family release-state --only unreleased,prepared
|
|
288
|
+
kettle-family release --execute --only unreleased,pending
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
The supported release-state tokens are:
|
|
292
|
+
|
|
293
|
+
| Token | Meaning |
|
|
294
|
+
|-------|---------|
|
|
295
|
+
| `unreleased` | The current `version.rb` is not the latest published gem version. |
|
|
296
|
+
| `prepared` | The changelog already has a versioned section for the current `version.rb`. |
|
|
297
|
+
| `pending` | The member has unreleased changelog work or an unpublished prepared release. |
|
|
278
298
|
|
|
279
299
|
Plan or update GitHub Actions workflow SHA pins across the selected family
|
|
280
300
|
members:
|
|
@@ -291,6 +311,15 @@ Run release prep/build phases without publishing:
|
|
|
291
311
|
kettle-family release --execute
|
|
292
312
|
```
|
|
293
313
|
|
|
314
|
+
When a remote mirror is temporarily unavailable, skip it for the underlying
|
|
315
|
+
`kettle-release` fetch/parity gate instead of removing the remote from each
|
|
316
|
+
member repository:
|
|
317
|
+
|
|
318
|
+
```console
|
|
319
|
+
kettle-family release --execute --publish --skip-remotes cb
|
|
320
|
+
kettle-family release --execute --publish --skip-remotes cb,mirror2
|
|
321
|
+
```
|
|
322
|
+
|
|
294
323
|
Publish through `kettle-release`. A full publish first runs the
|
|
295
324
|
`kettle-pre-release` gate, then prompts once for the gem signing key password
|
|
296
325
|
and leaves RubyGems MFA prompts interactive:
|
|
@@ -321,6 +350,61 @@ If you intentionally need to continue after CI failures, opt in explicitly:
|
|
|
321
350
|
kettle-family release --publish --execute --continue-ci-failures
|
|
322
351
|
```
|
|
323
352
|
|
|
353
|
+
Bump aligned member versions with `bump`. The older `bump-version` command still
|
|
354
|
+
works as a deprecated alias.
|
|
355
|
+
|
|
356
|
+
```console
|
|
357
|
+
kettle-family bump --execute --only pending patch
|
|
358
|
+
kettle-family bump --execute --only unreleased minor
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
Run `kettle-jem` templating across the selected family members. Planning shows
|
|
362
|
+
the commands that would run; `--execute` runs them. Executed templating defaults
|
|
363
|
+
to a parallel job count based on CPU cores, capped for readability, and can be
|
|
364
|
+
overridden with `--jobs`.
|
|
365
|
+
|
|
366
|
+
```console
|
|
367
|
+
kettle-family template
|
|
368
|
+
kettle-family template --execute --jobs 4
|
|
369
|
+
kettle-family template --execute --only kettle-family
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
Templating uses `kettle-jem --events` as the default child interface, so
|
|
373
|
+
executed runs stream member-prefixed progress while still keeping the final
|
|
374
|
+
family report. Progress marks include:
|
|
375
|
+
|
|
376
|
+
| Mark | Meaning |
|
|
377
|
+
|------|---------|
|
|
378
|
+
| `>` | A phase or command step started. |
|
|
379
|
+
| `.` | A phase, recipe, or step completed without changing files. |
|
|
380
|
+
| `*` | A recipe or step changed files. |
|
|
381
|
+
| `!` | A diagnostic was emitted. |
|
|
382
|
+
| `F` | A phase or step failed. |
|
|
383
|
+
| `done` | The member summary was emitted. |
|
|
384
|
+
|
|
385
|
+
Example progress:
|
|
386
|
+
|
|
387
|
+
```text
|
|
388
|
+
templating 1 member with 1 job:
|
|
389
|
+
[kettle-family] > recipes
|
|
390
|
+
[kettle-family] * Gemfile
|
|
391
|
+
[kettle-family] * post_apply:git_hooks_executable
|
|
392
|
+
[kettle-family] done 2 files changed
|
|
393
|
+
.
|
|
394
|
+
template summary: 1/1 members ok, 2 files changed
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
Use `--verbose` when you need `kettle-jem` verbose diagnostics layered on top of
|
|
398
|
+
the event stream. Environment overrides pass through to every member workflow
|
|
399
|
+
command, which is useful when templating against local unreleased dependencies.
|
|
400
|
+
|
|
401
|
+
```console
|
|
402
|
+
kettle-family template --execute --verbose --jobs 1
|
|
403
|
+
kettle-family template --execute \
|
|
404
|
+
--env K_JEM_TEMPLATING=true \
|
|
405
|
+
--env STRUCTUREDMERGE_DEV=/home/me/src/structuredmerge/ruby/gems
|
|
406
|
+
```
|
|
407
|
+
|
|
324
408
|
## 🔐 Security
|
|
325
409
|
|
|
326
410
|
See [SECURITY.md][🔐security].
|
|
@@ -386,7 +470,7 @@ For most applications, prefer the [Pessimistic Version Constraint][📌pvc] with
|
|
|
386
470
|
For example:
|
|
387
471
|
|
|
388
472
|
```ruby
|
|
389
|
-
spec.add_dependency("kettle-family", "~>
|
|
473
|
+
spec.add_dependency("kettle-family", "~> 1.0")
|
|
390
474
|
```
|
|
391
475
|
|
|
392
476
|
<details markdown="1">
|
|
@@ -583,7 +667,7 @@ Thanks for RTFM. ☺️
|
|
|
583
667
|
[📌gitmoji]: https://gitmoji.dev
|
|
584
668
|
[📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
585
669
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
586
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-2.
|
|
670
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-2.655-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
|
587
671
|
[🔐security]: https://github.com/kettle-dev/kettle-family/blob/main/SECURITY.md
|
|
588
672
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
|
589
673
|
[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
|
data/lib/kettle/family/cli.rb
CHANGED
|
@@ -10,7 +10,7 @@ module Kettle
|
|
|
10
10
|
class CLI < CommandKit::Command
|
|
11
11
|
include CommandKit::Commands
|
|
12
12
|
|
|
13
|
-
COMMANDS = %w[discover plan report metadata check test lint docs template gha-sha-pins bup bupb bex install bump-version add-changelog release push pull up branch-lanes release-state].freeze
|
|
13
|
+
COMMANDS = %w[discover plan report metadata check test lint docs template gha-sha-pins bup bupb bex install bump bump-version add-changelog release push pull up branch-lanes release-state].freeze
|
|
14
14
|
WORKFLOW_COMMANDS = %w[check test lint docs template gha-sha-pins bup bupb bex release push pull up].freeze
|
|
15
15
|
|
|
16
16
|
command_name "kettle-family"
|
|
@@ -37,7 +37,7 @@ module Kettle
|
|
|
37
37
|
|
|
38
38
|
module SelectionOptions
|
|
39
39
|
def self.included(base)
|
|
40
|
-
base.option :only, value: {type: String, usage: "MEMBERS"}, desc: "Select comma-separated members"
|
|
40
|
+
base.option :only, value: {type: String, usage: "MEMBERS"}, desc: "Select comma-separated members, or release-state tokens: unreleased, prepared, pending"
|
|
41
41
|
base.option :exclude, value: {type: String, usage: "MEMBERS"}, desc: "Exclude comma-separated members"
|
|
42
42
|
base.option :start_at, long: "--start-at", value: {type: String, usage: "MEMBER[@BRANCH]"}, desc: "Select from member through the end of order"
|
|
43
43
|
end
|
|
@@ -65,6 +65,7 @@ module Kettle
|
|
|
65
65
|
module WorkflowOptions
|
|
66
66
|
def self.included(base)
|
|
67
67
|
base.option :debug, desc: "Preserve debug environment for workflow commands"
|
|
68
|
+
base.option :verbose, desc: "Pass verbose mode through to supported workflow commands"
|
|
68
69
|
base.option :jobs, value: {type: Integer, usage: "N"}, desc: "Parallel jobs for supported executed workflows"
|
|
69
70
|
base.option :env, value: {type: String, usage: "KEY=VALUE"}, desc: "Override an environment variable for each member workflow command" do |value|
|
|
70
71
|
parse_env_override(value, workflow_env)
|
|
@@ -134,6 +135,7 @@ module Kettle
|
|
|
134
135
|
report: options[:report],
|
|
135
136
|
execute: truthy_option?(:execute),
|
|
136
137
|
debug: truthy_option?(:debug),
|
|
138
|
+
verbose: truthy_option?(:verbose),
|
|
137
139
|
jobs: options[:jobs],
|
|
138
140
|
workflow_env: workflow_env,
|
|
139
141
|
changelog_section: nil,
|
|
@@ -148,6 +150,7 @@ module Kettle
|
|
|
148
150
|
release_continue_ci_failures: false,
|
|
149
151
|
release_ci_workflows: nil,
|
|
150
152
|
release_skip_bundle_audit: false,
|
|
153
|
+
release_skip_remotes: nil,
|
|
151
154
|
accept: true,
|
|
152
155
|
tag: false,
|
|
153
156
|
push: false,
|
|
@@ -353,11 +356,11 @@ module Kettle
|
|
|
353
356
|
end
|
|
354
357
|
end
|
|
355
358
|
|
|
356
|
-
class
|
|
359
|
+
class Bump < BaseCommand
|
|
357
360
|
include ExecutionOptions
|
|
358
361
|
include CommitOptions
|
|
359
362
|
|
|
360
|
-
command_name "bump
|
|
363
|
+
command_name "bump"
|
|
361
364
|
usage "[options] VERSION|major|minor|patch|pre"
|
|
362
365
|
description "Check, plan, or execute family version alignment."
|
|
363
366
|
argument :target_version, required: false, usage: "VERSION|major|minor|patch|pre", desc: "Version or bump target"
|
|
@@ -366,9 +369,31 @@ module Kettle
|
|
|
366
369
|
option :from, value: {type: String, usage: "VERSION"}, desc: "Require selected members to currently match VERSION"
|
|
367
370
|
|
|
368
371
|
def run(target_version = nil)
|
|
369
|
-
raise Error, "
|
|
372
|
+
raise Error, "#{workflow_command_name} requires VERSION, major, minor, patch, or pre" unless target_version
|
|
373
|
+
|
|
374
|
+
run_family(workflow_command_name, target_version: target_version, from_version: options[:from])
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
private
|
|
378
|
+
|
|
379
|
+
def workflow_command_name
|
|
380
|
+
"bump"
|
|
381
|
+
end
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
class BumpVersion < Bump
|
|
385
|
+
command_name "bump-version"
|
|
386
|
+
description "Deprecated alias for bump."
|
|
387
|
+
|
|
388
|
+
def run(target_version = nil)
|
|
389
|
+
stderr.puts("kettle-family: bump-version is deprecated; use bump instead.")
|
|
390
|
+
super
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
private
|
|
370
394
|
|
|
371
|
-
|
|
395
|
+
def workflow_command_name
|
|
396
|
+
"bump-version"
|
|
372
397
|
end
|
|
373
398
|
end
|
|
374
399
|
|
|
@@ -407,6 +432,7 @@ module Kettle
|
|
|
407
432
|
option :continue_ci_failures, long: "--continue-ci-failures", desc: "Set K_RELEASE_CI_CONTINUE=true for release commands"
|
|
408
433
|
option :ci_workflows, long: "--ci-workflows", value: {type: String, usage: "LIST"}, desc: "Pass a comma-separated CI workflow monitor subset through to kettle-release commands"
|
|
409
434
|
option :skip_bundle_audit, long: "--skip-bundle-audit", desc: "Skip bundle:audit/update during release rake checks"
|
|
435
|
+
option :skip_remotes, long: "--skip-remotes", value: {type: String, usage: "LIST"}, desc: "Pass a comma-separated git remote skip list through to kettle-release commands"
|
|
410
436
|
option :no_auto_floors, long: "--no-auto-floors", desc: "Do not raise family dependency floors between member releases" do
|
|
411
437
|
options[:no_auto_floors] = true
|
|
412
438
|
end
|
|
@@ -428,6 +454,7 @@ module Kettle
|
|
|
428
454
|
release_continue_ci_failures: truthy_option?(:continue_ci_failures),
|
|
429
455
|
release_ci_workflows: options[:ci_workflows],
|
|
430
456
|
release_skip_bundle_audit: truthy_option?(:skip_bundle_audit),
|
|
457
|
+
release_skip_remotes: options[:skip_remotes],
|
|
431
458
|
release_auto_dependency_floors: !truthy_option?(:no_auto_floors),
|
|
432
459
|
accept: !options.key?(:accept) || options[:accept],
|
|
433
460
|
tag: truthy_option?(:tag),
|
|
@@ -468,6 +495,7 @@ module Kettle
|
|
|
468
495
|
command Bupb
|
|
469
496
|
command Bex
|
|
470
497
|
command Install
|
|
498
|
+
command Bump
|
|
471
499
|
command BumpVersion
|
|
472
500
|
command AddChangelog
|
|
473
501
|
command Release
|
|
@@ -514,7 +542,8 @@ module Kettle
|
|
|
514
542
|
else
|
|
515
543
|
Orderer.new(members: members, mode: config.order_mode, hints: config.order_hints).ordered
|
|
516
544
|
end
|
|
517
|
-
|
|
545
|
+
release_state_results = release_state_results_for_selection(config: config, members: ordered, only: options[:only])
|
|
546
|
+
selected = Selection.new(members: ordered, release_state_results: release_state_results).apply(only: options[:only], exclude: options[:exclude], start_at: start_at.member)
|
|
518
547
|
result_members = selected
|
|
519
548
|
results = command_results(command: command, config: config, members: result_members, options: options, start_at: start_at)
|
|
520
549
|
Report.new(
|
|
@@ -542,8 +571,14 @@ module Kettle
|
|
|
542
571
|
command_results_for_current_branch(command: command, config: config, members: members, options: options, start_at: start_at)
|
|
543
572
|
end
|
|
544
573
|
|
|
574
|
+
def release_state_results_for_selection(config:, members:, only:)
|
|
575
|
+
return nil unless only.to_s.split(",").map(&:strip).any? { |token| Selection.status_token?(token) }
|
|
576
|
+
|
|
577
|
+
ReleaseStateCheck.new(config: config, members: members).results
|
|
578
|
+
end
|
|
579
|
+
|
|
545
580
|
def command_results_for_current_branch(command:, config:, members:, options:, start_at: StartAt.new(nil, nil))
|
|
546
|
-
return bump_version_results(members: members, options: options
|
|
581
|
+
return bump_version_results(members: members, options: options, phase: command) if %w[bump bump-version].include?(command)
|
|
547
582
|
return add_changelog_results(members: members, options: options) if command == "add-changelog"
|
|
548
583
|
return branch_lane_results(config: config, members: members) if command == "branch-lanes"
|
|
549
584
|
return release_state_results(config: config, members: members) if command == "release-state"
|
|
@@ -567,11 +602,13 @@ module Kettle
|
|
|
567
602
|
continue_ci_failures: options[:release_continue_ci_failures],
|
|
568
603
|
ci_workflows: options[:release_ci_workflows],
|
|
569
604
|
skip_bundle_audit: options[:release_skip_bundle_audit],
|
|
605
|
+
skip_remotes: options[:release_skip_remotes],
|
|
570
606
|
auto_dependency_floors: options[:release_auto_dependency_floors],
|
|
571
607
|
gha_sha_pins_upgrade: options[:gha_sha_pins_upgrade],
|
|
572
608
|
gha_sha_pins_check: options[:check],
|
|
573
609
|
env_overrides: options[:workflow_env],
|
|
574
610
|
debug: options[:debug],
|
|
611
|
+
verbose: options[:verbose],
|
|
575
612
|
jobs: options[:jobs],
|
|
576
613
|
progress_io: progress_io(command, options),
|
|
577
614
|
bup_args: options[:bup_args],
|
|
@@ -593,14 +630,14 @@ module Kettle
|
|
|
593
630
|
return false if config.release_target_branches.empty?
|
|
594
631
|
return false if command == "release-state"
|
|
595
632
|
return false if command == "branch-lanes"
|
|
596
|
-
return false unless WORKFLOW_COMMANDS.include?(command) || %w[bump-version install add-changelog].include?(command)
|
|
633
|
+
return false unless WORKFLOW_COMMANDS.include?(command) || %w[bump bump-version install add-changelog].include?(command)
|
|
597
634
|
|
|
598
635
|
!WORKFLOW_COMMANDS.include?(command)
|
|
599
636
|
end
|
|
600
637
|
|
|
601
638
|
def member_local_branch_target_command?(command, config, members)
|
|
602
639
|
return false if !config.release_target_branches.empty?
|
|
603
|
-
return false unless %w[bump-version install add-changelog].include?(command)
|
|
640
|
+
return false unless %w[bump bump-version install add-changelog].include?(command)
|
|
604
641
|
|
|
605
642
|
members.any? { |member| member_release_config(member: member, config: config) }
|
|
606
643
|
end
|
|
@@ -686,14 +723,15 @@ module Kettle
|
|
|
686
723
|
StartAt.new(member, branch)
|
|
687
724
|
end
|
|
688
725
|
|
|
689
|
-
def bump_version_results(members:, options:)
|
|
726
|
+
def bump_version_results(members:, options:, phase:)
|
|
690
727
|
require_relative "version_bump"
|
|
691
728
|
|
|
692
729
|
results = VersionBump.new(
|
|
693
730
|
members: members,
|
|
694
731
|
target_version: options[:target_version],
|
|
695
732
|
from_version: options[:from_version],
|
|
696
|
-
mode: bump_version_mode(options)
|
|
733
|
+
mode: bump_version_mode(options),
|
|
734
|
+
phase: phase
|
|
697
735
|
).results
|
|
698
736
|
return results if options[:check] || !options[:commit]
|
|
699
737
|
return results unless results.all?(&:ok?)
|
|
@@ -111,7 +111,7 @@ module Kettle
|
|
|
111
111
|
@otp_coordinator = otp_coordinator
|
|
112
112
|
end
|
|
113
113
|
|
|
114
|
-
def call(member:, phase:, command:, env: {}, interactive: false)
|
|
114
|
+
def call(member:, phase:, command:, env: {}, interactive: false, stdout_line_handler: nil)
|
|
115
115
|
argv = command_argv(member: member, command: command, env: env)
|
|
116
116
|
process_env = process_env(member: member, env: env)
|
|
117
117
|
spawn_options = process_options
|
|
@@ -120,6 +120,8 @@ module Kettle
|
|
|
120
120
|
started = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
121
121
|
stdout, stderr, status = if interactive
|
|
122
122
|
run_interactive(env: process_env, argv: argv, chdir: member.root, member_name: member.name, process_options: spawn_options)
|
|
123
|
+
elsif stdout_line_handler
|
|
124
|
+
run_streaming(env: process_env, argv: argv, chdir: member.root, process_options: spawn_options, stdout_line_handler: stdout_line_handler)
|
|
123
125
|
else
|
|
124
126
|
Open3.capture3(process_env, *argv, chdir: member.root, **spawn_options)
|
|
125
127
|
end
|
|
@@ -145,6 +147,41 @@ module Kettle
|
|
|
145
147
|
|
|
146
148
|
attr_reader :execute, :accept, :gem_signing_password, :otp_coordinator
|
|
147
149
|
|
|
150
|
+
def run_streaming(env:, argv:, chdir:, process_options:, stdout_line_handler:)
|
|
151
|
+
captured_stdout = +""
|
|
152
|
+
captured_stderr = +""
|
|
153
|
+
stdout_line_buffer = +""
|
|
154
|
+
status = nil
|
|
155
|
+
Open3.popen3(env, *argv, chdir: chdir, **process_options) do |_input, output, error, wait_thread|
|
|
156
|
+
readers = [output, error]
|
|
157
|
+
until readers.empty?
|
|
158
|
+
ready = IO.select(readers)
|
|
159
|
+
ready.first.each do |reader|
|
|
160
|
+
if reader.equal?(output)
|
|
161
|
+
chunk = reader.readpartial(1024)
|
|
162
|
+
captured_stdout << chunk
|
|
163
|
+
stdout_line_buffer = stream_stdout_lines(stdout_line_buffer, chunk, stdout_line_handler)
|
|
164
|
+
else
|
|
165
|
+
captured_stderr << reader.readpartial(1024)
|
|
166
|
+
end
|
|
167
|
+
rescue EOFError
|
|
168
|
+
readers.delete(reader)
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
stdout_line_handler.call(stdout_line_buffer) unless stdout_line_buffer.empty?
|
|
172
|
+
status = wait_thread.value
|
|
173
|
+
end
|
|
174
|
+
[captured_stdout, captured_stderr, status]
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def stream_stdout_lines(buffer, chunk, handler)
|
|
178
|
+
pending = buffer + chunk
|
|
179
|
+
lines = pending.lines
|
|
180
|
+
remainder = pending.end_with?("\n") ? +"" : lines.pop.to_s
|
|
181
|
+
lines.each { |line| handler.call(line.chomp) }
|
|
182
|
+
remainder
|
|
183
|
+
end
|
|
184
|
+
|
|
148
185
|
def run_interactive(env:, argv:, chdir:, member_name:, process_options:)
|
|
149
186
|
return run_interactive_pty(env: env, argv: argv, chdir: chdir, member_name: member_name, process_options: process_options) if pty_available?
|
|
150
187
|
|
data/lib/kettle/family/config.rb
CHANGED
|
@@ -278,9 +278,9 @@ module Kettle
|
|
|
278
278
|
def default_release_disable_local_path_env
|
|
279
279
|
local_envs = %w[
|
|
280
280
|
K_JEM_TEMPLATING
|
|
281
|
-
|
|
281
|
+
STRUCTUREDMERGE_DEV
|
|
282
282
|
TSLP_DEV
|
|
283
|
-
|
|
283
|
+
KETTLE_DEV_DEV
|
|
284
284
|
RUBOCOP_LTS_DEV
|
|
285
285
|
PBOLING_DEV
|
|
286
286
|
GALTZO_FLOSS_DEV
|
|
@@ -125,7 +125,10 @@ module Kettle
|
|
|
125
125
|
latest_released = branch_latest_released(member, state["latest_changelog_version"])
|
|
126
126
|
return state unless latest_released
|
|
127
127
|
|
|
128
|
-
state.merge(
|
|
128
|
+
state.merge(
|
|
129
|
+
"latest_released" => latest_released,
|
|
130
|
+
"ahead" => commits_ahead_of_release(member.root, latest_released)
|
|
131
|
+
)
|
|
129
132
|
rescue ArgumentError
|
|
130
133
|
state
|
|
131
134
|
end
|
|
@@ -160,6 +163,25 @@ module Kettle
|
|
|
160
163
|
Gem::Version.new(value)
|
|
161
164
|
end
|
|
162
165
|
|
|
166
|
+
def commits_ahead_of_release(root, version)
|
|
167
|
+
tag = release_tag_for_version(root, version)
|
|
168
|
+
return nil unless tag && git_ref_exists?(root, "HEAD")
|
|
169
|
+
|
|
170
|
+
stdout, _stderr, status = Open3.capture3("git", "rev-list", "--count", "#{tag}..HEAD", chdir: root)
|
|
171
|
+
status.success? ? stdout.to_i : nil
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def release_tag_for_version(root, version)
|
|
175
|
+
return nil if version.to_s.empty?
|
|
176
|
+
|
|
177
|
+
["v#{version}", version.to_s].find { |tag| git_ref_exists?(root, "refs/tags/#{tag}^{commit}") }
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def git_ref_exists?(root, ref)
|
|
181
|
+
_stdout, _stderr, status = Open3.capture3("git", "rev-parse", "--verify", "--quiet", ref, chdir: root)
|
|
182
|
+
status.success?
|
|
183
|
+
end
|
|
184
|
+
|
|
163
185
|
def family_changelog_state(root)
|
|
164
186
|
changelog = File.expand_path(config.changelog_path, root)
|
|
165
187
|
raise Error, "missing root changelog #{config.changelog_path}" unless File.file?(changelog)
|
|
@@ -169,11 +191,13 @@ module Kettle
|
|
|
169
191
|
latest_changelog_version = latest_changelog_version(content)
|
|
170
192
|
unreleased_entries = unreleased_entries?(content)
|
|
171
193
|
prepared_release_pending = !version.to_s.empty? && latest_changelog_version == version
|
|
194
|
+
ahead = commits_ahead_of_release(root, latest_changelog_version)
|
|
172
195
|
{
|
|
173
196
|
"gem_name" => config.family_name,
|
|
174
197
|
"version" => version,
|
|
175
198
|
"latest_released" => nil,
|
|
176
199
|
"latest_changelog_version" => latest_changelog_version,
|
|
200
|
+
"ahead" => ahead,
|
|
177
201
|
"unreleased_entries" => unreleased_entries,
|
|
178
202
|
"prepared_release_pending" => prepared_release_pending,
|
|
179
203
|
"pending_release" => unreleased_entries || prepared_release_pending
|
data/lib/kettle/family/report.rb
CHANGED
|
@@ -316,6 +316,7 @@ module Kettle
|
|
|
316
316
|
state.fetch("version", "unknown").to_s,
|
|
317
317
|
state.fetch("latest_released", nil).to_s.empty? ? "unknown" : state.fetch("latest_released").to_s,
|
|
318
318
|
state.fetch("latest_changelog_version", nil).to_s.empty? ? "none" : state.fetch("latest_changelog_version").to_s,
|
|
319
|
+
state.fetch("ahead", nil).nil? ? "unknown" : state.fetch("ahead").to_s,
|
|
319
320
|
yes_no(state.fetch("unreleased_entries", nil)),
|
|
320
321
|
yes_no(state.fetch("prepared_release_pending", nil)),
|
|
321
322
|
yes_no(state.fetch("pending_release", nil))
|
|
@@ -326,7 +327,7 @@ module Kettle
|
|
|
326
327
|
end
|
|
327
328
|
|
|
328
329
|
def release_state_header
|
|
329
|
-
header = [["gem", "version.rb", "latest released", "latest changelog", "unreleased", "prepared", "pending"]]
|
|
330
|
+
header = [["gem", "version.rb", "latest released", "latest changelog", "ahead", "unreleased", "prepared", "pending"]]
|
|
330
331
|
return header unless release_state_has_branches?
|
|
331
332
|
|
|
332
333
|
[["branch", *header.first]]
|
|
@@ -3,8 +3,23 @@
|
|
|
3
3
|
module Kettle
|
|
4
4
|
module Family
|
|
5
5
|
class Selection
|
|
6
|
-
|
|
6
|
+
STATUS_TOKEN_KEYS = {
|
|
7
|
+
"unreleased" => "unreleased_entries",
|
|
8
|
+
"prepared" => "prepared_release_pending",
|
|
9
|
+
"pending" => "pending_release"
|
|
10
|
+
}.freeze
|
|
11
|
+
|
|
12
|
+
def self.status_tokens
|
|
13
|
+
STATUS_TOKEN_KEYS.keys
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.status_token?(value)
|
|
17
|
+
STATUS_TOKEN_KEYS.key?(value.to_s)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def initialize(members:, release_state_results: nil)
|
|
7
21
|
@members = members
|
|
22
|
+
@release_state_results = release_state_results
|
|
8
23
|
end
|
|
9
24
|
|
|
10
25
|
def apply(only: nil, exclude: nil, start_at: nil)
|
|
@@ -19,12 +34,20 @@ module Kettle
|
|
|
19
34
|
|
|
20
35
|
private
|
|
21
36
|
|
|
22
|
-
attr_reader :members
|
|
37
|
+
attr_reader :members, :release_state_results
|
|
23
38
|
|
|
24
39
|
def select_only(selected, only)
|
|
25
40
|
names = only.split(",").map(&:strip).reject(&:empty?)
|
|
26
41
|
raise Error, "--only requires at least one member" if names.empty?
|
|
27
42
|
|
|
43
|
+
status_tokens = names.select { |name| self.class.status_token?(name) }
|
|
44
|
+
unless status_tokens.empty?
|
|
45
|
+
member_names = names - status_tokens
|
|
46
|
+
raise Error, "--only release-state tokens cannot be combined with member names: #{member_names.join(", ")}" unless member_names.empty?
|
|
47
|
+
|
|
48
|
+
return select_release_state_status(selected, status_tokens)
|
|
49
|
+
end
|
|
50
|
+
|
|
28
51
|
unknown = names - members.map(&:name)
|
|
29
52
|
raise Error, "unknown member(s): #{unknown.join(", ")}" unless unknown.empty?
|
|
30
53
|
|
|
@@ -47,6 +70,29 @@ module Kettle
|
|
|
47
70
|
|
|
48
71
|
selected.drop(index)
|
|
49
72
|
end
|
|
73
|
+
|
|
74
|
+
def select_release_state_status(selected, status_tokens)
|
|
75
|
+
results_by_member = release_state_results_by_member
|
|
76
|
+
failed = results_by_member.values.select { |result| !result.ok? }
|
|
77
|
+
raise Error, "release-state check failed for: #{failed.map(&:member_name).join(", ")}" unless failed.empty?
|
|
78
|
+
|
|
79
|
+
selected.select do |candidate|
|
|
80
|
+
result = results_by_member[candidate.name]
|
|
81
|
+
result && status_tokens.all? { |token| truthy_state?(result.state[STATUS_TOKEN_KEYS.fetch(token)]) }
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def release_state_results_by_member
|
|
86
|
+
raise Error, "--only release-state tokens require release-state results" unless release_state_results
|
|
87
|
+
|
|
88
|
+
release_state_results.each_with_object({}) do |result, memo|
|
|
89
|
+
memo[result.member_name] = result
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def truthy_state?(value)
|
|
94
|
+
value == true
|
|
95
|
+
end
|
|
50
96
|
end
|
|
51
97
|
end
|
|
52
98
|
end
|
|
@@ -7,12 +7,13 @@ module Kettle
|
|
|
7
7
|
class VersionBump
|
|
8
8
|
DEPENDENCY_METHODS = %i[add_dependency add_runtime_dependency].freeze
|
|
9
9
|
|
|
10
|
-
def initialize(members:, target_version:, from_version: nil, mode: :dry_run)
|
|
10
|
+
def initialize(members:, target_version:, from_version: nil, mode: :dry_run, phase: "bump-version")
|
|
11
11
|
@members = members
|
|
12
12
|
@target_version = target_version.to_s
|
|
13
13
|
@explicit_target_version = validate_version(target_version) unless Kettle::Dev::VersionBump::BUMP_TYPES.include?(@target_version)
|
|
14
14
|
@from_version = validate_version(from_version) if from_version
|
|
15
15
|
@mode = mode
|
|
16
|
+
@phase = phase
|
|
16
17
|
@member_names = members.map(&:name)
|
|
17
18
|
@member_target_versions = members.each_with_object({}) do |member, memo|
|
|
18
19
|
memo[member.name] = resolve_target_version(member)
|
|
@@ -25,7 +26,7 @@ module Kettle
|
|
|
25
26
|
|
|
26
27
|
private
|
|
27
28
|
|
|
28
|
-
attr_reader :members, :target_version, :explicit_target_version, :from_version, :mode, :member_names, :member_target_versions
|
|
29
|
+
attr_reader :members, :target_version, :explicit_target_version, :from_version, :mode, :phase, :member_names, :member_target_versions
|
|
29
30
|
|
|
30
31
|
def validate_version(version)
|
|
31
32
|
with_dev_errors { Kettle::Dev::VersionBump.validate_version(version) }
|
|
@@ -39,8 +40,8 @@ module Kettle
|
|
|
39
40
|
write_edits(edits) if mode == :execute
|
|
40
41
|
CommandResult.new(
|
|
41
42
|
member_name: member.name,
|
|
42
|
-
phase:
|
|
43
|
-
command: ["internal",
|
|
43
|
+
phase: phase,
|
|
44
|
+
command: ["internal", phase, member_target_version],
|
|
44
45
|
workdir: member.root,
|
|
45
46
|
status: check_failed?(edits) ? 1 : 0,
|
|
46
47
|
success: !check_failed?(edits),
|
|
@@ -27,7 +27,7 @@ module Kettle
|
|
|
27
27
|
"KETTLE_JEM_QUIET" => "true",
|
|
28
28
|
"KETTLE_JEM_DEBUG" => "false",
|
|
29
29
|
"KETTLE_DEV_DEBUG" => "false",
|
|
30
|
-
"
|
|
30
|
+
"STRUCTUREDMERGE_DEBUG" => "false",
|
|
31
31
|
"DEBUG" => nil,
|
|
32
32
|
"BUNDLE_QUIET" => "true",
|
|
33
33
|
"BUNDLE_DEBUG" => "false",
|
|
@@ -46,7 +46,7 @@ module Kettle
|
|
|
46
46
|
REGISTRY_WAIT_ATTEMPTS = 15
|
|
47
47
|
REGISTRY_WAIT_INTERVAL_SECONDS = 15
|
|
48
48
|
|
|
49
|
-
def initialize(command:, config:, members:, execute: false, accept: true, commit: true, allow_dirty: false, publish: false, push: false, tag: false, start_step: nil, skip_steps: nil, local_ci: false, continue_ci_failures: false, ci_workflows: nil, skip_bundle_audit: false, auto_dependency_floors: nil, gha_sha_pins_upgrade: "patch", gha_sha_pins_check: false, env_overrides: {}, debug: false, gem_signing_password: nil, jobs: nil, progress_io: nil, bup_args: [], bex_args: [], start_member: nil, start_branch: nil, **options)
|
|
49
|
+
def initialize(command:, config:, members:, execute: false, accept: true, commit: true, allow_dirty: false, publish: false, push: false, tag: false, start_step: nil, skip_steps: nil, local_ci: false, continue_ci_failures: false, ci_workflows: nil, skip_bundle_audit: false, skip_remotes: nil, auto_dependency_floors: nil, gha_sha_pins_upgrade: "patch", gha_sha_pins_check: false, env_overrides: {}, debug: false, verbose: false, gem_signing_password: nil, jobs: nil, progress_io: nil, bup_args: [], bex_args: [], start_member: nil, start_branch: nil, **options)
|
|
50
50
|
@command = command
|
|
51
51
|
@config = config
|
|
52
52
|
@members = members
|
|
@@ -63,11 +63,13 @@ module Kettle
|
|
|
63
63
|
@continue_ci_failures = continue_ci_failures
|
|
64
64
|
@ci_workflows = validate_ci_workflows(ci_workflows)
|
|
65
65
|
@skip_bundle_audit = skip_bundle_audit
|
|
66
|
+
@skip_remotes = validate_skip_remotes(skip_remotes)
|
|
66
67
|
@auto_dependency_floors = auto_dependency_floors.nil? ? config.release_auto_dependency_floors? : auto_dependency_floors
|
|
67
68
|
@gha_sha_pins_upgrade = gha_sha_pins_upgrade
|
|
68
69
|
@gha_sha_pins_check = gha_sha_pins_check
|
|
69
70
|
@env_overrides = env_overrides
|
|
70
71
|
@debug = debug
|
|
72
|
+
@verbose = verbose
|
|
71
73
|
@gem_signing_password = gem_signing_password
|
|
72
74
|
@jobs = jobs
|
|
73
75
|
@progress_io = progress_io
|
|
@@ -90,7 +92,7 @@ module Kettle
|
|
|
90
92
|
|
|
91
93
|
private
|
|
92
94
|
|
|
93
|
-
attr_reader :command, :config, :members, :execute, :accept, :commit, :allow_dirty, :publish, :push, :tag, :start_step, :skip_steps, :local_ci, :continue_ci_failures, :ci_workflows, :skip_bundle_audit, :auto_dependency_floors, :gha_sha_pins_upgrade, :gha_sha_pins_check, :env_overrides, :debug, :jobs, :progress_io, :bup_args, :bex_args, :start_member, :start_branch
|
|
95
|
+
attr_reader :command, :config, :members, :execute, :accept, :commit, :allow_dirty, :publish, :push, :tag, :start_step, :skip_steps, :local_ci, :continue_ci_failures, :ci_workflows, :skip_bundle_audit, :skip_remotes, :auto_dependency_floors, :gha_sha_pins_upgrade, :gha_sha_pins_check, :env_overrides, :debug, :verbose, :jobs, :progress_io, :bup_args, :bex_args, :start_member, :start_branch
|
|
94
96
|
|
|
95
97
|
def current_branch_results(workflow_members)
|
|
96
98
|
return check_results(workflow_members) if command == "check"
|
|
@@ -101,7 +103,7 @@ module Kettle
|
|
|
101
103
|
end
|
|
102
104
|
|
|
103
105
|
def member_workflow_results(workflow_members)
|
|
104
|
-
return template_member_workflow_results(workflow_members) if command == "template" && execute
|
|
106
|
+
return template_member_workflow_results(workflow_members) if command == "template" && execute
|
|
105
107
|
|
|
106
108
|
runner = CommandRunner.new(execute: execute, accept: accept)
|
|
107
109
|
workflow_members.each_with_object([]) do |member, memo|
|
|
@@ -110,6 +112,11 @@ module Kettle
|
|
|
110
112
|
break memo unless memo.last.ok?
|
|
111
113
|
end
|
|
112
114
|
|
|
115
|
+
if command == "template"
|
|
116
|
+
prepared = prepare_template_dependencies(member: member, runner: runner, memo: memo)
|
|
117
|
+
break memo if prepared == false
|
|
118
|
+
end
|
|
119
|
+
|
|
113
120
|
command_text = workflow_command(member)
|
|
114
121
|
result = runner.call(member: member, phase: command, command: command_text, env: workflow_env)
|
|
115
122
|
memo << result
|
|
@@ -158,7 +165,16 @@ module Kettle
|
|
|
158
165
|
return memo unless memo.last.ok?
|
|
159
166
|
end
|
|
160
167
|
|
|
161
|
-
|
|
168
|
+
prepared = prepare_template_dependencies(member: member, runner: runner, memo: memo)
|
|
169
|
+
return memo if prepared == false
|
|
170
|
+
|
|
171
|
+
memo << runner.call(
|
|
172
|
+
member: member,
|
|
173
|
+
phase: command,
|
|
174
|
+
command: workflow_command(member),
|
|
175
|
+
env: workflow_env,
|
|
176
|
+
stdout_line_handler: template_event_line_handler(member)
|
|
177
|
+
)
|
|
162
178
|
return memo unless memo.last.ok?
|
|
163
179
|
|
|
164
180
|
normalize_lockfiles(member: member, runner: runner, memo: memo, phase: "normalize_lockfiles")
|
|
@@ -646,6 +662,7 @@ module Kettle
|
|
|
646
662
|
args << "--ci-workflows=#{ci_workflows}" if ci_workflows && !ci_workflows.to_s.empty?
|
|
647
663
|
args << "--local-ci" if local_ci
|
|
648
664
|
args << "--skip-bundle-audit" if skip_bundle_audit
|
|
665
|
+
args << "--skip-remotes=#{skip_remotes}" if skip_remotes && !skip_remotes.to_s.empty?
|
|
649
666
|
return command if args.empty?
|
|
650
667
|
|
|
651
668
|
command.is_a?(Array) ? [*command, *args] : "#{command} #{args.join(" ")}"
|
|
@@ -661,6 +678,16 @@ module Kettle
|
|
|
661
678
|
workflows.join(",")
|
|
662
679
|
end
|
|
663
680
|
|
|
681
|
+
def validate_skip_remotes(value)
|
|
682
|
+
return nil if value.nil? || value.to_s.empty?
|
|
683
|
+
|
|
684
|
+
remotes = value.to_s.split(",").map(&:strip)
|
|
685
|
+
invalid = remotes.find { |remote| remote.empty? || !remote.match?(/\A[A-Za-z0-9_.-]+\z/) }
|
|
686
|
+
raise Error, "invalid --skip-remotes value #{value.inspect}" if invalid
|
|
687
|
+
|
|
688
|
+
remotes.join(",")
|
|
689
|
+
end
|
|
690
|
+
|
|
664
691
|
def release_env
|
|
665
692
|
env = base_release_env
|
|
666
693
|
env.merge!(env_overrides)
|
|
@@ -674,6 +701,7 @@ module Kettle
|
|
|
674
701
|
env["K_RELEASE_CI_CONTINUE"] = "true" if continue_ci_failures
|
|
675
702
|
env["K_RELEASE_CI_WORKFLOWS"] = ci_workflows if ci_workflows && !ci_workflows.to_s.empty?
|
|
676
703
|
env["KETTLE_DEV_SKIP_BUNDLE_AUDIT"] = "true" if skip_bundle_audit
|
|
704
|
+
env["K_RELEASE_SKIP_REMOTES"] = skip_remotes if skip_remotes && !skip_remotes.to_s.empty?
|
|
677
705
|
env
|
|
678
706
|
end
|
|
679
707
|
|
|
@@ -886,6 +914,16 @@ module Kettle
|
|
|
886
914
|
def template_command(member)
|
|
887
915
|
command_text = config.template_command || default_template_command(member)
|
|
888
916
|
command_text = append_template_family_args(command_text) if kettle_jem_template_command?(command_text)
|
|
917
|
+
append_template_skip_commit(command_text)
|
|
918
|
+
end
|
|
919
|
+
|
|
920
|
+
def template_prepare_command(member)
|
|
921
|
+
command_text = "kettle-jem prepare"
|
|
922
|
+
command_text = append_template_family_args(command_text)
|
|
923
|
+
append_template_skip_commit(command_text)
|
|
924
|
+
end
|
|
925
|
+
|
|
926
|
+
def append_template_skip_commit(command_text)
|
|
889
927
|
return command_text if commit
|
|
890
928
|
return command_text if command_text.is_a?(Array) && command_text.include?("--skip-commit")
|
|
891
929
|
return [*command_text, "--skip-commit"] if command_text.is_a?(Array)
|
|
@@ -916,7 +954,11 @@ module Kettle
|
|
|
916
954
|
env["KJ_REPOSITORY_TOPOLOGY"] = config.template_repository_topology if config.template_repository_topology
|
|
917
955
|
end
|
|
918
956
|
env.merge!(env_overrides)
|
|
919
|
-
|
|
957
|
+
if command == "template" && verbose
|
|
958
|
+
env["KETTLE_JEM_VERBOSE"] = "true"
|
|
959
|
+
elsif command == "template" && !debug
|
|
960
|
+
env.merge!(TEMPLATE_QUIET_ENV)
|
|
961
|
+
end
|
|
920
962
|
end
|
|
921
963
|
end
|
|
922
964
|
|
|
@@ -926,8 +968,12 @@ module Kettle
|
|
|
926
968
|
|
|
927
969
|
def append_template_family_args(command_text)
|
|
928
970
|
args = []
|
|
929
|
-
|
|
930
|
-
|
|
971
|
+
if verbose
|
|
972
|
+
args << "--verbose" unless command_includes_arg?(command_text, "--verbose")
|
|
973
|
+
else
|
|
974
|
+
args << "--quiet" unless command_includes_arg?(command_text, "--quiet")
|
|
975
|
+
end
|
|
976
|
+
args << "--events" unless command_includes_arg?(command_text, "--events")
|
|
931
977
|
append_command_args(command_text, args)
|
|
932
978
|
end
|
|
933
979
|
|
|
@@ -946,6 +992,72 @@ module Kettle
|
|
|
946
992
|
progress_io.flush if progress_io.respond_to?(:flush)
|
|
947
993
|
end
|
|
948
994
|
|
|
995
|
+
def template_event_line_handler(member)
|
|
996
|
+
return nil unless progress_io
|
|
997
|
+
|
|
998
|
+
lambda do |line|
|
|
999
|
+
event = parse_template_event(line)
|
|
1000
|
+
next unless event
|
|
1001
|
+
|
|
1002
|
+
emit_template_event_progress(member, event)
|
|
1003
|
+
end
|
|
1004
|
+
end
|
|
1005
|
+
|
|
1006
|
+
def parse_template_event(line)
|
|
1007
|
+
payload = JSON.parse(line.to_s)
|
|
1008
|
+
(payload.is_a?(Hash) && payload["event_version"]) ? payload : nil
|
|
1009
|
+
rescue JSON::ParserError
|
|
1010
|
+
nil
|
|
1011
|
+
end
|
|
1012
|
+
|
|
1013
|
+
def emit_template_event_progress(member, event)
|
|
1014
|
+
case event["type"]
|
|
1015
|
+
when "phase_start"
|
|
1016
|
+
emit_template_event_line(member, ">", event["phase"].to_s)
|
|
1017
|
+
when "phase_finish"
|
|
1018
|
+
emit_template_event_line(member, phase_finish_event_mark(event), event["phase"].to_s)
|
|
1019
|
+
when "recipe"
|
|
1020
|
+
path = event["path"].to_s
|
|
1021
|
+
emit_template_event_line(member, template_event_mark(event, changed_mark: "*"), path)
|
|
1022
|
+
when "post_apply_step", "command_step"
|
|
1023
|
+
label = [event["phase"], event["name"]].map(&:to_s).reject(&:empty?).join(":")
|
|
1024
|
+
emit_template_event_line(member, template_event_mark(event), label)
|
|
1025
|
+
when "diagnostic"
|
|
1026
|
+
message = event["message"].to_s
|
|
1027
|
+
label = message.empty? ? event["kind"].to_s : message
|
|
1028
|
+
emit_template_event_line(member, "!", label)
|
|
1029
|
+
when "summary"
|
|
1030
|
+
emit_template_event_line(member, "done", "#{event["changed_count"].to_i} file#{"s" unless event["changed_count"].to_i == 1} changed")
|
|
1031
|
+
end
|
|
1032
|
+
end
|
|
1033
|
+
|
|
1034
|
+
def emit_template_event_line(member, mark, label)
|
|
1035
|
+
return if label.to_s.empty?
|
|
1036
|
+
|
|
1037
|
+
synchronize_template_progress do
|
|
1038
|
+
progress_io.puts("[#{member.name}] #{mark} #{label}")
|
|
1039
|
+
progress_io.flush if progress_io.respond_to?(:flush)
|
|
1040
|
+
end
|
|
1041
|
+
end
|
|
1042
|
+
|
|
1043
|
+
def template_event_mark(event, changed_mark: ".")
|
|
1044
|
+
mark = event["mark"].to_s
|
|
1045
|
+
return mark unless mark.empty?
|
|
1046
|
+
|
|
1047
|
+
event["changed"] ? changed_mark : "."
|
|
1048
|
+
end
|
|
1049
|
+
|
|
1050
|
+
def phase_finish_event_mark(event)
|
|
1051
|
+
return "F" if event["status"].to_s == "failed"
|
|
1052
|
+
|
|
1053
|
+
"."
|
|
1054
|
+
end
|
|
1055
|
+
|
|
1056
|
+
def synchronize_template_progress(&block)
|
|
1057
|
+
@template_progress_mutex ||= Mutex.new
|
|
1058
|
+
@template_progress_mutex.synchronize(&block)
|
|
1059
|
+
end
|
|
1060
|
+
|
|
949
1061
|
def emit_template_progress_summary(results)
|
|
950
1062
|
return unless progress_io
|
|
951
1063
|
|
|
@@ -957,6 +1069,9 @@ module Kettle
|
|
|
957
1069
|
end
|
|
958
1070
|
|
|
959
1071
|
def template_changed_file_count(result)
|
|
1072
|
+
event_count = template_changed_file_count_from_events(result.stdout)
|
|
1073
|
+
return event_count if event_count
|
|
1074
|
+
|
|
960
1075
|
payload = JSON.parse(result.stdout.to_s)
|
|
961
1076
|
Array(payload["changed_files"] || payload[:changed_files]).length if payload.is_a?(Hash)
|
|
962
1077
|
rescue JSON::ParserError
|
|
@@ -966,6 +1081,16 @@ module Kettle
|
|
|
966
1081
|
0
|
|
967
1082
|
end
|
|
968
1083
|
|
|
1084
|
+
def template_changed_file_count_from_events(output)
|
|
1085
|
+
summaries = output.to_s.lines.filter_map do |line|
|
|
1086
|
+
event = parse_template_event(line)
|
|
1087
|
+
event if event && event["type"] == "summary"
|
|
1088
|
+
end
|
|
1089
|
+
return nil if summaries.empty?
|
|
1090
|
+
|
|
1091
|
+
summaries.last["changed_count"].to_i
|
|
1092
|
+
end
|
|
1093
|
+
|
|
969
1094
|
def normalize_lockfiles(member:, runner:, memo:, phase:)
|
|
970
1095
|
return unless config.normalize_lockfiles?
|
|
971
1096
|
|
|
@@ -978,6 +1103,27 @@ module Kettle
|
|
|
978
1103
|
memo << result
|
|
979
1104
|
end
|
|
980
1105
|
|
|
1106
|
+
def prepare_template_dependencies(member:, runner:, memo:)
|
|
1107
|
+
command_text = config.template_command || default_template_command(member)
|
|
1108
|
+
return true unless kettle_jem_template_command?(command_text)
|
|
1109
|
+
|
|
1110
|
+
result = runner.call(
|
|
1111
|
+
member: member,
|
|
1112
|
+
phase: "prepare_template_dependencies",
|
|
1113
|
+
command: template_prepare_command(member),
|
|
1114
|
+
env: template_prepare_env
|
|
1115
|
+
)
|
|
1116
|
+
memo << result
|
|
1117
|
+
result.ok?
|
|
1118
|
+
end
|
|
1119
|
+
|
|
1120
|
+
def template_prepare_env
|
|
1121
|
+
env = workflow_env
|
|
1122
|
+
family_env_name = config.family_local_path_env_name
|
|
1123
|
+
env[family_env_name] = "false" if family_env_name && !env_overrides.key?(family_env_name)
|
|
1124
|
+
env
|
|
1125
|
+
end
|
|
1126
|
+
|
|
981
1127
|
def normalize_release_lockfiles(member:, runner:, memo:)
|
|
982
1128
|
result = runner.call(
|
|
983
1129
|
member: member,
|
data/sig/kettle/family.rbs
CHANGED
|
@@ -1,68 +1,5 @@
|
|
|
1
1
|
module Kettle
|
|
2
2
|
module Family
|
|
3
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
4
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
5
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
6
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
7
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
8
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
9
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
10
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
11
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
12
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
13
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
14
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
15
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
16
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
17
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
18
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
19
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
20
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
21
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
22
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
23
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
24
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
25
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
26
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
27
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
28
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
29
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
30
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
31
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
32
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
33
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
34
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
35
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
36
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
37
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
38
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
39
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
40
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
41
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
42
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
43
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
44
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
45
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
46
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
47
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
48
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
49
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
50
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
51
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
52
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
53
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
54
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
55
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
56
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
57
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
58
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
59
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
60
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
61
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
62
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
63
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
64
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
65
|
-
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
66
3
|
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
|
67
4
|
module Version
|
|
68
5
|
VERSION: String
|
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: 1.0.
|
|
4
|
+
version: 1.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter H. Boling
|
|
@@ -173,40 +173,40 @@ dependencies:
|
|
|
173
173
|
requirements:
|
|
174
174
|
- - "~>"
|
|
175
175
|
- !ruby/object:Gem::Version
|
|
176
|
-
version: '3.
|
|
176
|
+
version: '3.2'
|
|
177
177
|
- - ">="
|
|
178
178
|
- !ruby/object:Gem::Version
|
|
179
|
-
version: 3.
|
|
179
|
+
version: 3.2.0
|
|
180
180
|
type: :development
|
|
181
181
|
prerelease: false
|
|
182
182
|
version_requirements: !ruby/object:Gem::Requirement
|
|
183
183
|
requirements:
|
|
184
184
|
- - "~>"
|
|
185
185
|
- !ruby/object:Gem::Version
|
|
186
|
-
version: '3.
|
|
186
|
+
version: '3.2'
|
|
187
187
|
- - ">="
|
|
188
188
|
- !ruby/object:Gem::Version
|
|
189
|
-
version: 3.
|
|
189
|
+
version: 3.2.0
|
|
190
190
|
- !ruby/object:Gem::Dependency
|
|
191
191
|
name: turbo_tests2
|
|
192
192
|
requirement: !ruby/object:Gem::Requirement
|
|
193
193
|
requirements:
|
|
194
194
|
- - "~>"
|
|
195
195
|
- !ruby/object:Gem::Version
|
|
196
|
-
version: '3.
|
|
196
|
+
version: '3.2'
|
|
197
197
|
- - ">="
|
|
198
198
|
- !ruby/object:Gem::Version
|
|
199
|
-
version: 3.
|
|
199
|
+
version: 3.2.0
|
|
200
200
|
type: :development
|
|
201
201
|
prerelease: false
|
|
202
202
|
version_requirements: !ruby/object:Gem::Requirement
|
|
203
203
|
requirements:
|
|
204
204
|
- - "~>"
|
|
205
205
|
- !ruby/object:Gem::Version
|
|
206
|
-
version: '3.
|
|
206
|
+
version: '3.2'
|
|
207
207
|
- - ">="
|
|
208
208
|
- !ruby/object:Gem::Version
|
|
209
|
-
version: 3.
|
|
209
|
+
version: 3.2.0
|
|
210
210
|
- !ruby/object:Gem::Dependency
|
|
211
211
|
name: ruby-progressbar
|
|
212
212
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -303,10 +303,10 @@ licenses:
|
|
|
303
303
|
- AGPL-3.0-only
|
|
304
304
|
metadata:
|
|
305
305
|
homepage_uri: https://kettle-family.galtzo.com
|
|
306
|
-
source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v1.0.
|
|
307
|
-
changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v1.0.
|
|
306
|
+
source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v1.0.1
|
|
307
|
+
changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v1.0.1/CHANGELOG.md
|
|
308
308
|
bug_tracker_uri: https://github.com/kettle-dev/kettle-family/issues
|
|
309
|
-
documentation_uri: https://www.rubydoc.info/gems/kettle-family/1.0.
|
|
309
|
+
documentation_uri: https://www.rubydoc.info/gems/kettle-family/1.0.1
|
|
310
310
|
funding_uri: https://github.com/sponsors/pboling
|
|
311
311
|
wiki_uri: https://github.com/kettle-dev/kettle-family/wiki
|
|
312
312
|
news_uri: https://www.railsbling.com/tags/kettle-family
|
metadata.gz.sig
CHANGED
|
Binary file
|