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



86
87
88
89
# File 'lib/kettle/family/branch_target_config.rb', line 86

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:



79
80
81
82
83
84
# File 'lib/kettle/family/branch_target_config.rb', line 79

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_git_root(member) ⇒ Object

Raises:



51
52
53
54
55
56
# File 'lib/kettle/family/branch_target_config.rb', line 51

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



66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/kettle/family/branch_target_config.rb', line 66

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



19
20
21
22
23
24
25
26
27
28
29
# File 'lib/kettle/family/branch_target_config.rb', line 19

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



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

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:



58
59
60
61
62
63
64
# File 'lib/kettle/family/branch_target_config.rb', line 58

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

.same_config_path?(left, right) ⇒ Boolean

Returns:

  • (Boolean)


31
32
33
34
35
36
# File 'lib/kettle/family/branch_target_config.rb', line 31

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