kettle-family 1.0.2 → 1.0.4
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 +41 -1
- data/README.md +1 -1
- data/lib/kettle/family/cli.rb +18 -7
- data/lib/kettle/family/dependency_floor.rb +1 -1
- data/lib/kettle/family/discovery.rb +98 -3
- data/lib/kettle/family/member.rb +2 -0
- data/lib/kettle/family/release_waves.rb +50 -0
- data/lib/kettle/family/report.rb +7 -2
- data/lib/kettle/family/version.rb +1 -1
- data/lib/kettle/family/version_bump.rb +13 -5
- data/lib/kettle/family/workflow.rb +15 -28
- data/lib/kettle/family.rb +1 -0
- data.tar.gz.sig +0 -0
- metadata +5 -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: f81e03e49736eb1884f0272f7af5ee78b14239ace620cf5427da26cfbaf2df5c
|
|
4
|
+
data.tar.gz: cc974713f574848b1740c413c1db51913bd99f8fc91fa2683b312f7cdbcfcf91
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7fb8fa2d38f8a84c537558ab48d90fd17f9933cd27e8017b60a9f6ecf89f54a928d0c21b058dcc0e41766d47372dffb4a2a125c18c0e7049d11ce31ddaac24cd
|
|
7
|
+
data.tar.gz: 2e546a76ba606eb8078a477b696109a30a0acdfe23bda7267905fc926cb65dec5237f938f5d42ab8e8e75fb131a316d0303a3ec637284c7c41331e98a02bcdd2
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/CHANGELOG.md
CHANGED
|
@@ -30,6 +30,42 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
30
30
|
|
|
31
31
|
### Security
|
|
32
32
|
|
|
33
|
+
## [1.0.4] - 2026-07-21
|
|
34
|
+
|
|
35
|
+
- TAG: [v1.0.4][1.0.4t]
|
|
36
|
+
- COVERAGE: 95.68% -- 2726/2849 lines in 24 files
|
|
37
|
+
- BRANCH COVERAGE: 77.97% -- 952/1221 branches in 24 files
|
|
38
|
+
- 28.68% documented
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- `kettle-family release --publish` now skips already-published members with no
|
|
43
|
+
unreleased changes even when post-release commits leave HEAD ahead of the
|
|
44
|
+
release tag, allowing later pending members to continue.
|
|
45
|
+
|
|
46
|
+
## [1.0.3] - 2026-07-21
|
|
47
|
+
|
|
48
|
+
- TAG: [v1.0.3][1.0.3t]
|
|
49
|
+
- COVERAGE: 95.61% -- 2724/2849 lines in 24 files
|
|
50
|
+
- BRANCH COVERAGE: 77.97% -- 952/1221 branches in 24 files
|
|
51
|
+
- 28.68% documented
|
|
52
|
+
|
|
53
|
+
### Changed
|
|
54
|
+
|
|
55
|
+
- `kettle-family release-state` text tables now use compact column headings and
|
|
56
|
+
truncate checkout branch names to 10 characters.
|
|
57
|
+
|
|
58
|
+
### Fixed
|
|
59
|
+
|
|
60
|
+
- `kettle-family release` now builds release waves from gemspec development
|
|
61
|
+
dependencies and literal Gemfile dependencies, including dependencies in
|
|
62
|
+
modular Gemfiles loaded with `eval_gemfile`, so development-tooling releases
|
|
63
|
+
unblock dependent member releases before the next wave starts.
|
|
64
|
+
|
|
65
|
+
- `kettle-family bump` now rewrites exact family dependency pins according to
|
|
66
|
+
release-wave order, so earlier members are not changed to require unreleased
|
|
67
|
+
later member versions.
|
|
68
|
+
|
|
33
69
|
## [1.0.2] - 2026-07-21
|
|
34
70
|
|
|
35
71
|
- TAG: [v1.0.2][1.0.2t]
|
|
@@ -823,7 +859,11 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
823
859
|
- Fixed CI load failures on engines without compatible `pty` support by falling back to Open3 for interactive release commands.
|
|
824
860
|
- Fixed Ruby 3.2 version-bump support by loading Prism lazily and wiring the Prism gem only for MRI versions that need it.
|
|
825
861
|
|
|
826
|
-
[Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.0.
|
|
862
|
+
[Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.0.4...HEAD
|
|
863
|
+
[1.0.4]: https://github.com/kettle-dev/kettle-family/compare/v1.0.3...v1.0.4
|
|
864
|
+
[1.0.4t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.0.4
|
|
865
|
+
[1.0.3]: https://github.com/kettle-dev/kettle-family/compare/v1.0.2...v1.0.3
|
|
866
|
+
[1.0.3t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.0.3
|
|
827
867
|
[1.0.2]: https://github.com/kettle-dev/kettle-family/compare/v1.0.1...v1.0.2
|
|
828
868
|
[1.0.2t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.0.2
|
|
829
869
|
[1.0.1]: https://github.com/kettle-dev/kettle-family/compare/v1.0.0...v1.0.1
|
data/README.md
CHANGED
|
@@ -669,7 +669,7 @@ Thanks for RTFM. ☺️
|
|
|
669
669
|
[📌gitmoji]: https://gitmoji.dev
|
|
670
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
|
|
671
671
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
672
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-2.
|
|
672
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-2.849-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
|
673
673
|
[🔐security]: https://github.com/kettle-dev/kettle-family/blob/main/SECURITY.md
|
|
674
674
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
|
675
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
|
@@ -743,14 +743,25 @@ module Kettle
|
|
|
743
743
|
|
|
744
744
|
def bump_version_results(members:, options:, phase:)
|
|
745
745
|
require_relative "version_bump"
|
|
746
|
+
require_relative "release_waves"
|
|
747
|
+
|
|
748
|
+
results = []
|
|
749
|
+
completed_target_versions = {}
|
|
750
|
+
ReleaseWaves.new(members: members).waves.each do |wave|
|
|
751
|
+
bump = VersionBump.new(
|
|
752
|
+
members: wave,
|
|
753
|
+
target_version: options[:target_version],
|
|
754
|
+
from_version: options[:from_version],
|
|
755
|
+
mode: bump_version_mode(options),
|
|
756
|
+
phase: phase,
|
|
757
|
+
dependency_target_versions: completed_target_versions
|
|
758
|
+
)
|
|
759
|
+
wave_results = bump.results
|
|
760
|
+
results.concat(wave_results)
|
|
761
|
+
break unless wave_results.all?(&:ok?)
|
|
746
762
|
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
target_version: options[:target_version],
|
|
750
|
-
from_version: options[:from_version],
|
|
751
|
-
mode: bump_version_mode(options),
|
|
752
|
-
phase: phase
|
|
753
|
-
).results
|
|
763
|
+
completed_target_versions.merge!(bump.target_versions)
|
|
764
|
+
end
|
|
754
765
|
return results if options[:check] || !options[:commit]
|
|
755
766
|
return results unless results.all?(&:ok?)
|
|
756
767
|
|
|
@@ -5,7 +5,7 @@ require "kettle/dev"
|
|
|
5
5
|
module Kettle
|
|
6
6
|
module Family
|
|
7
7
|
class DependencyFloor
|
|
8
|
-
DEPENDENCY_METHODS = %i[add_dependency add_runtime_dependency].freeze
|
|
8
|
+
DEPENDENCY_METHODS = %i[add_dependency add_runtime_dependency add_development_dependency].freeze
|
|
9
9
|
|
|
10
10
|
def initialize(released_members:, dependent_members:, mode: :dry_run)
|
|
11
11
|
@released_members = released_members
|
|
@@ -57,19 +57,41 @@ module Kettle
|
|
|
57
57
|
|
|
58
58
|
def member_from_gemspec(path)
|
|
59
59
|
spec = load_gemspec(path)
|
|
60
|
+
root = File.dirname(path)
|
|
61
|
+
dependencies = spec.runtime_dependencies.map(&:name).sort
|
|
60
62
|
Member.new(
|
|
61
63
|
name: spec.name,
|
|
62
|
-
root:
|
|
64
|
+
root: root,
|
|
63
65
|
gemspec_path: path,
|
|
64
|
-
version_file: version_file(
|
|
66
|
+
version_file: version_file(root, spec.name),
|
|
65
67
|
version: spec.version.to_s,
|
|
66
|
-
dependencies:
|
|
68
|
+
dependencies: dependencies,
|
|
69
|
+
release_dependencies: release_dependencies(root: root, spec: spec, dependencies: dependencies),
|
|
67
70
|
required_ruby_version: required_ruby_version(spec),
|
|
68
71
|
licenses: licenses(spec),
|
|
69
72
|
authors: authors(spec)
|
|
70
73
|
)
|
|
71
74
|
end
|
|
72
75
|
|
|
76
|
+
def release_dependencies(root:, spec:, dependencies:)
|
|
77
|
+
(
|
|
78
|
+
dependencies +
|
|
79
|
+
spec.development_dependencies.map(&:name) +
|
|
80
|
+
gemfile_dependencies(root)
|
|
81
|
+
).uniq.sort
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def gemfile_dependencies(root)
|
|
85
|
+
gemfile = File.join(root, "Gemfile")
|
|
86
|
+
return [] unless File.file?(gemfile)
|
|
87
|
+
|
|
88
|
+
gemfile_dependency_collector(root: root).dependencies_for(gemfile).sort
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def gemfile_dependency_collector(root:)
|
|
92
|
+
GemfileDependencyCollector.new(root: root)
|
|
93
|
+
end
|
|
94
|
+
|
|
73
95
|
def required_ruby_version(spec)
|
|
74
96
|
value = spec.required_ruby_version&.to_s&.strip
|
|
75
97
|
value.empty? ? nil : value
|
|
@@ -153,6 +175,79 @@ module Kettle
|
|
|
153
175
|
|
|
154
176
|
expanded_path.delete_prefix(prefix)
|
|
155
177
|
end
|
|
178
|
+
|
|
179
|
+
class GemfileDependencyCollector
|
|
180
|
+
GEM_METHODS = %i[gem].freeze
|
|
181
|
+
EVAL_GEMFILE_METHODS = %i[eval_gemfile].freeze
|
|
182
|
+
|
|
183
|
+
def initialize(root:)
|
|
184
|
+
@root = root
|
|
185
|
+
@dependencies = Set.new
|
|
186
|
+
@visited = Set.new
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def dependencies_for(path)
|
|
190
|
+
collect(File.expand_path(path))
|
|
191
|
+
dependencies.to_a
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
private
|
|
195
|
+
|
|
196
|
+
attr_reader :root, :dependencies, :visited
|
|
197
|
+
|
|
198
|
+
def collect(path)
|
|
199
|
+
return unless File.file?(path)
|
|
200
|
+
return if visited.include?(path)
|
|
201
|
+
|
|
202
|
+
visited << path
|
|
203
|
+
source = File.read(path)
|
|
204
|
+
parse_result = parse_source(source, path)
|
|
205
|
+
each_node(parse_result.value) do |node|
|
|
206
|
+
collect_call(path, node) if node.is_a?(Prism::CallNode)
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def collect_call(path, node)
|
|
211
|
+
args = node.arguments&.arguments || []
|
|
212
|
+
first_arg = args.first
|
|
213
|
+
dependencies << first_arg.unescaped if GEM_METHODS.include?(node.name) && first_arg.is_a?(Prism::StringNode)
|
|
214
|
+
collect(eval_gemfile_path(path, first_arg)) if EVAL_GEMFILE_METHODS.include?(node.name) && first_arg.is_a?(Prism::StringNode)
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def eval_gemfile_path(path, node)
|
|
218
|
+
gemfile_path = node.unescaped
|
|
219
|
+
return File.expand_path(gemfile_path, root) if gemfile_path.start_with?("/")
|
|
220
|
+
|
|
221
|
+
File.expand_path(gemfile_path, File.dirname(path))
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def parse_source(source, path)
|
|
225
|
+
require_prism
|
|
226
|
+
parse_result = Prism.parse(source)
|
|
227
|
+
raise Error, "could not parse Gemfile dependency file #{path}" unless parse_result.success?
|
|
228
|
+
|
|
229
|
+
parse_result
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def require_prism
|
|
233
|
+
return if defined?(Prism)
|
|
234
|
+
|
|
235
|
+
require "prism"
|
|
236
|
+
rescue LoadError => error
|
|
237
|
+
raise Error, "Gemfile dependency discovery requires Prism; install the prism gem or run on Ruby 3.3+ (#{error.message})"
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def each_node(root)
|
|
241
|
+
return enum_for(__method__, root) unless block_given?
|
|
242
|
+
|
|
243
|
+
queue = [root]
|
|
244
|
+
until queue.empty?
|
|
245
|
+
node = queue.shift
|
|
246
|
+
yield node
|
|
247
|
+
queue.concat(node.child_nodes.compact) if node.respond_to?(:child_nodes)
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
end
|
|
156
251
|
end
|
|
157
252
|
end
|
|
158
253
|
end
|
data/lib/kettle/family/member.rb
CHANGED
|
@@ -9,6 +9,7 @@ module Kettle
|
|
|
9
9
|
:version_file,
|
|
10
10
|
:version,
|
|
11
11
|
:dependencies,
|
|
12
|
+
:release_dependencies,
|
|
12
13
|
:required_ruby_version,
|
|
13
14
|
:licenses,
|
|
14
15
|
:authors
|
|
@@ -21,6 +22,7 @@ module Kettle
|
|
|
21
22
|
"version_file" => version_file,
|
|
22
23
|
"version" => version,
|
|
23
24
|
"dependencies" => dependencies,
|
|
25
|
+
"release_dependencies" => release_dependencies || dependencies,
|
|
24
26
|
"required_ruby_version" => required_ruby_version,
|
|
25
27
|
"licenses" => Array(licenses),
|
|
26
28
|
"authors" => Array(authors)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Kettle
|
|
4
|
+
module Family
|
|
5
|
+
class ReleaseWaves
|
|
6
|
+
def initialize(members:)
|
|
7
|
+
@members = members
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def waves
|
|
11
|
+
by_name = members.to_h { |member| [member.name, member] }
|
|
12
|
+
pending = by_name.keys
|
|
13
|
+
completed = []
|
|
14
|
+
[].tap do |planned_waves|
|
|
15
|
+
until pending.empty?
|
|
16
|
+
hard_ready = pending.select do |name|
|
|
17
|
+
selected_hard_dependencies_for(by_name.fetch(name), by_name).all? { |dependency| completed.include?(dependency) }
|
|
18
|
+
end
|
|
19
|
+
raise Error, "cyclic release dependency order: #{pending.join(", ")}" if hard_ready.empty?
|
|
20
|
+
|
|
21
|
+
wave_names = hard_ready.select do |name|
|
|
22
|
+
selected_dependencies_for(by_name.fetch(name), by_name).all? { |dependency| completed.include?(dependency) }
|
|
23
|
+
end
|
|
24
|
+
wave_names = [hard_ready.first] if wave_names.empty?
|
|
25
|
+
|
|
26
|
+
planned_waves << wave_names.map { |name| by_name.fetch(name) }
|
|
27
|
+
completed.concat(wave_names)
|
|
28
|
+
pending -= wave_names
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
attr_reader :members
|
|
36
|
+
|
|
37
|
+
def selected_hard_dependencies_for(member, by_name)
|
|
38
|
+
Array(member.dependencies).map(&:to_s).select { |dependency| by_name.key?(dependency) }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def selected_dependencies_for(member, by_name)
|
|
42
|
+
release_dependency_names(member).select { |dependency| by_name.key?(dependency) }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def release_dependency_names(member)
|
|
46
|
+
Array(member.release_dependencies || member.dependencies).map(&:to_s)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
data/lib/kettle/family/report.rb
CHANGED
|
@@ -357,7 +357,7 @@ module Kettle
|
|
|
357
357
|
state = result.state || {}
|
|
358
358
|
row = [
|
|
359
359
|
state.fetch("gem_name", result.member_name).to_s,
|
|
360
|
-
|
|
360
|
+
release_state_checkout(state),
|
|
361
361
|
state.fetch("version", "unknown").to_s,
|
|
362
362
|
state.fetch("latest_released", nil).to_s.empty? ? "unknown" : state.fetch("latest_released").to_s,
|
|
363
363
|
state.fetch("latest_changelog_version", nil).to_s.empty? ? "none" : state.fetch("latest_changelog_version").to_s,
|
|
@@ -372,12 +372,17 @@ module Kettle
|
|
|
372
372
|
end
|
|
373
373
|
|
|
374
374
|
def release_state_header
|
|
375
|
-
header = [["gem", "checkout", "
|
|
375
|
+
header = [["gem", "checkout", "V.rb", "V.rel", "V.ch.md", "🔼 / 🔽", "unrel", "prep", "pend"]]
|
|
376
376
|
return header unless release_state_has_branches?
|
|
377
377
|
|
|
378
378
|
[["branch", *header.first]]
|
|
379
379
|
end
|
|
380
380
|
|
|
381
|
+
def release_state_checkout(state)
|
|
382
|
+
branch = state.fetch("current_branch", nil).to_s
|
|
383
|
+
branch.empty? ? "unknown" : branch[0, 10]
|
|
384
|
+
end
|
|
385
|
+
|
|
381
386
|
def release_state_ahead_behind(state)
|
|
382
387
|
local_ahead = state.fetch("ahead", nil)
|
|
383
388
|
local_behind = state.fetch("behind", nil)
|
|
@@ -5,9 +5,9 @@ require "kettle/dev"
|
|
|
5
5
|
module Kettle
|
|
6
6
|
module Family
|
|
7
7
|
class VersionBump
|
|
8
|
-
DEPENDENCY_METHODS = %i[add_dependency add_runtime_dependency].freeze
|
|
8
|
+
DEPENDENCY_METHODS = %i[add_dependency add_runtime_dependency add_development_dependency].freeze
|
|
9
9
|
|
|
10
|
-
def initialize(members:, target_version:, from_version: nil, mode: :dry_run, phase: "bump-version")
|
|
10
|
+
def initialize(members:, target_version:, from_version: nil, mode: :dry_run, phase: "bump-version", dependency_target_versions: nil)
|
|
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)
|
|
@@ -18,15 +18,21 @@ module Kettle
|
|
|
18
18
|
@member_target_versions = members.each_with_object({}) do |member, memo|
|
|
19
19
|
memo[member.name] = resolve_target_version(member)
|
|
20
20
|
end
|
|
21
|
+
@dependency_target_versions = dependency_target_versions || member_target_versions
|
|
22
|
+
@dependency_member_names = @dependency_target_versions.keys
|
|
21
23
|
end
|
|
22
24
|
|
|
23
25
|
def results
|
|
24
26
|
members.map { |member| result_for(member) }
|
|
25
27
|
end
|
|
26
28
|
|
|
29
|
+
def target_versions
|
|
30
|
+
member_target_versions.dup
|
|
31
|
+
end
|
|
32
|
+
|
|
27
33
|
private
|
|
28
34
|
|
|
29
|
-
attr_reader :members, :target_version, :explicit_target_version, :from_version, :mode, :phase, :
|
|
35
|
+
attr_reader :members, :target_version, :explicit_target_version, :from_version, :mode, :phase, :member_target_versions, :dependency_target_versions, :dependency_member_names
|
|
30
36
|
|
|
31
37
|
def validate_version(version)
|
|
32
38
|
with_dev_errors { Kettle::Dev::VersionBump.validate_version(version) }
|
|
@@ -90,9 +96,11 @@ module Kettle
|
|
|
90
96
|
|
|
91
97
|
args = node.arguments&.arguments || []
|
|
92
98
|
name_node, requirement_node = args
|
|
93
|
-
return unless name_node.is_a?(Prism::StringNode) &&
|
|
99
|
+
return unless name_node.is_a?(Prism::StringNode) && dependency_member_names.include?(name_node.unescaped)
|
|
94
100
|
return unless requirement_node
|
|
95
|
-
dependency_target_version =
|
|
101
|
+
dependency_target_version = dependency_target_versions[name_node.unescaped]
|
|
102
|
+
return unless dependency_target_version
|
|
103
|
+
|
|
96
104
|
if same_version_dependency_requirement?(node, requirement_node)
|
|
97
105
|
return if dependency_target_version == target_version_for(member)
|
|
98
106
|
|
|
@@ -520,25 +520,7 @@ module Kettle
|
|
|
520
520
|
end
|
|
521
521
|
|
|
522
522
|
def release_waves(release_members)
|
|
523
|
-
|
|
524
|
-
pending = by_name.keys
|
|
525
|
-
completed = []
|
|
526
|
-
waves = []
|
|
527
|
-
until pending.empty?
|
|
528
|
-
wave_names = pending.select do |name|
|
|
529
|
-
selected_dependencies_for(by_name.fetch(name), by_name).all? { |dependency| completed.include?(dependency) }
|
|
530
|
-
end
|
|
531
|
-
raise Error, "cyclic release dependency order: #{pending.join(", ")}" if wave_names.empty?
|
|
532
|
-
|
|
533
|
-
waves << wave_names.map { |name| by_name.fetch(name) }
|
|
534
|
-
completed.concat(wave_names)
|
|
535
|
-
pending -= wave_names
|
|
536
|
-
end
|
|
537
|
-
waves
|
|
538
|
-
end
|
|
539
|
-
|
|
540
|
-
def selected_dependencies_for(member, by_name)
|
|
541
|
-
Array(member.dependencies).map(&:to_s).select { |dependency| by_name.key?(dependency) }
|
|
523
|
+
ReleaseWaves.new(members: release_members).waves
|
|
542
524
|
end
|
|
543
525
|
|
|
544
526
|
def append_dependency_floor_results(released_members:, dependent_members:, runner:, memo:)
|
|
@@ -565,10 +547,14 @@ module Kettle
|
|
|
565
547
|
def dependent_members_depending_on(released_members:, dependent_members:)
|
|
566
548
|
released_names = released_members.map(&:name)
|
|
567
549
|
dependent_members.select do |member|
|
|
568
|
-
|
|
550
|
+
release_dependency_names(member).any? { |dependency| released_names.include?(dependency) }
|
|
569
551
|
end
|
|
570
552
|
end
|
|
571
553
|
|
|
554
|
+
def release_dependency_names(member)
|
|
555
|
+
Array(member.release_dependencies || member.dependencies).map(&:to_s)
|
|
556
|
+
end
|
|
557
|
+
|
|
572
558
|
def append_registry_wait_result(released_members:, dependent_members:, memo:)
|
|
573
559
|
return unless execute && publish
|
|
574
560
|
return if dependent_members.empty?
|
|
@@ -807,14 +793,15 @@ module Kettle
|
|
|
807
793
|
stdout = "#{member.name} #{member.version} is already published and current HEAD matches #{tag}; skipping release"
|
|
808
794
|
reason = "already released"
|
|
809
795
|
skipped = true
|
|
810
|
-
elsif
|
|
811
|
-
stdout = "#{member.name} #{member.version} is already published, but
|
|
812
|
-
"Bump the version with `kettle-family bump
|
|
813
|
-
reason = "published version
|
|
796
|
+
elsif unreleased_changes_pending?(member)
|
|
797
|
+
stdout = "#{member.name} #{member.version} is already published, but release-state reports unreleased changes. " \
|
|
798
|
+
"Bump the version with `kettle-family bump patch --execute --only #{member.name}` before releasing."
|
|
799
|
+
reason = "published version has unreleased changes"
|
|
814
800
|
skipped = false
|
|
815
801
|
else
|
|
816
|
-
stdout = "#{member.name} #{member.version} is already published
|
|
817
|
-
|
|
802
|
+
stdout = "#{member.name} #{member.version} is already published, current HEAD is newer than #{tag}, " \
|
|
803
|
+
"and release-state reports no unreleased changes; skipping release"
|
|
804
|
+
reason = "already released; no unreleased changes"
|
|
818
805
|
skipped = true
|
|
819
806
|
end
|
|
820
807
|
|
|
@@ -833,11 +820,11 @@ module Kettle
|
|
|
833
820
|
)
|
|
834
821
|
end
|
|
835
822
|
|
|
836
|
-
def
|
|
823
|
+
def unreleased_changes_pending?(member)
|
|
837
824
|
results = ReleaseStateCheck.new(members: [member], config: config).results
|
|
838
825
|
return true unless results.all?(&:ok?)
|
|
839
826
|
|
|
840
|
-
results.any? { |result| result.state.fetch("
|
|
827
|
+
results.any? { |result| result.state.fetch("unreleased_entries", true) }
|
|
841
828
|
end
|
|
842
829
|
|
|
843
830
|
def release_tag_name(version)
|
data/lib/kettle/family.rb
CHANGED
|
@@ -15,6 +15,7 @@ require_relative "family/config"
|
|
|
15
15
|
require_relative "family/branch_target_config"
|
|
16
16
|
require_relative "family/release_state_check"
|
|
17
17
|
require_relative "family/local_install"
|
|
18
|
+
require_relative "family/release_waves"
|
|
18
19
|
require_relative "family/workflow"
|
|
19
20
|
require_relative "family/discovery"
|
|
20
21
|
require_relative "family/orderer"
|
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.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter H. Boling
|
|
@@ -291,6 +291,7 @@ files:
|
|
|
291
291
|
- lib/kettle/family/readiness_check.rb
|
|
292
292
|
- lib/kettle/family/release_state_check.rb
|
|
293
293
|
- lib/kettle/family/release_state_result.rb
|
|
294
|
+
- lib/kettle/family/release_waves.rb
|
|
294
295
|
- lib/kettle/family/report.rb
|
|
295
296
|
- lib/kettle/family/selection.rb
|
|
296
297
|
- lib/kettle/family/version.rb
|
|
@@ -303,10 +304,10 @@ licenses:
|
|
|
303
304
|
- AGPL-3.0-only
|
|
304
305
|
metadata:
|
|
305
306
|
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.
|
|
307
|
+
source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v1.0.4
|
|
308
|
+
changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v1.0.4/CHANGELOG.md
|
|
308
309
|
bug_tracker_uri: https://github.com/kettle-dev/kettle-family/issues
|
|
309
|
-
documentation_uri: https://www.rubydoc.info/gems/kettle-family/1.0.
|
|
310
|
+
documentation_uri: https://www.rubydoc.info/gems/kettle-family/1.0.4
|
|
310
311
|
funding_uri: https://github.com/sponsors/pboling
|
|
311
312
|
wiki_uri: https://github.com/kettle-dev/kettle-family/wiki
|
|
312
313
|
news_uri: https://www.railsbling.com/tags/kettle-family
|
metadata.gz.sig
CHANGED
|
Binary file
|