require 'spec_helper' describe GitReflow::Workflows::Core do let(:feature_branch) { 'new-feature' } let(:existing_pull_requests) { Fixture.new('pull_requests/pull_requests.json').to_json_hashie } let(:existing_gh_pull_request) { GitReflow::GitServer::GitHub::PullRequest.new existing_pull_requests.first } let(:pull_request_message_file) { "#{GitReflow.git_root_dir}/.git/GIT_REFLOW_PR_MSG" } let(:workflow) { described_class } before do allow(workflow).to receive(:current_branch).and_return(feature_branch) allow_any_instance_of(HighLine).to receive(:choose) end describe ".load_workflow(workflow_path)" do let(:workflow_path) { "/tmp/Workflow" } subject { GitReflow::Workflows::Core.load_workflow(workflow_path) } before { allow(GitReflow::Workflows::Core).to receive(:load_workflow).and_call_original } it "returns `nil` if the workflow path doesn't exist" do allow(File).to receive(:exists?).and_return(false) expect(subject).to be_nil end it "evaluates the workflow file in the context of the class" do workflow_content = "# testing" allow(File).to receive(:exists?).with("#{GitReflow.git_root_dir}/Workflow").and_return(false) allow(File).to receive(:exists?).with(workflow_path).and_return(true) expect(File).to receive(:read).with(workflow_path).and_return(workflow_content) expect(GitReflow::Workflows::Core).to receive(:load_raw_workflow).with(workflow_content) subject end end describe ".load_raw_workflow(workflow_string)" do before { allow(GitReflow::Workflows::Core).to receive(:load_workflow).and_call_original } it "evaluates the raw string in the context of the Core workflow" do workflow_content = <<~WORKFLOW_CONTENT command :dummy do puts "Dummy" end WORKFLOW_CONTENT fake_binding = instance_double(Binding) expect(fake_binding).to receive(:eval).with(workflow_content) expect(described_class).to receive(:binding).and_return(fake_binding) GitReflow::Workflows::Core.load_raw_workflow(workflow_content) end end describe ".setup" do subject { workflow.setup } before do allow(File).to receive(:exist?).and_return(false) stub_command_line_inputs({ 'Set the minimum number of approvals (leaving blank will require approval from all commenters): ' => '' }) end specify { expect { subject }.to have_run_command_silently "git config -f #{GitReflow::Config::CONFIG_FILE_PATH} --replace-all core.editor \"#{GitReflow.default_editor}\"", blocking: false } specify { expect { subject }.to have_said "Updated git's editor (via git config key 'core.editor') to: #{GitReflow.default_editor}.", :notice } context "core.editor git config has already been set" do before do allow(GitReflow::Config).to receive(:get) { "" } allow(workflow.git_config).to receive(:get) { "" } allow(workflow.git_config).to receive(:get).with('core.editor').and_return('emacs') end specify { expect { subject }.to_not have_run_command_silently "git config -f #{GitReflow::Config::CONFIG_FILE_PATH} --replace-all core.editor \"#{GitReflow.default_editor}\"", blocking: false } end context "git-reflow has not been setup before" do it "notifies the user of global setup" do expect { subject }.to have_said "We'll walk you through setting up git-reflow's defaults for all your projects.", :notice expect { subject }.to have_said "In the future, you can run \`git-reflow setup --local\` from the root of any project you want to setup differently.", :notice end it "creates a .gitconfig.reflow file and includes it in the user's global git config" do expect { subject }.to have_run_command "touch #{GitReflow::Config::CONFIG_FILE_PATH}" expect { subject }.to have_run_command_silently "git config --global --add include.path \"#{GitReflow::Config::CONFIG_FILE_PATH}\"", blocking: false expect { subject }.to have_said "Created #{GitReflow::Config::CONFIG_FILE_PATH} for git-reflow specific configurations.", :notice expect { subject }.to have_said "Added #{GitReflow::Config::CONFIG_FILE_PATH} to include.path in $HOME/.gitconfig.", :notice end it "sets the default approval minimum and regex" do expect { subject }.to have_run_command_silently "git config -f #{GitReflow::Config::CONFIG_FILE_PATH} --replace-all constants.minimumApprovals \"\"", blocking: false expect { subject }.to have_run_command_silently "git config -f #{GitReflow::Config::CONFIG_FILE_PATH} --replace-all constants.approvalRegex \"#{GitReflow::GitServer::PullRequest::DEFAULT_APPROVAL_REGEX}\"", blocking: false end context "when setting a custom approval minimum" do before do stub_command_line_inputs({ 'Set the minimum number of approvals (leaving blank will require approval from all commenters): ' => '3' }) end specify { expect { subject }.to have_run_command_silently "git config -f #{GitReflow::Config::CONFIG_FILE_PATH} --replace-all constants.minimumApprovals \"3\"", blocking: false } end end context "git-reflow has been setup before" do before do allow(File).to receive(:exist?).and_return(true) end it "doesn't create another .gitconfig.reflow file" do expect { subject }.to_not have_run_command "touch #{GitReflow::Config::CONFIG_FILE_PATH}" expect { subject }.to_not have_said "Created #{GitReflow::Config::CONFIG_FILE_PATH} for git-reflow specific configurations.", :notice end it "doesn't add the .gitconfig.reflow file to the git-config include path" do expect { subject }.to_not have_run_command_silently "git config --global --add include.path \"#{GitReflow::Config::CONFIG_FILE_PATH}\"", blocking: false expect { subject }.to_not have_said "Added #{GitReflow::Config::CONFIG_FILE_PATH} to include.path in $HOME/.gitconfig.", :notice end end end describe ".start" do let(:feature_branch) { 'new_feature' } subject { workflow.start feature_branch: feature_branch } it "updates the local repo and creates a new branch" do expect { subject }.to have_run_commands_in_order [ "git checkout master", "git pull origin master", "git push origin master:refs/heads/#{feature_branch}", "git checkout --track -b #{feature_branch} origin/#{feature_branch}" ] end context "but no branch name is provided" do let(:feature_branch) { "" } it "doesn't run any commands and returns usage" do expect { subject }.to_not have_run_command "git checkout master" expect { subject }.to_not have_run_command "git pull origin master" expect { subject }.to_not have_run_command "git push origin master:refs/heads/#{feature_branch}" expect { subject }.to_not have_run_command "git checkout --track -b #{feature_branch} origin/#{feature_branch}" expect { subject }.to have_said "usage: git-reflow start [new-branch-name]", :error end end it "starts from a different base branch when one is supplied" do expect { workflow.start feature_branch: feature_branch, base: 'development' }.to have_run_commands_in_order [ "git checkout development", "git pull origin development", "git push origin development:refs/heads/#{feature_branch}", "git checkout --track -b #{feature_branch} origin/#{feature_branch}" ] end it "starts from a different base branch when one is configured" do allow(GitReflow::Config).to receive(:get).with("reflow.base-branch").and_return("sudo-master") expect { workflow.start feature_branch: feature_branch }.to have_run_commands_in_order [ "git checkout sudo-master", "git pull origin sudo-master", "git push origin sudo-master:refs/heads/#{feature_branch}", "git checkout --track -b #{feature_branch} origin/#{feature_branch}" ] end end describe ".review" do let(:feature_branch) { 'new-feature' } let(:user) { 'reenhanced' } let(:password) { 'shazam' } let(:repo) { 'repo' } let(:inputs) { {} } before do allow(workflow).to receive(:remote_user).and_return(user) allow(GitReflow).to receive(:git_server).and_return(GitReflow::GitServer) allow(workflow.git_server).to receive(:get_build_status).and_return(Struct.new(:state, :description, :url, :target_url).new) allow(workflow.git_server).to receive(:find_open_pull_request).and_return(nil) allow(workflow.git_server).to receive(:create_pull_request).and_return(existing_gh_pull_request) allow(File).to receive(:open).with(pull_request_message_file, 'w') allow(File).to receive(:read).with(pull_request_message_file).and_return("bingo") allow(File).to receive(:delete) stub_command_line_inputs({ "Submit pull request? (Y)" => "" }) end subject { workflow.review inputs } it "fetches updates to the base branch" do expect { subject }.to have_run_command "git fetch origin master" end it "pushes the current branch to the remote repo" do expect { subject }.to have_run_command "git push origin #{feature_branch}" end it "uses the current branch name as the text for the PR" do fake_file = double expect(File).to receive(:open).with(pull_request_message_file, "w").and_yield(fake_file) expect(fake_file).to receive(:write).with(workflow.current_branch) subject end it "opens the pull request file for modification" do allow(File).to receive(:open).with(pull_request_message_file, 'w') expect { subject }.to have_run_command "#{GitReflow.git_editor_command} #{pull_request_message_file}" end it "reads the file then cleans up the temporary pull request message file" do expect(File).to receive(:read).with(pull_request_message_file) expect(File).to receive(:delete).with(pull_request_message_file) subject end it "displays a review of the PR before submitting it" do expect { subject }.to have_said "\nReview your PR:\n" expect { subject }.to have_said "Title:\nbingo\n\n" expect { subject }.to have_said "Body:\n\n\n" end context "and a PR template exists" do let(:template_content) { "hey now" } before do allow(workflow).to receive(:pull_request_template).and_return(template_content) end it "uses the template's content for the PR" do fake_file = double expect(File).to receive(:open).with(pull_request_message_file, "w").and_yield(fake_file) expect(fake_file).to receive(:write).with(template_content) subject end end context "providing a base branch" do let(:inputs) {{ base: "development" }} before do stub_command_line_inputs({ 'Submit pull request? (Y)' => 'yes' }) end it "creates a pull request using the custom base branch" do expect(workflow.git_server).to receive(:create_pull_request).with({ title: 'bingo', body: "\n", head: "#{user}:#{feature_branch}", base: inputs[:base] }) subject end end context 'when a base branch is configured' do before do stub_command_line_inputs('Submit pull request? (Y)' => 'yes') allow(GitReflow::Config).to receive(:get).and_call_original allow(GitReflow::Config).to receive(:get).with('reflow.base-branch').and_return('racecar') inputs.delete(:base) end it 'creates a pull request using the custom base branch' do expect(GitReflow.git_server).to receive(:create_pull_request).with({ title: 'bingo', body: "\n", head: "#{user}:#{feature_branch}", base: 'racecar' }) subject end end context "providing only a title" do let(:inputs) {{ title: "Amazing new feature" }} before do stub_command_line_inputs({ 'Submit pull request? (Y)' => 'yes' }) end it "creates a pull request with only the given title" do expect(workflow.git_server).to receive(:create_pull_request).with({ title: inputs[:title], body: nil, head: "#{user}:#{feature_branch}", base: 'master' }) subject end it "does not bother opening any template file" do expect(File).to_not receive(:open) expect(File).to_not receive(:read) expect(File).to_not receive(:delete) subject end end context "providing only a body" do let(:inputs) {{ message: "Please pull this in!" }} before do stub_command_line_inputs({ 'Submit pull request? (Y)' => 'yes' }) end it "creates a pull request with the body as both title and body" do expect(workflow.git_server).to receive(:create_pull_request).with({ title: inputs[:message], body: inputs[:message], head: "#{user}:#{feature_branch}", base: 'master' }) subject end end context "providing both title and body" do let(:inputs) {{ title: "Amazing new feature", message: "Please pull this in!" }} before do stub_command_line_inputs({ 'Submit pull request? (Y)' => 'yes' }) end it "creates a pull request with only the given title" do expect(workflow.git_server).to receive(:create_pull_request).with({ title: inputs[:title], body: inputs[:message], head: "#{user}:#{feature_branch}", base: 'master' }) subject end end context "with existing pull request" do before do expect(workflow.git_server).to receive(:find_open_pull_request).and_return(existing_gh_pull_request) allow(existing_gh_pull_request).to receive(:display_pull_request_summary) end specify { expect{subject}.to have_said "A pull request already exists for these branches:", :notice } it "displays a notice that an existing PR exists" do expect(existing_gh_pull_request).to receive(:display_pull_request_summary) subject end end context "approving PR submission" do before do stub_command_line_inputs({ 'Submit pull request? (Y)' => 'yes' }) end it "creates a pull request" do expect(workflow.git_server).to receive(:create_pull_request).with({ title: 'bingo', body: "\n", head: "#{user}:#{feature_branch}", base: 'master' }) subject end it "notifies the user that the pull request was created" do expect(workflow.git_server).to receive(:create_pull_request).and_return(existing_gh_pull_request) expect{ subject }.to have_said "Successfully created pull request ##{existing_gh_pull_request.number}: #{existing_gh_pull_request.title}\nPull Request URL: #{existing_gh_pull_request.html_url}\n", :success end context "when pull request creation fails" do let(:github_error) { Github::Error::UnprocessableEntity.new(eval(Fixture.new('pull_requests/pull_request_branch_nonexistent_error.json').to_s)) } it "retries creating a pull request" do call_count = 0 allow(workflow.git_server).to receive(:create_pull_request) do call_count += 1 (call_count <= 1) ? raise(github_error) : existing_gh_pull_request end expect{ subject }.to have_said "Successfully created pull request ##{existing_gh_pull_request.number}: #{existing_gh_pull_request.title}\nPull Request URL: #{existing_gh_pull_request.html_url}\n", :success end it "reports failures even after retrying" do allow(workflow.git_server).to receive(:create_pull_request).and_raise github_error expect { subject }.to have_said "Github Error: #{github_error.to_s}", :error end end end context "aborting during PR template review" do before do stub_command_line_inputs({ 'Submit pull request? (Y)' => 'no' }) end it "does not create a pull request" do expect(workflow.git_server).to_not receive(:create_pull_request) subject end it "notifies the user that the review was aborted" do expect { subject }.to have_said "Review aborted. No pull request has been created.", :review_halted end end end describe ".status" do let(:feature_branch) { 'new-feature' } let(:destination_branch) { nil } subject { workflow.status destination_branch: destination_branch } before do allow(GitReflow).to receive(:git_server).and_return(GitReflow::GitServer) allow(workflow.git_server).to receive(:get_build_status).and_return(Struct.new(:state, :description, :url, :target_url).new) allow(GitReflow).to receive(:current_branch).and_return(feature_branch) allow(existing_gh_pull_request).to receive(:display_pull_request_summary) end context "with no existing pull request" do before { allow(workflow.git_server).to receive(:find_open_pull_request).with({from: feature_branch, to: 'master'}).and_return(nil) } it { expect{ subject }.to have_said "No pull request exists for #{feature_branch} -> master", :notice } it { expect{ subject }.to have_said "Run 'git reflow review master' to start the review process", :notice } end context "with an existing pull request" do let(:destination_branch) { 'master' } before do allow(workflow.git_server).to receive(:find_open_pull_request).and_return(existing_gh_pull_request) end it "displays a summary of the pull request" do expect(existing_gh_pull_request).to receive(:display_pull_request_summary) expect{ subject }.to have_said "Here's the status of your review:" end context "with custom destination branch" do let(:destination_branch) { 'develop' } it "uses the custom destination branch to lookup the pull request" do expect(workflow.git_server).to receive(:find_open_pull_request).with({from: feature_branch, to: destination_branch}).and_return(existing_gh_pull_request) subject end end context "when custom base-branch is configured" do before do allow(GitReflow::Config).to receive(:get).and_call_original allow(GitReflow::Config).to receive(:get).with('reflow.base-branch').and_return('racecar') end subject { workflow.status } it "uses the custom configured base-branch to lookup the pull request" do expect(GitReflow.git_server).to receive(:find_open_pull_request).with({from: feature_branch, to: 'racecar'}).and_return(existing_gh_pull_request) subject end end end end describe ".deploy" do let(:deploy_command) { "bundle exec cap #{destination} deploy" } let(:destination) { nil } subject { workflow.deploy(destination_server: destination) } before do stub_command_line_inputs({ "Enter the command you use to deploy to default (leaving blank will skip deployment)" => "bundle exec cap deploy", "Enter the command you use to deploy to #{destination} (leaving blank will skip deployment)" => "bundle exec cap #{destination} deploy" }) end it "sets the local git-config for reflow.deploy-to-default-command" do expect(GitReflow::Config).to receive(:set).with('reflow.deploy-to-default-command', deploy_command.squeeze, local: true) subject end it "runs the staging deploy command" do expect { subject }.to have_run_command(deploy_command.squeeze) end context "staging" do let(:destination) { "staging" } it "sets the local git-config for reflow.deploy-to-staging-command" do expect(GitReflow::Config).to receive(:set).with('reflow.deploy-to-staging-command', deploy_command, local: true) subject end it "runs the staging deploy command" do expect { subject }.to have_run_command(deploy_command) end end end describe ".stage" do let(:feature_branch) { 'new-feature' } subject { workflow.stage } before do allow(workflow).to receive(:current_branch).and_return(feature_branch) allow(workflow.git_config).to receive(:get).and_call_original allow(GitReflow::Workflows::Core).to receive(:deploy) end it "checks out and updates the staging branch" do expect(workflow.git_config).to receive(:get).with('reflow.staging-branch', local: true).and_return('staging') expect { subject }.to have_run_commands_in_order([ "git checkout staging", "git pull origin staging", "git merge #{feature_branch}", "git push origin staging" ]) end context "merge is not successful" do before do allow(workflow.git_config).to receive(:get).with('reflow.staging-branch', local: true).and_return('staging') allow(workflow).to receive(:run_command_with_label).and_call_original expect(workflow).to receive(:run_command_with_label).with("git merge #{feature_branch}", with_system: true).and_return(false) end it "notifies the user of unsuccessful merge" do expect { subject }.to have_said "There were issues merging your feature branch to staging.", :error end it "does not push any changes to the remote repo" do expect { subject }.to_not have_run_command "git push origin staging" end it "does not deploy to staging" do expect(GitReflow::Workflows::Core).to_not receive(:deploy) subject end end context "merge is successful" do before do allow(workflow.git_config).to receive(:get).with('reflow.staging-branch', local: true).and_return('staging') allow(workflow).to receive(:run_command_with_label).and_call_original expect(workflow).to receive(:run_command_with_label).with("git merge #{feature_branch}", with_system: true).and_return(true).and_call_original end specify { expect{ subject }.to have_run_command "git push origin staging" } context "and deployment is successful" do before { expect(GitReflow::Workflows::Core).to receive(:deploy).with(destination_server: :staging).and_return(true) } specify { expect{ subject }.to have_said "Deployed to Staging.", :success } end context "but deployment is not successful" do before { allow(GitReflow::Workflows::Core).to receive(:deploy).with(destination_server: :staging).and_return(false) } specify { expect{ subject }.to have_said "There were issues deploying to staging.", :error } end end context "no staging branch has been setup" do before do allow(workflow.git_config).to receive(:get).with('reflow.staging-branch', local: true).and_return('') stub_command_line_inputs({ "What's the name of your staging branch? (default: 'staging') " => "bobby" }) end it "sets the reflow.staging-branch git config to 'staging'" do expect(workflow.git_config).to receive(:set).with("reflow.staging-branch", "bobby", local: true) subject end it "checks out and updates the staging branch" do allow(workflow.git_config).to receive(:set).with("reflow.staging-branch", "bobby", local: true) expect { subject }.to have_run_commands_in_order([ "git checkout bobby", "git pull origin bobby", "git merge #{feature_branch}", "git push origin bobby" ]) end context "and I don't enter one in" do before do stub_command_line_inputs({ "What's the name of your staging branch? (default: 'staging') " => "" }) end it "sets the reflow.staging-branch git config to 'staging'" do expect { subject }.to have_run_command_silently "git config --replace-all reflow.staging-branch \"staging\"", blocking: false end it "checks out and updates the staging branch" do expect { subject }.to have_run_commands_in_order([ "git checkout staging", "git pull origin staging", "git merge #{feature_branch}", "git push origin staging" ]) end end end end describe ".deliver" do let(:feature_branch) { 'new-feature' } let(:user) { 'reenhanced' } let(:repo) { 'repo' } subject { workflow.deliver } before do allow(GitReflow).to receive(:git_server).and_return(GitReflow::GitServer) allow(GitReflow).to receive(:remote_user).and_return(user) allow(workflow).to receive(:remote_user).and_return(user) allow(GitReflow).to receive(:current_branch).and_return(feature_branch) allow(workflow).to receive(:current_branch).and_return(feature_branch) allow(workflow.git_server).to receive(:get_build_status).and_return(Struct.new(:state, :description, :url, :target_url).new) end context "pull request does not exist" do before { allow(workflow.git_server).to receive(:find_open_pull_request).with( from: feature_branch, to: 'master').and_return(nil) } specify { expect{ subject }.to have_said "No pull request exists for #{user}:#{feature_branch}\nPlease submit your branch for review first with \`git reflow review\`", :deliver_halted } end context "pull request exists" do before do allow(workflow.git_server).to receive(:find_open_pull_request).with( from: feature_branch, to: 'master').and_return(existing_gh_pull_request) allow(GitReflow::Workflows::Core).to receive(:status) end context "and PR passes all QA checks" do before { allow(existing_gh_pull_request).to receive(:good_to_merge?).and_return(true) } it "displays the status of the PR" do allow(existing_gh_pull_request).to receive(:merge!) expect(GitReflow::Workflows::Core).to receive(:status).with(destination_branch: 'master') subject end it "merges the feature branch" do expect(existing_gh_pull_request).to receive(:merge!) subject end context "but there is an error from the git server" do let(:github_error) { Github::Error::UnprocessableEntity.new(eval(Fixture.new('pull_requests/pull_request_exists_error.json').to_s)) } before do allow(existing_gh_pull_request).to receive(:merge!).and_raise github_error end it "notifies the user of the error" do expect { subject }.to have_said "Github Error: #{github_error.inspect}", :error end end end context "and PR fails some QA checks" do before do allow(existing_gh_pull_request).to receive(:good_to_merge?).and_return(false) allow(existing_gh_pull_request).to receive(:rejection_message).and_return("I think you need a hug.") end it "does not merge the feature branch" do expect(existing_gh_pull_request).to_not receive(:merge!) subject end it "does not display the status of the PR" do expect(GitReflow::Workflows::Core).to_not receive(:status).with(destination_branch: 'master') subject end it "notifies the user of the reason the merge is unsafe" do expect { subject }.to have_said "I think you need a hug.", :deliver_halted end context "but forcing the deliver" do subject { workflow.deliver force: true } before do allow(existing_gh_pull_request).to receive(:good_to_merge?).with(force: true).and_return(true) allow(existing_gh_pull_request).to receive(:merge!).with( force: true, merge_method: "squash", base: 'master', skip_lgtm: false ) end it "displays the status of the PR" do expect(GitReflow::Workflows::Core).to receive(:status).with(destination_branch: 'master') subject end it "merges the feature branch anyway" do expect(existing_gh_pull_request).to receive(:merge!).with( force: true, merge_method: "squash", base: 'master', skip_lgtm: false ) subject end end end context "and using a custom base branch" do subject { workflow.deliver base: 'development' } before do expect(workflow.git_server).to receive(:find_open_pull_request).with( from: feature_branch, to: 'development').and_return(existing_gh_pull_request) allow(existing_gh_pull_request).to receive(:good_to_merge?).and_return(true) end it "displays the status of the PR" do allow(existing_gh_pull_request).to receive(:merge!).with( base: 'development', merge_method: "squash", force: false, skip_lgtm: false ) expect(GitReflow::Workflows::Core).to receive(:status).with(destination_branch: 'development') subject end it "merges the feature branch" do expect(existing_gh_pull_request).to receive(:merge!).with( base: "development", merge_method: "squash", force: false, skip_lgtm: false ) subject end end context "when a custom base-branch is configured" do subject { workflow.deliver } before do expect(GitReflow.git_server).to receive(:find_open_pull_request).with( from: feature_branch, to: 'racecar').and_return(existing_gh_pull_request) allow(existing_gh_pull_request).to receive(:good_to_merge?).and_return(true) allow(GitReflow::Config).to receive(:get).with('reflow.base-branch').and_return('racecar') end it "displays the status of the PR" do allow(existing_gh_pull_request).to receive(:merge!).with( base: 'racecar', merge_method: "squash", force: false, skip_lgtm: false ) expect(GitReflow::Workflows::Core).to receive(:status).with(destination_branch: 'racecar') subject end it "merges the feature branch" do expect(existing_gh_pull_request).to receive(:merge!).with( base: "racecar", merge_method: "squash", force: false, skip_lgtm: false ) subject end end end end describe ".refresh" do subject { workflow.refresh } it "updates the feature branch with default remote repo and base branch" do expect(workflow).to receive(:update_feature_branch).with(remote: 'origin', base: 'master') subject end context "providing a custom base branch" do subject { workflow.refresh base: 'development' } it "updates the feature branch with default remote repo and base branch" do expect(workflow).to receive(:update_feature_branch).with(remote: 'origin', base: 'development') subject end end context "when a custom base branch is configured" do before { allow(workflow.git_config).to receive(:get).with('reflow.base-branch').and_return('racecar') } subject { workflow.refresh } it "updates the feature branch with custom base branch" do expect(workflow).to receive(:update_feature_branch).with(remote: 'origin', base: 'racecar') subject end end context "provding a custom remote repo" do subject { workflow.refresh remote: 'upstream' } it "updates the feature branch with default remote repo and base branch" do expect(workflow).to receive(:update_feature_branch).with(remote: 'upstream', base: 'master') subject end end context "providing a custom base branch and remote repo" do subject { workflow.refresh remote: 'upstream', base: 'development' } it "updates the feature branch with default remote repo and base branch" do expect(workflow).to receive(:update_feature_branch).with(remote: 'upstream', base: 'development') subject end end end end