kettle-family 0.1.13 → 0.1.15

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a3c5233f8223ab84157bd218613782a68b6d86073276611f5f48efcf399b3f7d
4
- data.tar.gz: f96d4584d39c94b5956722d776d27309cdaad86779ebf4a522e47c5c42fe395d
3
+ metadata.gz: f34f86e4bbc4ff6d79503e62d90a5f5942f2cf5ca71889d28e9580467e1cbf62
4
+ data.tar.gz: 5b930341c10d8dbd8f254cfdd1cd38ffd553ce42801e43bc7d53be1feb794127
5
5
  SHA512:
6
- metadata.gz: c6c40b482098bf7af4668965740cb643b7a4256efefc5398ec8c85071d1eec03a779317aa9c8121f9fc517e0beea3ae090318027d1ed61e940870b00e8199461
7
- data.tar.gz: 0661b72077e5f25d7c8b7029accc11d56e8e459e2e060b3a394514b70bacdc92d69b43b5ce51eec88665a1046662c4d1f0bede30ed076a7e9f54825d0d1ed676
6
+ metadata.gz: 4728fe4ae1ee4c04ab01034ccc2443b7d77379912ec38aa0838c63f1ee08c902ce0db06c4d4753521a5461a34bd62a97715b4f3594eac960f4b4e0d3c0ea32b8
7
+ data.tar.gz: e51a4793bb4b96ac610165217d143cba66976ef4e0ac2c106e87c9c7197ba5a238af032b3e9b5f360e67134668a11f9fce70e70ac9d6fa4cc545e2fd7b2689ac
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -20,6 +20,8 @@ Please file a bug if you notice a violation of semantic versioning.
20
20
 
21
21
  ### Added
22
22
 
23
+ - `kettle-family push`, `kettle-family pull`, and `kettle-family up` now plan
24
+ or execute family-wide git synchronization commands.
23
25
  - `kettle-family bump-version` now accepts the same relative bump targets as
24
26
  `kettle-bump` (`major`, `minor`, `patch`, and `pre`) and applies them per
25
27
  member from each member's current version.
@@ -32,9 +34,17 @@ Please file a bug if you notice a violation of semantic versioning.
32
34
 
33
35
  ### Fixed
34
36
 
37
+ - Branch-stack commands now allow `main` as a configured branch target for
38
+ workflows like templating while excluding it from install and release
39
+ traversals.
35
40
  - `kettle-family bump-version` now leaves non-exact family dependency
36
41
  requirements unchanged instead of rejecting them as ambiguous, allowing
37
42
  families with loose inter-gem constraints to use relative version bumps.
43
+ - `kettle-family bump-version --execute` now reports actual writes as
44
+ `updated`, includes each member's `current -> target` version change, commits
45
+ version bump edits, and uses member-local branch target stacks so branch
46
+ traversal can continue safely.
47
+ - Text reports now indent each line of multi-line command output consistently.
38
48
 
39
49
  ### Security
40
50
 
@@ -6,8 +6,9 @@ require "optparse"
6
6
  module Kettle
7
7
  module Family
8
8
  class CLI
9
- COMMANDS = %w[discover plan report metadata check test lint docs template install bump-version add-changelog release branch-lanes release-state].freeze
10
- WORKFLOW_COMMANDS = %w[check test lint docs template release].freeze
9
+ COMMANDS = %w[discover plan report metadata check test lint docs template install bump-version add-changelog release push pull up branch-lanes release-state].freeze
10
+ WORKFLOW_COMMANDS = %w[check test lint docs template release push pull up].freeze
11
+ MAIN_BRANCH_SKIPPING_COMMANDS = %w[install release].freeze
11
12
 
12
13
  def self.call(argv, out: $stdout, err: $stderr)
13
14
  new(argv, out: out, err: err).call
@@ -64,6 +65,9 @@ module Kettle
64
65
  bump-version Check, plan, or execute family version alignment
65
66
  add-changelog Add an entry to an existing Unreleased changelog section
66
67
  release Plan or execute release build/publish phases
68
+ push Plan or execute git push per member
69
+ pull Plan or execute git pull --rebase per member
70
+ up Plan or execute git pull --rebase then git push per member
67
71
  branch-lanes Audit configured branch lane release mappings
68
72
  release-state Report changelog release state for family members
69
73
 
@@ -176,8 +180,8 @@ module Kettle
176
180
  selected_members: selected,
177
181
  config_path: config.path,
178
182
  branch_lanes: config.branch_lanes,
179
- release_target_branches: config.release_target_branches,
180
- member_release_target_branches: member_release_target_branches(members: selected, config: config),
183
+ release_target_branches: branch_targets_for(command, config.release_target_branches),
184
+ member_release_target_branches: member_release_target_branches(command: command, members: selected, config: config),
181
185
  release_mode: release_mode(command: command, options: options),
182
186
  command: command,
183
187
  results: results
@@ -186,6 +190,7 @@ module Kettle
186
190
 
187
191
  def command_results(command:, config:, members:, options:)
188
192
  return branch_target_command_results(command: command, config: config, members: members, options: options) if branch_target_command?(command, config)
193
+ return member_local_branch_target_command_results(command: command, config: config, members: members, options: options) if member_local_branch_target_command?(command, config, members)
189
194
 
190
195
  command_results_for_current_branch(command: command, config: config, members: members, options: options)
191
196
  end
@@ -224,10 +229,17 @@ module Kettle
224
229
  !WORKFLOW_COMMANDS.include?(command)
225
230
  end
226
231
 
232
+ def member_local_branch_target_command?(command, config, members)
233
+ return false if !config.release_target_branches.empty?
234
+ return false unless command == "bump-version"
235
+
236
+ members.any? { |member| member_local_release_config(member: member, config: config) }
237
+ end
238
+
227
239
  def branch_target_command_results(command:, config:, members:, options:)
228
240
  runner = CommandRunner.new(execute: options[:execute])
229
241
  selected_names = members.map(&:name)
230
- config.release_target_branches.each_with_object([]) do |branch, memo|
242
+ branch_targets_for(command, config.release_target_branches).each_with_object([]) do |branch, memo|
231
243
  memo << runner.call(
232
244
  member: family_member(config),
233
245
  phase: "release_checkout",
@@ -245,6 +257,33 @@ module Kettle
245
257
  end
246
258
  end
247
259
 
260
+ def member_local_branch_target_command_results(command:, config:, members:, options:)
261
+ runner = CommandRunner.new(execute: options[:execute])
262
+ members.each_with_object([]) do |member, memo|
263
+ member_config = member_local_release_config(member: member, config: config)
264
+ unless member_config
265
+ memo.concat(command_results_for_current_branch(command: command, config: config, members: [member], options: options))
266
+ break memo unless memo.last&.ok?
267
+ next
268
+ end
269
+
270
+ branch_targets_for(command, member_config.release_target_branches).each do |branch|
271
+ memo << runner.call(
272
+ member: member,
273
+ phase: "release_checkout",
274
+ command: ["git", "checkout", branch]
275
+ )
276
+ break unless memo.last.ok?
277
+
278
+ branch_members = rediscovered_selected_members(config: member_config, selected_names: [member.name], command: command)
279
+ branch_members = [member] if branch_members.empty?
280
+ memo.concat(command_results_for_current_branch(command: command, config: member_config, members: branch_members, options: options))
281
+ break unless memo.last&.ok?
282
+ end
283
+ break memo unless memo.last&.ok?
284
+ end
285
+ end
286
+
248
287
  def rediscovered_selected_members(config:, selected_names:, command:)
249
288
  discovered = Discovery.new(config: config).members
250
289
  ordered = (command == "install") ? install_order(discovered, config) : Orderer.new(members: discovered, mode: config.order_mode, hints: config.order_hints).ordered
@@ -271,12 +310,28 @@ module Kettle
271
310
  end
272
311
 
273
312
  def bump_version_results(members:, options:)
274
- VersionBump.new(
313
+ results = VersionBump.new(
275
314
  members: members,
276
315
  target_version: options[:target_version],
277
316
  from_version: options[:from_version],
278
317
  mode: bump_version_mode(options)
279
318
  ).results
319
+ return results if options[:check] || !options[:commit]
320
+ return results unless results.all?(&:ok?)
321
+
322
+ runner = CommandRunner.new(execute: options[:execute])
323
+ members.each_with_object(results) do |member, memo|
324
+ memo << runner.call(
325
+ member: member,
326
+ phase: "commit_version_bump",
327
+ command: [
328
+ "sh",
329
+ "-lc",
330
+ "if ! git diff --quiet -- '*.gemspec' 'lib/**/version.rb'; then git add -- '*.gemspec' 'lib/**/version.rb' && git commit -m '🔖 Bump gem version'; fi"
331
+ ]
332
+ )
333
+ break memo unless memo.last.ok?
334
+ end
280
335
  end
281
336
 
282
337
  def add_changelog_results(members:, options:)
@@ -340,13 +395,19 @@ module Kettle
340
395
  options[:publish] ? "publish" : "build-only"
341
396
  end
342
397
 
343
- def member_release_target_branches(members:, config:)
398
+ def member_release_target_branches(command:, members:, config:)
344
399
  members.each_with_object({}) do |member, memo|
345
400
  member_config = member_local_release_config(member: member, config: config)
346
- memo[member.name] = member_config.release_target_branches if member_config
401
+ memo[member.name] = branch_targets_for(command, member_config.release_target_branches) if member_config
347
402
  end
348
403
  end
349
404
 
405
+ def branch_targets_for(command, branches)
406
+ return branches unless MAIN_BRANCH_SKIPPING_COMMANDS.include?(command)
407
+
408
+ branches.reject { |branch| branch == "main" }
409
+ end
410
+
350
411
  def member_local_release_config(member:, config:)
351
412
  member_config = Config.load(root: member.root)
352
413
  return unless member_config.path
@@ -77,12 +77,16 @@ module Kettle
77
77
  lines << "results:"
78
78
  results.each do |result|
79
79
  lines << " #{result_state(result)} #{result.member_name} #{result.phase} #{result.reason || ""}".rstrip
80
- lines << " #{result.stdout}" unless result.stdout.to_s.empty?
81
- lines << " #{result.stderr}" if !result.ok? && !result.stderr.to_s.empty?
80
+ append_indented_output(lines, result.stdout) unless result.stdout.to_s.empty?
81
+ append_indented_output(lines, result.stderr) if !result.ok? && !result.stderr.to_s.empty?
82
82
  lines << " resume: #{resume_hint_for(result)}" unless result.ok?
83
83
  end
84
84
  end
85
85
 
86
+ def append_indented_output(lines, output)
87
+ output.to_s.each_line(chomp: true) { |line| lines << " #{line}" }
88
+ end
89
+
86
90
  def append_member_release_targets(lines)
87
91
  return if member_release_target_branches.empty?
88
92
 
@@ -3,7 +3,7 @@
3
3
  module Kettle
4
4
  module Family
5
5
  module Version
6
- VERSION = "0.1.13"
6
+ VERSION = "0.1.15"
7
7
  end
8
8
  VERSION = Version::VERSION # Traditional Constant Location
9
9
  end
@@ -45,7 +45,7 @@ module Kettle
45
45
  workdir: member.root,
46
46
  status: check_failed?(edits) ? 1 : 0,
47
47
  success: !check_failed?(edits),
48
- stdout: edit_summary(edits),
48
+ stdout: edit_summary(member: member, target_version: member_target_version, edits: edits),
49
49
  stderr: "",
50
50
  elapsed_seconds: 0.0,
51
51
  skipped: mode == :dry_run,
@@ -220,10 +220,13 @@ module Kettle
220
220
  end
221
221
  end
222
222
 
223
- def edit_summary(edits)
224
- return "no version changes needed" if edits.empty?
223
+ def edit_summary(member:, target_version:, edits:)
224
+ lines = ["#{member.version} -> #{target_version}"]
225
+ return [*lines, "no version changes needed"].join("\n") if edits.empty?
225
226
 
226
- edits.map { |edit| "would update #{edit.fetch(:path)}" }.uniq.join("\n")
227
+ verb = (mode == :execute) ? "updated" : "would update"
228
+ lines.concat(edits.map { |edit| "#{verb} #{edit.fetch(:path)}" }.uniq)
229
+ lines.join("\n")
227
230
  end
228
231
  end
229
232
  end
@@ -14,6 +14,12 @@ module Kettle
14
14
  "lint" => "bundle exec rake rubocop_gradual",
15
15
  "docs" => "bundle exec rake yard"
16
16
  }.freeze
17
+ GIT_SYNC_COMMANDS = {
18
+ "push" => [["push", %w[git push]]],
19
+ "pull" => [["pull", %w[git pull --rebase]]],
20
+ "up" => [["pull", %w[git pull --rebase]], ["push", %w[git push]]]
21
+ }.freeze
22
+ MAIN_BRANCH_SKIPPING_COMMANDS = %w[release].freeze
17
23
 
18
24
  def initialize(command:, config:, members:, execute: false, commit: true, allow_dirty: false, publish: false, push: false, tag: false, start_step: nil, local_ci: false, continue_ci_failures: false, env_overrides: {}, gem_signing_password: nil)
19
25
  @command = command
@@ -47,6 +53,7 @@ module Kettle
47
53
  def current_branch_results(workflow_members)
48
54
  return check_results(workflow_members) if command == "check"
49
55
  return release_member_results(workflow_members, include_family_changelog: true) if command == "release"
56
+ return git_sync_results(workflow_members) if GIT_SYNC_COMMANDS.key?(command)
50
57
 
51
58
  member_workflow_results(workflow_members)
52
59
  end
@@ -75,7 +82,7 @@ module Kettle
75
82
  def branch_target_results
76
83
  runner = command_runner
77
84
  selected_names = members.map(&:name)
78
- config.release_target_branches.each_with_object([]) do |branch, memo|
85
+ branch_targets.each_with_object([]) do |branch, memo|
79
86
  memo << checkout_branch_result(branch: branch, runner: runner)
80
87
  break memo unless memo.last.ok?
81
88
 
@@ -176,6 +183,17 @@ module Kettle
176
183
  end
177
184
  end
178
185
 
186
+ def git_sync_results(sync_members)
187
+ runner = command_runner
188
+ sync_members.each_with_object([]) do |member, memo|
189
+ GIT_SYNC_COMMANDS.fetch(command).each do |phase, git_command|
190
+ memo << runner.call(member: member, phase: phase, command: git_command)
191
+ break unless memo.last.ok?
192
+ end
193
+ break memo unless memo.last.ok?
194
+ end
195
+ end
196
+
179
197
  def command_runner
180
198
  CommandRunner.new(execute: execute, gem_signing_password: @gem_signing_password)
181
199
  end
@@ -190,6 +208,12 @@ module Kettle
190
208
  members.any? { |member| member_local_release_config(member) }
191
209
  end
192
210
 
211
+ def branch_targets
212
+ return config.release_target_branches unless MAIN_BRANCH_SKIPPING_COMMANDS.include?(command)
213
+
214
+ config.release_target_branches.reject { |branch| branch == "main" }
215
+ end
216
+
193
217
  def member_local_release_config(member)
194
218
  member_config = Config.load(root: member.root)
195
219
  return unless member_config.path
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.13
4
+ version: 0.1.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter H. Boling
@@ -309,10 +309,10 @@ licenses:
309
309
  - AGPL-3.0-only
310
310
  metadata:
311
311
  homepage_uri: https://kettle-family.galtzo.com
312
- source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v0.1.13
313
- changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v0.1.13/CHANGELOG.md
312
+ source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v0.1.15
313
+ changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v0.1.15/CHANGELOG.md
314
314
  bug_tracker_uri: https://github.com/kettle-dev/kettle-family/issues
315
- documentation_uri: https://www.rubydoc.info/gems/kettle-family/0.1.13
315
+ documentation_uri: https://www.rubydoc.info/gems/kettle-family/0.1.15
316
316
  funding_uri: https://github.com/sponsors/pboling
317
317
  wiki_uri: https://github.com/kettle-dev/kettle-family/wiki
318
318
  news_uri: https://www.railsbling.com/tags/kettle-family
metadata.gz.sig CHANGED
Binary file