diff --git a/fastlane/lib/fastlane/actions/git_remote_branch.rb b/fastlane/lib/fastlane/actions/git_remote_branch.rb new file mode 100644 index 00000000000..d79c3879a50 --- /dev/null +++ b/fastlane/lib/fastlane/actions/git_remote_branch.rb @@ -0,0 +1,57 @@ +module Fastlane + module Actions + class GitRemoteBranchAction < Action + def self.run(params) + Actions.git_remote_branch_name(params[:remote_name]) + end + + ##################################################### + # @!group Documentation + ##################################################### + + def self.description + "Returns the name of the current git remote default branch" + end + + def self.details + "If no default remote branch could be found, this action will return nil. This is a wrapper for the internal action Actions.git_default_remote_branch_name" + end + + def self.available_options + [ + FastlaneCore::ConfigItem.new(key: :remote_name, + env_name: "FL_REMOTE_REPOSITORY_NAME", + description: "The remote repository to check", + optional: true) + ] + end + + def self.output + [] + end + + def self.authors + ["SeanMcNeil"] + end + + def self.is_supported?(platform) + true + end + + def self.example_code + [ + 'git_remote_branch # Query git for first available remote name', + 'git_remote_branch(remote_name:"upstream") # Provide a remote name' + ] + end + + def self.return_type + :string + end + + def self.category + :source_control + end + end + end +end diff --git a/fastlane/lib/fastlane/helper/git_helper.rb b/fastlane/lib/fastlane/helper/git_helper.rb index 5dea94cc9e6..c8b181dd988 100644 --- a/fastlane/lib/fastlane/helper/git_helper.rb +++ b/fastlane/lib/fastlane/helper/git_helper.rb @@ -131,12 +131,24 @@ def self.git_branch # Returns the checked out git branch name or "HEAD" if you're in detached HEAD state def self.git_branch_name_using_HEAD # Rescues if not a git repo or no commits in a git repo - begin - Actions.sh("git rev-parse --abbrev-ref HEAD", log: false).chomp - rescue => err - UI.verbose("Error getting git branch: #{err.message}") - nil + Actions.sh("git rev-parse --abbrev-ref HEAD", log: false).chomp + rescue => err + UI.verbose("Error getting git branch: #{err.message}") + nil + end + + # Returns the default git remote branch name + def self.git_remote_branch_name(remote_name) + # Rescues if not a git repo or no remote repo + if remote_name + Actions.sh("git remote show #{remote_name} | grep 'HEAD branch' | sed 's/.*: //'", log: false).chomp + else + # Query git for the current remote head + Actions.sh("variable=$(git remote) && git remote show $variable | grep 'HEAD branch' | sed 's/.*: //'", log: false).chomp end + rescue => err + UI.verbose("Error getting git default remote branch: #{err.message}") + nil end private_class_method diff --git a/fastlane/spec/actions_specs/git_remote_branch_spec.rb b/fastlane/spec/actions_specs/git_remote_branch_spec.rb new file mode 100644 index 00000000000..21dd6e56ab2 --- /dev/null +++ b/fastlane/spec/actions_specs/git_remote_branch_spec.rb @@ -0,0 +1,83 @@ +describe Fastlane do + describe Fastlane::FastFile do + directory = "fl_spec_default_remote_branch" + + describe "Git Remote Branch Action" do + it "generates the correct git command for retrieving default branch from remote" do + result = Fastlane::FastFile.new.parse("lane :test do + git_remote_branch + end").runner.execute(:test) + + expect(result).to eq("variable=$(git remote) && git remote show $variable | grep 'HEAD branch' | sed 's/.*: //'") + end + end + + describe "Git Remote Branch Action with optional remote name" do + it "generates the correct git command for retrieving default branch using provided remote name" do + result = Fastlane::FastFile.new.parse("lane :test do + git_remote_branch(remote_name:'upstream') + end").runner.execute(:test) + + expect(result).to eq("git remote show upstream | grep 'HEAD branch' | sed 's/.*: //'") + end + end + + context "runs the command in a directory with no git repo" do + it "Confirms that no default remote is found" do + test_directory_path = Dir.mktmpdir(directory) + + Dir.chdir(test_directory_path) do + expect(Fastlane::Actions).to receive(:sh) + .with("variable=$(git remote) && git remote show $variable | grep 'HEAD branch' | sed 's/.*: //'", log: false) + + result = Fastlane::FastFile.new.parse("lane :test do + git_remote_branch + end").runner.execute(:test) + + expect(result).to be_nil + end + end + end + + context "runs the command in a directory with no remote git repo" do + it "Confirms that no default remote is found" do + test_directory_path = Dir.mktmpdir(directory) + + Dir.chdir(test_directory_path) do + `git init` + + File.write('test_file', <<-TESTFILE) + 'Hello' + TESTFILE + `git add .` + `git commit --message "Test file"` + + expect(Fastlane::Actions).to receive(:sh) + .with("variable=$(git remote) && git remote show $variable | grep 'HEAD branch' | sed 's/.*: //'", log: false) + + result = Fastlane::FastFile.new.parse("lane :test do + git_remote_branch + end").runner.execute(:test) + + expect(result).to be_nil + end + end + end + + context "runs the command with a remote git repo" do + it "Confirms that a default remote is found" do + allow(Fastlane::Actions).to receive(:sh) + .with("variable=$(git remote) && git remote show $variable | grep 'HEAD branch' | sed 's/.*: //'", log: false) + .and_return("main") + allow(Fastlane::Actions).to receive(:git_branch).and_return(nil) + + result = Fastlane::FastFile.new.parse("lane :test do + git_remote_branch + end").runner.execute(:test) + + expect(result).to eq("main") + end + end + + end +end