diff --git a/Library/Homebrew/extend/git_repository.rb b/Library/Homebrew/extend/git_repository.rb index 8e11ff5a09325..e490e12eeebb6 100644 --- a/Library/Homebrew/extend/git_repository.rb +++ b/Library/Homebrew/extend/git_repository.rb @@ -18,9 +18,7 @@ def git? # Gets the URL of the Git origin remote. sig { returns(T.nilable(String)) } def git_origin - return if !git? || !Utils::Git.available? - - Utils.popen_read(Utils::Git.git, "config", "--get", "remote.origin.url", chdir: self).chomp.presence + popen_git("config", "--get", "remote.origin.url") end # Sets the URL of the Git origin remote. @@ -47,26 +45,19 @@ def git_short_head(length: nil, safe: false) # Gets the relative date of the last commit, e.g. "1 hour ago" sig { returns(T.nilable(String)) } def git_last_commit - return if !git? || !Utils::Git.available? - - Utils.popen_read(Utils::Git.git, "show", "-s", "--format=%cr", "HEAD", chdir: self).chomp.presence + popen_git("show", "-s", "--format=%cr", "HEAD") end # Gets the name of the currently checked-out branch, or HEAD if the repository is in a detached HEAD state. - sig { returns(T.nilable(String)) } - def git_branch - return if !git? || !Utils::Git.available? - - Utils.popen_read(Utils::Git.git, "rev-parse", "--abbrev-ref", "HEAD", chdir: self).chomp.presence + sig { params(safe: T::Boolean).returns(T.nilable(String)) } + def git_branch(safe: false) + popen_git("rev-parse", "--abbrev-ref", "HEAD", safe: safe) end # Gets the name of the default origin HEAD branch. sig { returns(T.nilable(String)) } def git_origin_branch - return if !git? || !Utils::Git.available? - - Utils.popen_read(Utils::Git.git, "symbolic-ref", "-q", "--short", "refs/remotes/origin/HEAD", chdir: self) - .chomp.presence&.split("/")&.last + popen_git("symbolic-ref", "-q", "--short", "refs/remotes/origin/HEAD")&.split("/")&.last end # Returns true if the repository's current branch matches the default origin branch. @@ -78,23 +69,19 @@ def git_default_origin_branch? # Returns the date of the last commit, in YYYY-MM-DD format. sig { returns(T.nilable(String)) } def git_last_commit_date - return if !git? || !Utils::Git.available? - - Utils.popen_read(Utils::Git.git, "show", "-s", "--format=%cd", "--date=short", "HEAD", chdir: self).chomp.presence + popen_git("show", "-s", "--format=%cd", "--date=short", "HEAD") end # Gets the full commit message of the specified commit, or of the HEAD commit if unspecified. - sig { params(commit: String).returns(T.nilable(String)) } - def git_commit_message(commit = "HEAD") - return if !git? || !Utils::Git.available? - - Utils.popen_read(Utils::Git.git, "log", "-1", "--pretty=%B", commit, "--", chdir: self, err: :out).strip.presence + sig { params(commit: String, safe: T::Boolean).returns(T.nilable(String)) } + def git_commit_message(commit = "HEAD", safe: false) + popen_git("log", "-1", "--pretty=%B", commit, "--", safe: safe, err: :out)&.strip end private - sig { params(args: T.untyped, safe: T::Boolean).returns(T.nilable(String)) } - def popen_git(*args, safe: false) + sig { params(args: T.untyped, safe: T::Boolean, err: T.nilable(Symbol)).returns(T.nilable(String)) } + def popen_git(*args, safe: false, err: nil) unless git? return unless safe @@ -107,6 +94,6 @@ def popen_git(*args, safe: false) raise "Git is unavailable" end - T.unsafe(Utils).popen_read(Utils::Git.git, *args, safe: safe, chdir: self).chomp.presence + T.unsafe(Utils).popen_read(Utils::Git.git, *args, safe: safe, chdir: self, err: err).chomp.presence end end diff --git a/Library/Homebrew/test/utils/git_repository_spec.rb b/Library/Homebrew/test/utils/git_repository_spec.rb index 3288ccfe3a3fe..e2df6b4e389d1 100644 --- a/Library/Homebrew/test/utils/git_repository_spec.rb +++ b/Library/Homebrew/test/utils/git_repository_spec.rb @@ -37,20 +37,21 @@ system "git", "init" Pathname("README.md").write("README") system "git", "add", "README.md" - system "git", "commit", "-m", "File added" + system "git", "commit", "-m", commit_message + system "git", "checkout", "-b", branch_name end end + let(:commit_message) { "File added" } + let(:branch_name) { "test-branch" } + let(:head_revision) { HOMEBREW_CACHE.cd { `git rev-parse HEAD`.chomp } } let(:short_head_revision) { HOMEBREW_CACHE.cd { `git rev-parse --short HEAD`.chomp } } - describe ".git_head" do - it "returns the revision at HEAD if repo parameter is specified" do + describe "::git_head" do + it "returns the revision at HEAD" do expect(described_class.git_head(HOMEBREW_CACHE)).to eq(head_revision) expect(described_class.git_head(HOMEBREW_CACHE, length: 5)).to eq(head_revision[0...5]) - end - - it "returns the revision at HEAD if repo parameter is omitted" do HOMEBREW_CACHE.cd do expect(described_class.git_head).to eq(head_revision) expect(described_class.git_head(length: 5)).to eq(head_revision[0...5]) @@ -60,13 +61,10 @@ include_examples "git_repository helper function", :git_head end - describe ".git_short_head" do - it "returns the short revision at HEAD if repo parameter is specified" do + describe "::git_short_head" do + it "returns the short revision at HEAD" do expect(described_class.git_short_head(HOMEBREW_CACHE)).to eq(short_head_revision) expect(described_class.git_short_head(HOMEBREW_CACHE, length: 5)).to eq(head_revision[0...5]) - end - - it "returns the short revision at HEAD if repo parameter is omitted" do HOMEBREW_CACHE.cd do expect(described_class.git_short_head).to eq(short_head_revision) expect(described_class.git_short_head(length: 5)).to eq(head_revision[0...5]) @@ -75,4 +73,28 @@ include_examples "git_repository helper function", :git_short_head end + + describe "::git_branch" do + include_examples "git_repository helper function", :git_branch + + it "returns the current Git branch" do + expect(described_class.git_branch(HOMEBREW_CACHE)).to eq(branch_name) + HOMEBREW_CACHE.cd do + expect(described_class.git_branch).to eq(branch_name) + end + end + end + + describe "::git_commit_message" do + include_examples "git_repository helper function", :git_commit_message + + it "returns the commit message of HEAD" do + expect(described_class.git_commit_message(HOMEBREW_CACHE)).to eq(commit_message) + expect(described_class.git_commit_message(HOMEBREW_CACHE, commit: head_revision)).to eq(commit_message) + HOMEBREW_CACHE.cd do + expect(described_class.git_commit_message).to eq(commit_message) + expect(described_class.git_commit_message(commit: head_revision)).to eq(commit_message) + end + end + end end diff --git a/Library/Homebrew/utils/git_repository.rb b/Library/Homebrew/utils/git_repository.rb index 6ade0505bfe4a..6c0e983a8921e 100644 --- a/Library/Homebrew/utils/git_repository.rb +++ b/Library/Homebrew/utils/git_repository.rb @@ -4,6 +4,7 @@ module Utils extend T::Sig + # Gets the full commit hash of the HEAD commit. sig { params( repo: T.any(String, Pathname), @@ -18,6 +19,7 @@ def self.git_head(repo = Pathname.pwd, length: nil, safe: true) repo.git_head(safe: safe) end + # Gets a short commit hash of the HEAD commit. sig { params( repo: T.any(String, Pathname), @@ -29,4 +31,29 @@ def self.git_short_head(repo = Pathname.pwd, length: nil, safe: true) repo = Pathname(repo).extend(GitRepositoryExtension) repo.git_short_head(length: length, safe: safe) end + + # Gets the name of the currently checked-out branch, or HEAD if the repository is in a detached HEAD state. + sig { + params( + repo: T.any(String, Pathname), + safe: T::Boolean, + ).returns(T.nilable(String)) + } + def self.git_branch(repo = Pathname.pwd, safe: true) + repo = Pathname(repo).extend(GitRepositoryExtension) + repo.git_branch(safe: safe) + end + + # Gets the full commit message of the specified commit, or of the HEAD commit if unspecified. + sig { + params( + repo: T.any(String, Pathname), + commit: String, + safe: T::Boolean, + ).returns(T.nilable(String)) + } + def self.git_commit_message(repo = Pathname.pwd, commit: "HEAD", safe: true) + repo = Pathname(repo).extend(GitRepositoryExtension) + repo.git_commit_message(commit, safe: safe) + end end