Module: Kettle::Family::BranchTargetConfig

Defined in:
lib/kettle/family/branch_target_config.rb

Constant Summary collapse

MAIN_BRANCH_SKIPPING_COMMANDS =
%w[install release].freeze

Class Method Summary collapse

Class Method Details

.branch_targets_for(command, branches) ⇒ Object



13
14
15
16
17
# File 'lib/kettle/family/branch_target_config.rb', line 13

def branch_targets_for(command, branches)
  return branches unless MAIN_BRANCH_SKIPPING_COMMANDS.include?(command)

  branches.reject { |branch| branch == "main" }
end

.git_show(root, revision) ⇒ Object



103
104
105
106
# File 'lib/kettle/family/branch_target_config.rb', line 103

def git_show(root, revision)
  stdout, _stderr, status = Open3.capture3("git", "show", revision, chdir: root)
  status.success? ? stdout : nil
end

.local_branches(root) ⇒ Object

Raises:



96
97
98
99
100
101
# File 'lib/kettle/family/branch_target_config.rb', line 96

def local_branches(root)
  stdout, stderr, status = Open3.capture3("git", "for-each-ref", "--format=%(refname:short)", "refs/heads", chdir: root)
  raise Error, "could not list local branches for #{root}: #{stderr}" unless status.success?

  stdout.lines.map(&:strip).reject(&:empty?)
end

.member_configured_release_config(member:, config:) ⇒ Object



24
25
26
27
28
29
30
31
32
33
34
# File 'lib/kettle/family/branch_target_config.rb', line 24

def member_configured_release_config(member:, config:)
  return unless config&.respond_to?(:member_release_target_branches)

  branches = config.member_release_target_branches.fetch(member.name, nil)
  return if branches.nil? || branches.empty?

  data = config.data.merge(
    "release" => config.data.fetch("release", {}).merge("target_branches" => branches)
  )
  Config.new(root: member.root, path: config.path, data: data)
end

.member_git_root(member) ⇒ Object

Raises:



68
69
70
71
72
73
# File 'lib/kettle/family/branch_target_config.rb', line 68

def member_git_root(member)
  stdout, stderr, status = Open3.capture3("git", "rev-parse", "--show-toplevel", chdir: member.root)
  raise Error, "could not determine git root for #{member.root}: #{stderr}" unless status.success?

  File.realpath(stdout.strip)
end

.member_local_config_paths(root, relative_root) ⇒ Object



83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/kettle/family/branch_target_config.rb', line 83

def member_local_config_paths(root, relative_root)
  branches = local_branches(root)
  candidates = Config::DEFAULT_PATHS.map do |path|
    (relative_root == ".") ? path : File.join(relative_root, path)
  end
  branches.each_with_object([]) do |branch, memo|
    candidates.each do |path|
      content = git_show(root, "#{branch}:#{path}")
      memo << ["#{branch}:#{path}", content] if content
    end
  end
end

.member_local_release_config(member:, config:) ⇒ Object



36
37
38
39
40
41
42
43
44
45
46
# File 'lib/kettle/family/branch_target_config.rb', line 36

def member_local_release_config(member:, config:)
  member_config = Config.load(root: member.root)
  member_config = member_local_release_config_from_branch(member) || member_config unless member_config.path
  return unless member_config.path
  return if same_config_path?(config&.path, member_config.path)
  return if member_config.release_target_branches.empty?

  member_config
rescue Errno::ENOENT
  nil
end

.member_local_release_config_from_branch(member) ⇒ Object



55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/kettle/family/branch_target_config.rb', line 55

def member_local_release_config_from_branch(member)
  root = member_git_root(member)
  relative_root = member_relative_root(member, root)
  member_local_config_paths(root, relative_root).each do |config_ref, content|
    loaded = YAML.safe_load(content) || {}
    branch_config = Config.new(root: member.root, path: config_ref, data: loaded)
    return branch_config unless branch_config.release_target_branches.empty?
  end
  nil
rescue Error, Psych::SyntaxError
  nil
end

.member_relative_root(member, root) ⇒ Object

Raises:



75
76
77
78
79
80
81
# File 'lib/kettle/family/branch_target_config.rb', line 75

def member_relative_root(member, root)
  member_root = File.realpath(member.root)
  return "." if member_root == root
  return member_root.delete_prefix("#{root}/") if member_root.start_with?("#{root}/")

  raise Error, "member root #{member.root} is outside git root #{root}"
end

.member_release_config(member:, config:) ⇒ Object



19
20
21
22
# File 'lib/kettle/family/branch_target_config.rb', line 19

def member_release_config(member:, config:)
  member_configured_release_config(member: member, config: config) ||
    member_local_release_config(member: member, config: config)
end

.same_config_path?(left, right) ⇒ Boolean

Returns:

  • (Boolean)


48
49
50
51
52
53
# File 'lib/kettle/family/branch_target_config.rb', line 48

def same_config_path?(left, right)
  return false if left.to_s.empty? || right.to_s.empty?
  return false unless File.file?(left) && File.file?(right)

  File.realpath(left) == File.realpath(right)
end