Module: Moult::Git
- Defined in:
- lib/moult/git.rb
Overview
Thin, injection-safe wrapper over the git CLI. All commands run with an explicit working directory and argument array (never a shell string), and failures surface as nil/false rather than exceptions so callers can degrade gracefully outside a repository.
Class Method Summary collapse
-
.capture(dir, *args) ⇒ Object
Run a git subcommand, returning stdout, or nil on any failure.
-
.diff_name_status(dir, ref) ⇒ String?
git diff --name-status REF: one "\t " line per changed file between refand the working tree (renames carry two paths). -
.diff_unified_zero(dir, ref) ⇒ String?
git diff --unified=0 REF: a context-free unified diff betweenrefand the working tree. -
.head_ref(dir) ⇒ String?
The HEAD commit sha, or nil outside a repo.
-
.listed_files(dir) ⇒ Array<String>
Tracked + untracked-but-not-ignored files, relative to
dir, respecting .gitignore. -
.log_name_only(dir, since:) ⇒ String?
Raw
git logfile listing for churn: one path per line, blank lines between commits. -
.merge_base(dir, base_ref) ⇒ String?
The common ancestor of
base_refand HEAD — the "new code" boundary, the same merge-base semantics SonarQube/CodeScene use to scope a diff. -
.repo?(dir) ⇒ Boolean
Whether
diris inside a git work tree.
Class Method Details
.capture(dir, *args) ⇒ Object
Run a git subcommand, returning stdout, or nil on any failure.
76 77 78 79 80 81 |
# File 'lib/moult/git.rb', line 76 def capture(dir, *args) out, _, status = Open3.capture3("git", *args, chdir: dir) status.success? ? out : nil rescue SystemCallError nil end |
.diff_name_status(dir, ref) ⇒ String?
git diff --name-status REF: one "ref and the working tree (renames carry two paths). Empty string
when nothing changed; nil on failure.
62 63 64 |
# File 'lib/moult/git.rb', line 62 def diff_name_status(dir, ref) capture(dir, "diff", "--name-status", ref) end |
.diff_unified_zero(dir, ref) ⇒ String?
git diff --unified=0 REF: a context-free unified diff between ref and the
working tree. Zero context means each hunk header's new-side range
(@@ -a,b +c,d @@) is exactly the changed/added lines — what the gate needs
to scope findings to the diff. Empty string when nothing changed; nil on failure.
71 72 73 |
# File 'lib/moult/git.rb', line 71 def diff_unified_zero(dir, ref) capture(dir, "diff", "--unified=0", ref) end |
.head_ref(dir) ⇒ String?
Returns the HEAD commit sha, or nil outside a repo.
22 23 24 25 |
# File 'lib/moult/git.rb', line 22 def head_ref(dir) out = capture(dir, "rev-parse", "HEAD") out&.strip end |
.listed_files(dir) ⇒ Array<String>
Returns tracked + untracked-but-not-ignored files,
relative to dir, respecting .gitignore. Empty outside a repo.
29 30 31 32 33 34 |
# File 'lib/moult/git.rb', line 29 def listed_files(dir) out = capture(dir, "ls-files", "--cached", "--others", "--exclude-standard", "-z") return [] unless out out.split("\x0").reject(&:empty?) end |
.log_name_only(dir, since:) ⇒ String?
Raw git log file listing for churn: one path per line, blank lines
between commits. Each commit lists a touched path at most once.
39 40 41 |
# File 'lib/moult/git.rb', line 39 def log_name_only(dir, since:) capture(dir, "log", "--since=#{since}", "--name-only", "--pretty=format:") end |
.merge_base(dir, base_ref) ⇒ String?
The common ancestor of base_ref and HEAD — the "new code" boundary, the
same merge-base semantics SonarQube/CodeScene use to scope a diff.
53 54 55 56 |
# File 'lib/moult/git.rb', line 53 def merge_base(dir, base_ref) out = capture(dir, "merge-base", base_ref, "HEAD") out&.strip end |
.repo?(dir) ⇒ Boolean
Returns whether dir is inside a git work tree.
14 15 16 17 18 19 |
# File 'lib/moult/git.rb', line 14 def repo?(dir) out, _, status = Open3.capture3("git", "rev-parse", "--is-inside-work-tree", chdir: dir) status.success? && out.strip == "true" rescue SystemCallError false end |