Class: RobotLab::To::CommitManager

Inherits:
Object
  • Object
show all
Defined in:
lib/robot_lab/to/commit_manager.rb

Overview

All git operations needed by the orchestrator.

All subprocess calls use explicit argv arrays (no shell interpolation). GIT_TERMINAL_PROMPT=0 prevents credential prompts from hanging the loop.

Constant Summary collapse

GIT_ENV =
{ "GIT_TERMINAL_PROMPT" => "0" }.freeze

Instance Method Summary collapse

Constructor Details

#initialize(work_dir: Dir.pwd) ⇒ CommitManager

Returns a new instance of CommitManager.



14
15
16
# File 'lib/robot_lab/to/commit_manager.rb', line 14

def initialize(work_dir: Dir.pwd)
  @work_dir = work_dir
end

Instance Method Details

#add_allObject



41
42
43
# File 'lib/robot_lab/to/commit_manager.rb', line 41

def add_all
  git("add", "-A")
end

#add_to_local_exclude(entry) ⇒ Object



75
76
77
78
79
80
81
82
# File 'lib/robot_lab/to/commit_manager.rb', line 75

def add_to_local_exclude(entry)
  exclude = Pathname.new(@work_dir).join(".git", "info", "exclude")
  exclude.parent.mkpath
  content = exclude.exist? ? exclude.read : ""
  return if content.include?(entry)

  File.open(exclude, "a") { |f| f.puts(entry) }
end

#changed_files_since(base_sha) ⇒ Object



84
85
86
87
88
# File 'lib/robot_lab/to/commit_manager.rb', line 84

def changed_files_since(base_sha)
  out, _err, _status = Open3.capture3(GIT_ENV, "git", "diff", "--name-only",
                                      "#{base_sha}..HEAD", chdir: @work_dir)
  out.lines.map(&:chomp).reject(&:empty?)
end

#changed_vs_worktree(ref) ⇒ Object

Files differing between a ref and the current working tree (uncommitted changes), INCLUDING new untracked files. Used by pairwise evals to compare a draft against its parent -- and a prose doer typically CREATES the document, so the untracked case is the common one (git diff alone misses new files).



95
96
97
98
99
100
# File 'lib/robot_lab/to/commit_manager.rb', line 95

def changed_vs_worktree(ref)
  tracked, = Open3.capture3(GIT_ENV, "git", "diff", "--name-only", ref, chdir: @work_dir)
  untracked, = Open3.capture3(GIT_ENV, "git", "ls-files", "--others", "--exclude-standard",
                              chdir: @work_dir)
  (tracked.lines + untracked.lines).map(&:chomp).reject(&:empty?).uniq
end

#checkout_branch(name) ⇒ Object

Switch to an existing branch (used when resuming a prior run).



31
32
33
# File 'lib/robot_lab/to/commit_manager.rb', line 31

def checkout_branch(name)
  git("checkout", name)
end

#commit(message) ⇒ Object

Raises:



45
46
47
48
49
50
51
52
53
54
# File 'lib/robot_lab/to/commit_manager.rb', line 45

def commit(message)
  out, err, status = Open3.capture3(
    GIT_ENV, "git", "-c", "commit.gpgsign=false", "-c", "tag.gpgsign=false",
    "commit", "-m", message,
    chdir: @work_dir
  )
  return if status.success?

  raise CommitFailedError.new("git commit failed", output: (out + err).strip)
end

#create_branch(name) ⇒ Object



26
27
28
# File 'lib/robot_lab/to/commit_manager.rb', line 26

def create_branch(name)
  git("checkout", "-b", name)
end

#current_branchObject



18
19
20
# File 'lib/robot_lab/to/commit_manager.rb', line 18

def current_branch
  git("rev-parse", "--abbrev-ref", "HEAD").chomp
end

#diff_stat(base_sha) ⇒ Object



69
70
71
72
73
# File 'lib/robot_lab/to/commit_manager.rb', line 69

def diff_stat(base_sha)
  out, _err, _status = Open3.capture3(GIT_ENV, "git", "diff", "--stat",
                                      "#{base_sha}..HEAD", chdir: @work_dir)
  parse_diff_stat(out)
end

#head_exists?Boolean

Returns:

  • (Boolean)


56
57
58
59
60
# File 'lib/robot_lab/to/commit_manager.rb', line 56

def head_exists?
  _out, _err, status = Open3.capture3(GIT_ENV, "git", "rev-parse", "--verify", "HEAD",
                                      chdir: @work_dir)
  status.success?
end

#head_shaObject



22
23
24
# File 'lib/robot_lab/to/commit_manager.rb', line 22

def head_sha
  git("rev-parse", "HEAD").chomp
end

#reset_hardObject



62
63
64
65
66
67
# File 'lib/robot_lab/to/commit_manager.rb', line 62

def reset_hard
  return unless head_exists?

  git("reset", "--hard", "HEAD")
  git("clean", "-fd")
end

#show(ref, path) ⇒ Object

Contents of a path at a given ref, or "" when it did not exist there.



103
104
105
106
107
# File 'lib/robot_lab/to/commit_manager.rb', line 103

def show(ref, path)
  out, _err, status = Open3.capture3(GIT_ENV, "git", "show", "#{ref}:#{path}",
                                     chdir: @work_dir)
  status.success? ? out : ""
end

#staged?Boolean

Returns:

  • (Boolean)


35
36
37
38
39
# File 'lib/robot_lab/to/commit_manager.rb', line 35

def staged?
  _out, _err, status = Open3.capture3(GIT_ENV, "git", "diff", "--cached", "--quiet",
                                      chdir: @work_dir)
  !status.success? # exit 1 = changes are staged
end

#tracked_filesObject

All tracked files — the project's committed layout. Excludes the run dir (it's in .git/info/exclude), so it's a clean workspace digest.



111
112
113
114
115
116
# File 'lib/robot_lab/to/commit_manager.rb', line 111

def tracked_files
  out, _err, status = Open3.capture3(GIT_ENV, "git", "ls-files", chdir: @work_dir)
  return [] unless status.success?

  out.lines.map(&:chomp).reject(&:empty?)
end