Module: SpecGuard::RSpec::GitCheckout

Defined in:
lib/specguard/rspec/configuration.rb

Overview

Where the checkout is sitting — which commit, and which branch — asked of git directly.

This is the last resort for both, consulted only when no environment variable named the answer.

The two questions carry different stakes and the same honesty requirement. commit_sha is the one envelope field the platform refuses a run without (Ingest::Payload#validate_commit_sha rejects a blank one and the whole POST comes back 400, every example discarded), so a run that cannot name its commit is a run whose telemetry is lost entirely — not one with a gap in it. A nil branch, by contrast, is accepted: the platform stores it, and renders it as "not reported". Which is precisely why a guess is worse here than a gap — see BRANCH_COMMAND.

Three properties, all load-bearing, and both questions have all three:

* It never raises. `git` may not be installed at all, in which case
`IO.popen` raises `Errno::ENOENT` before a subprocess ever exists.
* It never prints. `git rev-parse HEAD` outside a repository writes
"fatal: not a git repository" to stderr, and a telemetry tool that
graffitis somebody's CI log with a git error has already failed.
* It answers once per process. Each result is memoized *separately*
because a subprocess is expensive relative to everything else here,
and neither answer can change mid-run.

Constant Summary collapse

COMMIT_SHA_COMMAND =
%w[git rev-parse HEAD].freeze
BRANCH_COMMAND =

symbolic-ref, deliberately, and not rev-parse --abbrev-ref HEAD.

On a detached checkout --abbrev-ref succeeds, exit 0, printing the literal string "HEAD". actions/checkout detaches by default, so that command would report branch: "HEAD" for a large share of CI runs — a value the platform stores, renders in its Branch column, and groups by, indistinguishable from a repository that genuinely has a branch called HEAD. It is the wrong answer wearing the costume of a right one.

git symbolic-ref --short -q HEAD asks the question actually being asked: what branch is HEAD a symbolic reference to? Detached, there is no answer, and it says so the honest way — no output, exit 1, and -q keeps it silent while doing it. resolve's existing $?.success? guard turns that straight into nil, which is what a detached checkout should report and what the platform already knows how to render.

%w[git symbolic-ref --short -q HEAD].freeze

Class Method Summary collapse

Class Method Details

.branchString?

Returns the branch the checkout is on, or nil for any reason at all — no git, no repository, and notably a detached HEAD, which is nil rather than the string "HEAD". See BRANCH_COMMAND.

Returns:

  • (String, nil)

    the branch the checkout is on, or nil for any reason at all — no git, no repository, and notably a detached HEAD, which is nil rather than the string "HEAD". See BRANCH_COMMAND.



63
64
65
66
67
# File 'lib/specguard/rspec/configuration.rb', line 63

def branch
  return @branch if defined?(@branch)

  @branch = resolve(BRANCH_COMMAND)
end

.commit_shaString?

Returns the checked-out commit, or nil for any reason at all — no git, no repository, an empty repository, a broken HEAD.

Returns:

  • (String, nil)

    the checked-out commit, or nil for any reason at all — no git, no repository, an empty repository, a broken HEAD.



53
54
55
56
57
# File 'lib/specguard/rspec/configuration.rb', line 53

def commit_sha
  return @commit_sha if defined?(@commit_sha)

  @commit_sha = resolve(COMMIT_SHA_COMMAND)
end

.reset!void

This method returns an undefined value.

Drop the memoized answers — both of them. For tests, and for the rare caller that changes directory into a different checkout mid-process, where the commit and the branch have equally gone stale.



74
75
76
77
78
# File 'lib/specguard/rspec/configuration.rb', line 74

def reset!
  remove_instance_variable(:@commit_sha) if defined?(@commit_sha)
  remove_instance_variable(:@branch) if defined?(@branch)
  nil
end