kettle-family 1.0.1 → 1.0.2
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 +42 -3
- data/README.md +4 -2
- data/lib/kettle/family/cli.rb +20 -2
- data/lib/kettle/family/config.rb +31 -0
- data/lib/kettle/family/release_state_check.rb +70 -2
- data/lib/kettle/family/report.rb +63 -3
- data/lib/kettle/family/version.rb +1 -1
- data/lib/kettle/family/workflow.rb +35 -0
- data.tar.gz.sig +0 -0
- metadata +4 -4
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 19486d91816150dae28ac5f1e8b31ef3f43b0f4f7004337681f08819fb41b27d
|
|
4
|
+
data.tar.gz: e2bf61a97f739f211accb4fc5cbfe91acc4121077c5f620786d30d217b4cc803
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e8826e083336b3de83e313fc3207c60461e494fc8c1c4ad22b8148b861024ca78adcefa1b5c357d7ed90af79dddb3cda59dc4900434e862739d8d2f930e8e0c3
|
|
7
|
+
data.tar.gz: 1d735e6c84877eab971381d22226c96871e2fa0198bab1d9895bf771abdbbe2d5bf2c69a0d16bd04c0a3cdfdc830c7e7354f526313a5f0b8dbeec2a96df7d908
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/CHANGELOG.md
CHANGED
|
@@ -28,11 +28,48 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
28
28
|
|
|
29
29
|
### Fixed
|
|
30
30
|
|
|
31
|
+
### Security
|
|
32
|
+
|
|
33
|
+
## [1.0.2] - 2026-07-21
|
|
34
|
+
|
|
35
|
+
- TAG: [v1.0.2][1.0.2t]
|
|
36
|
+
- COVERAGE: 95.51% -- 2637/2761 lines in 23 files
|
|
37
|
+
- BRANCH COVERAGE: 77.98% -- 928/1190 branches in 23 files
|
|
38
|
+
- 28.63% documented
|
|
39
|
+
|
|
40
|
+
### Added
|
|
41
|
+
|
|
42
|
+
- `kettle-family template` now passes family-level `readme.corporate_sponsors`
|
|
43
|
+
config into member `kettle-jem` runs for template-managed README sponsor logos.
|
|
44
|
+
- `kettle-family state` is now an alias for `kettle-family release-state`.
|
|
45
|
+
- `kettle-family sync` now fetches the remote default branch, rebases the local
|
|
46
|
+
default branch onto it, then rebases the original checked-out branch onto the
|
|
47
|
+
updated local default branch.
|
|
48
|
+
|
|
49
|
+
### Changed
|
|
50
|
+
|
|
51
|
+
- `kettle-family release-state` now reports the checked-out branch and displays
|
|
52
|
+
release distance as local/remote ahead and behind counts.
|
|
53
|
+
- kettle-jem-template-20260720-001 - Generated READMEs can now render
|
|
54
|
+
template-managed corporate sponsor logos from project or family config.
|
|
55
|
+
- kettle-jem-template-20260720-002 - Generated development Gemfiles now use the
|
|
56
|
+
released `tree_sitter_language_pack` gem 1.13.3 or newer by default.
|
|
57
|
+
- kettle-jem-template-20260720-003 - Generated StructuredMerge Git diff driver
|
|
58
|
+
config now uses the installed `smorg-rb` Ruby driver name.
|
|
59
|
+
- kettle-jem-template-20260720-004 - Generated multi-engine workflow files now
|
|
60
|
+
omit JRuby and TruffleRuby jobs when project config declares MRI-only engines.
|
|
61
|
+
- kettle-jem-template-20260720-005 - Generated README Support & Community rows
|
|
62
|
+
now include a RubyForum help badge.
|
|
63
|
+
|
|
64
|
+
### Fixed
|
|
65
|
+
|
|
66
|
+
- Default member discovery now excludes benchmark fixture gemspecs so benchmark
|
|
67
|
+
projects are not treated as install/template/release family members.
|
|
68
|
+
- `kettle-family template` now keeps non-verbose `kettle-jem --events` progress
|
|
69
|
+
compact and omits raw NDJSON event streams from failed text reports.
|
|
31
70
|
- Generated HEAD and runtime dependency HEAD CI workflows no longer include
|
|
32
71
|
JRuby or TruffleRuby jobs for this MRI-only gem.
|
|
33
72
|
|
|
34
|
-
### Security
|
|
35
|
-
|
|
36
73
|
## [1.0.1] - 2026-07-20
|
|
37
74
|
|
|
38
75
|
- TAG: [v1.0.1][1.0.1t]
|
|
@@ -786,7 +823,9 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
786
823
|
- Fixed CI load failures on engines without compatible `pty` support by falling back to Open3 for interactive release commands.
|
|
787
824
|
- Fixed Ruby 3.2 version-bump support by loading Prism lazily and wiring the Prism gem only for MRI versions that need it.
|
|
788
825
|
|
|
789
|
-
[Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.0.
|
|
826
|
+
[Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.0.2...HEAD
|
|
827
|
+
[1.0.2]: https://github.com/kettle-dev/kettle-family/compare/v1.0.1...v1.0.2
|
|
828
|
+
[1.0.2t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.0.2
|
|
790
829
|
[1.0.1]: https://github.com/kettle-dev/kettle-family/compare/v1.0.0...v1.0.1
|
|
791
830
|
[1.0.1t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.0.1
|
|
792
831
|
[1.0.0]: https://github.com/kettle-dev/kettle-family/compare/v0.2.7...v1.0.0
|
data/README.md
CHANGED
|
@@ -45,7 +45,7 @@ while RubyGems MFA prompts remain interactive.
|
|
|
45
45
|
| Tokens to Remember | [![Gem name][⛳️name-img]][⛳️gem-name] [![Gem namespace][⛳️namespace-img]][⛳️gem-namespace] |
|
|
46
46
|
|-------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
47
47
|
| Works with MRI Ruby 4 | [![Ruby current Compat][💎ruby-c-i]][🚎11-c-wf] [![Ruby HEAD Compat][💎ruby-headi]][🚎3-hd-wf]|
|
|
48
|
-
| 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] |
|
|
48
|
+
| Support & Community | [![Join Me on Daily.dev's RubyFriends][✉️ruby-friends-img]][✉️ruby-friends] [![Get help from RubyForum][✉️ruby-forum-img]][✉️ruby-forum] [![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] |
|
|
49
49
|
| 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] |
|
|
50
50
|
| 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] |
|
|
51
51
|
| 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] |
|
|
@@ -560,6 +560,8 @@ Thanks for RTFM. ☺️
|
|
|
560
560
|
[✉️discord-invite-img-ftb]: https://img.shields.io/discord/1373797679469170758?style=for-the-badge&logo=discord
|
|
561
561
|
[✉️ruby-friends-img]: https://img.shields.io/badge/daily.dev-%F0%9F%92%8E_Ruby_Friends-0A0A0A?style=for-the-badge&logo=dailydotdev&logoColor=white
|
|
562
562
|
[✉️ruby-friends]: https://app.daily.dev/squads/rubyfriends
|
|
563
|
+
[✉️ruby-forum-img]: https://img.shields.io/badge/RubyForum-Help-CC342D?style=for-the-badge&logo=ruby&logoColor=white
|
|
564
|
+
[✉️ruby-forum]: https://www.rubyforum.org/c/help/8
|
|
563
565
|
|
|
564
566
|
[✇bundle-group-pattern]: https://gist.github.com/pboling/4564780
|
|
565
567
|
[⛳️gem-namespace]: https://github.com/kettle-dev/kettle-family
|
|
@@ -667,7 +669,7 @@ Thanks for RTFM. ☺️
|
|
|
667
669
|
[📌gitmoji]: https://gitmoji.dev
|
|
668
670
|
[📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
669
671
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
670
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-2.
|
|
672
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-2.761-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
|
671
673
|
[🔐security]: https://github.com/kettle-dev/kettle-family/blob/main/SECURITY.md
|
|
672
674
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
|
673
675
|
[📄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,8 +10,8 @@ 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 bump-version add-changelog release push pull up branch-lanes release-state].freeze
|
|
14
|
-
WORKFLOW_COMMANDS = %w[check test lint docs template gha-sha-pins bup bupb bex release push pull up].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 sync up branch-lanes release-state state].freeze
|
|
14
|
+
WORKFLOW_COMMANDS = %w[check test lint docs template gha-sha-pins bup bupb bex release push pull sync up].freeze
|
|
15
15
|
|
|
16
16
|
command_name "kettle-family"
|
|
17
17
|
usage "[options] COMMAND [ARGS...]"
|
|
@@ -254,6 +254,16 @@ module Kettle
|
|
|
254
254
|
end
|
|
255
255
|
end
|
|
256
256
|
|
|
257
|
+
class State < ReleaseState
|
|
258
|
+
command_name "state"
|
|
259
|
+
description "Alias for release-state."
|
|
260
|
+
|
|
261
|
+
def run(*args)
|
|
262
|
+
unexpected_arguments!(args)
|
|
263
|
+
run_family("release-state")
|
|
264
|
+
end
|
|
265
|
+
end
|
|
266
|
+
|
|
257
267
|
class WorkflowCommand < BaseCommand
|
|
258
268
|
include ExecutionOptions
|
|
259
269
|
include WorkflowOptions
|
|
@@ -475,6 +485,12 @@ module Kettle
|
|
|
475
485
|
description "Plan or execute git pull --rebase per member."
|
|
476
486
|
end
|
|
477
487
|
|
|
488
|
+
class Sync < WorkflowCommand
|
|
489
|
+
command_name "sync"
|
|
490
|
+
usage "[options]"
|
|
491
|
+
description "Plan or execute default-branch fetch/rebase and branch rebase per member."
|
|
492
|
+
end
|
|
493
|
+
|
|
478
494
|
class Up < WorkflowCommand
|
|
479
495
|
command_name "up"
|
|
480
496
|
usage "[options]"
|
|
@@ -501,9 +517,11 @@ module Kettle
|
|
|
501
517
|
command Release
|
|
502
518
|
command Push
|
|
503
519
|
command Pull
|
|
520
|
+
command Sync
|
|
504
521
|
command Up
|
|
505
522
|
command BranchLanes
|
|
506
523
|
command ReleaseState
|
|
524
|
+
command State
|
|
507
525
|
|
|
508
526
|
prepend ReturningMain
|
|
509
527
|
|
data/lib/kettle/family/config.rb
CHANGED
|
@@ -9,6 +9,8 @@ module Kettle
|
|
|
9
9
|
DEFAULT_MEMBER_EXCLUDES = [
|
|
10
10
|
"vendor/**",
|
|
11
11
|
"**/vendor/**",
|
|
12
|
+
"benchmarks/**",
|
|
13
|
+
"**/benchmarks/**",
|
|
12
14
|
"tmp/**",
|
|
13
15
|
"**/tmp/**",
|
|
14
16
|
"spec/**",
|
|
@@ -190,6 +192,13 @@ module Kettle
|
|
|
190
192
|
fetch_path("template", "jobs")
|
|
191
193
|
end
|
|
192
194
|
|
|
195
|
+
def readme_corporate_sponsors
|
|
196
|
+
raw = fetch_path("readme", "corporate_sponsors") ||
|
|
197
|
+
fetch_path("sponsorships", "corporate") ||
|
|
198
|
+
fetch_path("corporate_sponsors")
|
|
199
|
+
normalize_corporate_sponsors(raw)
|
|
200
|
+
end
|
|
201
|
+
|
|
193
202
|
def normalize_lockfiles?
|
|
194
203
|
fetch_path("template", "normalize_lockfiles") == true
|
|
195
204
|
end
|
|
@@ -306,6 +315,28 @@ module Kettle
|
|
|
306
315
|
.select { |path| File.directory?(path) }
|
|
307
316
|
end
|
|
308
317
|
|
|
318
|
+
def normalize_corporate_sponsors(raw)
|
|
319
|
+
Array(raw).filter_map do |entry|
|
|
320
|
+
unless entry.is_a?(Hash)
|
|
321
|
+
raise ArgumentError, "corporate sponsor entries must be mappings with name, url, and img_src"
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
sponsor = stringify_keys(entry)
|
|
325
|
+
name = sponsor["name"].to_s.strip
|
|
326
|
+
url = sponsor["url"].to_s.strip
|
|
327
|
+
img_src = sponsor["img_src"].to_s.strip
|
|
328
|
+
if name.empty? || url.empty? || img_src.empty?
|
|
329
|
+
raise ArgumentError, "corporate sponsor entries require name, url, and img_src"
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
{
|
|
333
|
+
"name" => name,
|
|
334
|
+
"url" => url,
|
|
335
|
+
"img_src" => img_src
|
|
336
|
+
}
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
|
|
309
340
|
def fetch_path(*keys)
|
|
310
341
|
keys.reduce(data) do |memo, key|
|
|
311
342
|
break nil unless memo.is_a?(Hash)
|
|
@@ -59,6 +59,7 @@ module Kettle
|
|
|
59
59
|
success = status.success?
|
|
60
60
|
state = success ? JSON.parse(stdout) : {}
|
|
61
61
|
state = branch_filtered_state(member, state, branch) if success && branch
|
|
62
|
+
state = enrich_git_state(member.root, state) if success
|
|
62
63
|
result(member: member, command: command, stdout: stdout, stderr: stderr, status: status.exitstatus, elapsed: elapsed, success: success, state: state, branch: branch)
|
|
63
64
|
rescue JSON::ParserError => error
|
|
64
65
|
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)
|
|
@@ -182,6 +183,73 @@ module Kettle
|
|
|
182
183
|
status.success?
|
|
183
184
|
end
|
|
184
185
|
|
|
186
|
+
def enrich_git_state(root, state)
|
|
187
|
+
return state unless git_work_tree?(root)
|
|
188
|
+
|
|
189
|
+
enriched = state.dup
|
|
190
|
+
current_branch = git_output(root, "branch", "--show-current")
|
|
191
|
+
enriched["current_branch"] = current_branch unless current_branch.to_s.empty?
|
|
192
|
+
|
|
193
|
+
version = state["latest_released"].to_s.empty? ? state["latest_changelog_version"] : state["latest_released"]
|
|
194
|
+
return enriched if version.to_s.empty?
|
|
195
|
+
|
|
196
|
+
local_default = default_branch(root)
|
|
197
|
+
if local_default
|
|
198
|
+
enriched["default_branch"] = local_default
|
|
199
|
+
if (counts = release_counts_for_ref(root, version, local_default))
|
|
200
|
+
enriched["behind"] = counts.fetch(:behind)
|
|
201
|
+
enriched["ahead"] = counts.fetch(:ahead)
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
remote_default = remote_default_branch(root, local_default)
|
|
206
|
+
if remote_default
|
|
207
|
+
enriched["remote_default_branch"] = remote_default
|
|
208
|
+
if (counts = release_counts_for_ref(root, version, remote_default))
|
|
209
|
+
enriched["remote_behind"] = counts.fetch(:behind)
|
|
210
|
+
enriched["remote_ahead"] = counts.fetch(:ahead)
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
enriched
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def git_work_tree?(root)
|
|
218
|
+
_stdout, _stderr, status = Open3.capture3("git", "rev-parse", "--is-inside-work-tree", chdir: root)
|
|
219
|
+
status.success?
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def default_branch(root)
|
|
223
|
+
remote_default = remote_default_branch(root)
|
|
224
|
+
branch = remote_default&.delete_prefix("origin/")
|
|
225
|
+
return branch if branch && git_ref_exists?(root, "refs/heads/#{branch}")
|
|
226
|
+
|
|
227
|
+
%w[main master].find { |name| git_ref_exists?(root, "refs/heads/#{name}") }
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def remote_default_branch(root, local_default = nil)
|
|
231
|
+
symbolic = git_output(root, "symbolic-ref", "--quiet", "--short", "refs/remotes/origin/HEAD")
|
|
232
|
+
return symbolic if symbolic&.start_with?("origin/")
|
|
233
|
+
|
|
234
|
+
"origin/#{local_default}" if local_default && git_ref_exists?(root, "refs/remotes/origin/#{local_default}")
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def release_counts_for_ref(root, version, ref)
|
|
238
|
+
tag = release_tag_for_version(root, version)
|
|
239
|
+
return nil unless tag && git_ref_exists?(root, ref)
|
|
240
|
+
|
|
241
|
+
stdout = git_output(root, "rev-list", "--left-right", "--count", "#{tag}...#{ref}")
|
|
242
|
+
parts = stdout.to_s.split
|
|
243
|
+
return nil unless parts.length == 2 && parts.all? { |part| part.match?(/\A\d+\z/) }
|
|
244
|
+
|
|
245
|
+
{behind: parts.fetch(0).to_i, ahead: parts.fetch(1).to_i}
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
def git_output(root, *args)
|
|
249
|
+
stdout, _stderr, status = Open3.capture3("git", *args, chdir: root)
|
|
250
|
+
status.success? ? stdout.strip : nil
|
|
251
|
+
end
|
|
252
|
+
|
|
185
253
|
def family_changelog_state(root)
|
|
186
254
|
changelog = File.expand_path(config.changelog_path, root)
|
|
187
255
|
raise Error, "missing root changelog #{config.changelog_path}" unless File.file?(changelog)
|
|
@@ -192,7 +260,7 @@ module Kettle
|
|
|
192
260
|
unreleased_entries = unreleased_entries?(content)
|
|
193
261
|
prepared_release_pending = !version.to_s.empty? && latest_changelog_version == version
|
|
194
262
|
ahead = commits_ahead_of_release(root, latest_changelog_version)
|
|
195
|
-
{
|
|
263
|
+
enrich_git_state(root, {
|
|
196
264
|
"gem_name" => config.family_name,
|
|
197
265
|
"version" => version,
|
|
198
266
|
"latest_released" => nil,
|
|
@@ -201,7 +269,7 @@ module Kettle
|
|
|
201
269
|
"unreleased_entries" => unreleased_entries,
|
|
202
270
|
"prepared_release_pending" => prepared_release_pending,
|
|
203
271
|
"pending_release" => unreleased_entries || prepared_release_pending
|
|
204
|
-
}
|
|
272
|
+
})
|
|
205
273
|
end
|
|
206
274
|
|
|
207
275
|
def root_changelog_version(root)
|
data/lib/kettle/family/report.rb
CHANGED
|
@@ -20,6 +20,7 @@ module Kettle
|
|
|
20
20
|
push
|
|
21
21
|
release
|
|
22
22
|
release-state
|
|
23
|
+
sync
|
|
23
24
|
template
|
|
24
25
|
test
|
|
25
26
|
up
|
|
@@ -103,7 +104,7 @@ module Kettle
|
|
|
103
104
|
lines << "results:"
|
|
104
105
|
visible_results.each do |result|
|
|
105
106
|
lines << " #{result_state(result)} #{result.member_name} #{result.phase} #{result.reason || ""}".rstrip
|
|
106
|
-
|
|
107
|
+
append_result_stdout(lines, result)
|
|
107
108
|
append_indented_output(lines, result.stderr) if !result.ok? && !result.stderr.to_s.empty?
|
|
108
109
|
lines << " resume: #{resume_hint_for(result)}" unless result.ok?
|
|
109
110
|
end
|
|
@@ -158,10 +159,34 @@ module Kettle
|
|
|
158
159
|
output.to_s.each_line(chomp: true) { |line| lines << " #{line}" }
|
|
159
160
|
end
|
|
160
161
|
|
|
162
|
+
def append_result_stdout(lines, result)
|
|
163
|
+
return if suppress_success_output?(result)
|
|
164
|
+
|
|
165
|
+
if template_event_stdout?(result)
|
|
166
|
+
append_template_event_failure_summary(lines, result.stdout) unless result.ok?
|
|
167
|
+
else
|
|
168
|
+
append_indented_output(lines, result.stdout)
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
161
172
|
def suppress_success_output?(result)
|
|
162
173
|
result.stdout.to_s.empty? || (command == "template" && result.ok?)
|
|
163
174
|
end
|
|
164
175
|
|
|
176
|
+
def template_event_stdout?(result)
|
|
177
|
+
command == "template" && result.phase == "template" && template_events(result.stdout).any?
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def append_template_event_failure_summary(lines, output)
|
|
181
|
+
diagnostics = template_events(output).filter_map do |event|
|
|
182
|
+
next unless event["type"] == "diagnostic"
|
|
183
|
+
|
|
184
|
+
event["message"].to_s.empty? ? event["kind"].to_s : event["message"].to_s
|
|
185
|
+
end.uniq
|
|
186
|
+
diagnostics.each { |message| lines << " diagnostic: #{message}" unless message.empty? }
|
|
187
|
+
lines << " template event stream omitted from text report"
|
|
188
|
+
end
|
|
189
|
+
|
|
165
190
|
def append_template_summary(lines)
|
|
166
191
|
template_results = results.select { |result| result.phase == "template" }
|
|
167
192
|
return if template_results.empty?
|
|
@@ -173,6 +198,9 @@ module Kettle
|
|
|
173
198
|
end
|
|
174
199
|
|
|
175
200
|
def template_changed_file_count(result)
|
|
201
|
+
event_count = template_changed_file_count_from_events(result.stdout)
|
|
202
|
+
return event_count if event_count
|
|
203
|
+
|
|
176
204
|
payload = JSON.parse(result.stdout.to_s)
|
|
177
205
|
Array(payload["changed_files"] || payload[:changed_files]).length if payload.is_a?(Hash)
|
|
178
206
|
rescue JSON::ParserError
|
|
@@ -182,6 +210,22 @@ module Kettle
|
|
|
182
210
|
0
|
|
183
211
|
end
|
|
184
212
|
|
|
213
|
+
def template_changed_file_count_from_events(output)
|
|
214
|
+
summaries = template_events(output).select { |event| event["type"] == "summary" && event.key?("changed_count") }
|
|
215
|
+
return nil if summaries.empty?
|
|
216
|
+
|
|
217
|
+
summaries.sum { |event| event["changed_count"].to_i }
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def template_events(output)
|
|
221
|
+
output.to_s.each_line.filter_map do |line|
|
|
222
|
+
payload = JSON.parse(line)
|
|
223
|
+
payload if payload.is_a?(Hash) && payload["event_version"]
|
|
224
|
+
rescue JSON::ParserError
|
|
225
|
+
nil
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
|
|
185
229
|
def append_member_release_targets(lines)
|
|
186
230
|
return if member_release_target_branches.empty?
|
|
187
231
|
|
|
@@ -313,10 +357,11 @@ module Kettle
|
|
|
313
357
|
state = result.state || {}
|
|
314
358
|
row = [
|
|
315
359
|
state.fetch("gem_name", result.member_name).to_s,
|
|
360
|
+
state.fetch("current_branch", nil).to_s.empty? ? "unknown" : state.fetch("current_branch").to_s,
|
|
316
361
|
state.fetch("version", "unknown").to_s,
|
|
317
362
|
state.fetch("latest_released", nil).to_s.empty? ? "unknown" : state.fetch("latest_released").to_s,
|
|
318
363
|
state.fetch("latest_changelog_version", nil).to_s.empty? ? "none" : state.fetch("latest_changelog_version").to_s,
|
|
319
|
-
|
|
364
|
+
release_state_ahead_behind(state),
|
|
320
365
|
yes_no(state.fetch("unreleased_entries", nil)),
|
|
321
366
|
yes_no(state.fetch("prepared_release_pending", nil)),
|
|
322
367
|
yes_no(state.fetch("pending_release", nil))
|
|
@@ -327,12 +372,27 @@ module Kettle
|
|
|
327
372
|
end
|
|
328
373
|
|
|
329
374
|
def release_state_header
|
|
330
|
-
header = [["gem", "version.rb", "latest released", "latest changelog", "ahead", "unreleased", "prepared", "pending"]]
|
|
375
|
+
header = [["gem", "checkout", "version.rb", "latest released", "latest changelog", "ahead / behind", "unreleased", "prepared", "pending"]]
|
|
331
376
|
return header unless release_state_has_branches?
|
|
332
377
|
|
|
333
378
|
[["branch", *header.first]]
|
|
334
379
|
end
|
|
335
380
|
|
|
381
|
+
def release_state_ahead_behind(state)
|
|
382
|
+
local_ahead = state.fetch("ahead", nil)
|
|
383
|
+
local_behind = state.fetch("behind", nil)
|
|
384
|
+
return "unknown" if local_ahead.nil? && local_behind.nil?
|
|
385
|
+
|
|
386
|
+
"#{release_state_count(local_ahead, state.fetch("remote_ahead", nil))} / #{release_state_count(local_behind, state.fetch("remote_behind", nil))}"
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
def release_state_count(local_value, remote_value)
|
|
390
|
+
local_text = local_value.nil? ? "unknown" : local_value.to_s
|
|
391
|
+
return local_text if remote_value.nil? || remote_value == local_value
|
|
392
|
+
|
|
393
|
+
"#{local_text} (#{remote_value})"
|
|
394
|
+
end
|
|
395
|
+
|
|
336
396
|
def release_state_has_branches?
|
|
337
397
|
results.any? { |result| !result.branch.to_s.empty? }
|
|
338
398
|
end
|
|
@@ -16,6 +16,36 @@ module Kettle
|
|
|
16
16
|
"lint" => "bundle exec rake rubocop_gradual",
|
|
17
17
|
"docs" => "bundle exec rake yard",
|
|
18
18
|
"gha-sha-pins" => "bundle exec kettle-gha-sha-pins",
|
|
19
|
+
"sync" => [
|
|
20
|
+
"sh",
|
|
21
|
+
"-lc",
|
|
22
|
+
<<~SH
|
|
23
|
+
set -e
|
|
24
|
+
current_branch=$(git branch --show-current)
|
|
25
|
+
if [ -z "$current_branch" ]; then
|
|
26
|
+
echo "kettle-family sync requires a named branch checkout" >&2
|
|
27
|
+
exit 1
|
|
28
|
+
fi
|
|
29
|
+
default_ref=$(git symbolic-ref --quiet --short refs/remotes/origin/HEAD 2>/dev/null || true)
|
|
30
|
+
default_branch=${default_ref#origin/}
|
|
31
|
+
if [ -z "$default_branch" ] || [ "$default_branch" = "$default_ref" ]; then
|
|
32
|
+
default_branch=$(git remote show origin | awk '/HEAD branch:/ { print $NF; exit }')
|
|
33
|
+
fi
|
|
34
|
+
if [ -z "$default_branch" ]; then
|
|
35
|
+
echo "could not determine origin default branch" >&2
|
|
36
|
+
exit 1
|
|
37
|
+
fi
|
|
38
|
+
git fetch origin "$default_branch"
|
|
39
|
+
if [ "$current_branch" != "$default_branch" ]; then
|
|
40
|
+
git switch "$default_branch"
|
|
41
|
+
fi
|
|
42
|
+
git rebase "origin/$default_branch"
|
|
43
|
+
if [ "$current_branch" != "$default_branch" ]; then
|
|
44
|
+
git switch "$current_branch"
|
|
45
|
+
git rebase "$default_branch"
|
|
46
|
+
fi
|
|
47
|
+
SH
|
|
48
|
+
],
|
|
19
49
|
"bupb" => %w[bundle update --bundler]
|
|
20
50
|
}.freeze
|
|
21
51
|
GIT_SYNC_COMMANDS = {
|
|
@@ -952,6 +982,10 @@ module Kettle
|
|
|
952
982
|
if command == "template"
|
|
953
983
|
env["KETTLE_JEM_TEMPLATE_PROFILE"] = config.template_profile if config.template_profile
|
|
954
984
|
env["KJ_REPOSITORY_TOPOLOGY"] = config.template_repository_topology if config.template_repository_topology
|
|
985
|
+
corporate_sponsors = config.readme_corporate_sponsors
|
|
986
|
+
unless corporate_sponsors.empty?
|
|
987
|
+
env["KETTLE_JEM_CORPORATE_SPONSORS_JSON"] = JSON.generate(corporate_sponsors)
|
|
988
|
+
end
|
|
955
989
|
end
|
|
956
990
|
env.merge!(env_overrides)
|
|
957
991
|
if command == "template" && verbose
|
|
@@ -994,6 +1028,7 @@ module Kettle
|
|
|
994
1028
|
|
|
995
1029
|
def template_event_line_handler(member)
|
|
996
1030
|
return nil unless progress_io
|
|
1031
|
+
return nil unless verbose || debug
|
|
997
1032
|
|
|
998
1033
|
lambda do |line|
|
|
999
1034
|
event = parse_template_event(line)
|
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.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter H. Boling
|
|
@@ -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.2
|
|
307
|
+
changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v1.0.2/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.2
|
|
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
|