# Git Pivotal Tracker Integration # Copyright (c) 2013 the original author or authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require "spec_helper" require "git-pivotal-tracker-integration/util/git" require "git-pivotal-tracker-integration/util/shell" describe GitPivotalTrackerIntegration::Util::Git do before do $stdout = StringIO.new $stderr = StringIO.new end it "should return the current branch name" do GitPivotalTrackerIntegration::Util::Shell.should_receive(:exec).with("git branch").and_return(" master\n * dev_branch") current_branch = GitPivotalTrackerIntegration::Util::Git.branch_name expect(current_branch).to eq("dev_branch") end it "should return the repository root" do Dir.mktmpdir do |root| child_directory = File.expand_path "child", root Dir.mkdir child_directory git_directory = File.expand_path ".git", root Dir.mkdir git_directory Dir.should_receive(:pwd).and_return(child_directory) repository_root = GitPivotalTrackerIntegration::Util::Git.repository_root expect(repository_root).to eq(root) end end it "should raise an error there is no repository root" do Dir.mktmpdir do |root| child_directory = File.expand_path "child", root Dir.mkdir child_directory Dir.should_receive(:pwd).and_return(child_directory) expect { GitPivotalTrackerIntegration::Util::Git.repository_root }.to raise_error end end it "should get configuration when :branch scope is specified" do GitPivotalTrackerIntegration::Util::Git.should_receive(:branch_name).and_return("test_branch_name") GitPivotalTrackerIntegration::Util::Shell.should_receive(:exec).with("git config branch.test_branch_name.test_key", false).and_return("test_value") value = GitPivotalTrackerIntegration::Util::Git.get_config "test_key", :branch expect(value).to eq("test_value") end it "should get configuration when :inherited scope is specified" do GitPivotalTrackerIntegration::Util::Shell.should_receive(:exec).with("git config test_key", false).and_return("test_value") value = GitPivotalTrackerIntegration::Util::Git.get_config "test_key", :inherited expect(value).to eq("test_value") end it "should raise an error when an unknown scope is specified (get)" do expect { GitPivotalTrackerIntegration::Util::Git.get_config "test_key", :unknown }.to raise_error end it "should set configuration when :branch scope is specified" do GitPivotalTrackerIntegration::Util::Git.should_receive(:branch_name).and_return("test_branch_name") GitPivotalTrackerIntegration::Util::Shell.should_receive(:exec).with("git config --local branch.test_branch_name.test_key test_value") GitPivotalTrackerIntegration::Util::Git.set_config "test_key", "test_value", :branch end it "should set configuration when :global scope is specified" do GitPivotalTrackerIntegration::Util::Shell.should_receive(:exec).with("git config --global test_key test_value") GitPivotalTrackerIntegration::Util::Git.set_config "test_key", "test_value", :global end it "should set configuration when :local scope is specified" do GitPivotalTrackerIntegration::Util::Shell.should_receive(:exec).with("git config --local test_key test_value") GitPivotalTrackerIntegration::Util::Git.set_config "test_key", "test_value", :local end it "should raise an error when an unknown scope is specified (set)" do expect { GitPivotalTrackerIntegration::Util::Git.set_config "test_key", "test_valeu", :unknown }.to raise_error end it "should create a branch and set the root_branch and root_remote properties on it" do GitPivotalTrackerIntegration::Util::Git.should_receive(:branch_name).and_return("master") GitPivotalTrackerIntegration::Util::Git.should_receive(:get_config).with("remote", :branch).and_return("origin") GitPivotalTrackerIntegration::Util::Shell.should_receive(:exec).with("git pull --quiet --ff-only") GitPivotalTrackerIntegration::Util::Shell.should_receive(:exec).and_return("git checkout --quiet -b dev_branch") GitPivotalTrackerIntegration::Util::Git.should_receive(:set_config).with("root-branch", "master", :branch) GitPivotalTrackerIntegration::Util::Git.should_receive(:set_config).with("root-remote", "origin", :branch) GitPivotalTrackerIntegration::Util::Git.create_branch "dev_branch" end it "should not add a hook if it already exists" do Dir.mktmpdir do |root| GitPivotalTrackerIntegration::Util::Git.should_receive(:repository_root).and_return(root) hook = "#{root}/.git/hooks/prepare-commit-msg" File.should_receive(:exist?).with(hook).and_return(true) GitPivotalTrackerIntegration::Util::Git.add_hook "prepare-commit-msg", __FILE__ File.should_receive(:exist?).and_call_original expect(File.exist?(hook)).to be_false end end it "should add a hook if it does not exist" do Dir.mktmpdir do |root| GitPivotalTrackerIntegration::Util::Git.should_receive(:repository_root).and_return(root) hook = "#{root}/.git/hooks/prepare-commit-msg" File.should_receive(:exist?).with(hook).and_return(false) GitPivotalTrackerIntegration::Util::Git.add_hook "prepare-commit-msg", __FILE__ File.should_receive(:exist?).and_call_original expect(File.exist?(hook)).to be_true end end it "should add a hook if it already exists and overwrite is true" do Dir.mktmpdir do |root| GitPivotalTrackerIntegration::Util::Git.should_receive(:repository_root).and_return(root) hook = "#{root}/.git/hooks/prepare-commit-msg" GitPivotalTrackerIntegration::Util::Git.add_hook "prepare-commit-msg", __FILE__, true File.should_receive(:exist?).and_call_original expect(File.exist?(hook)).to be_true end end it "should fail if root tip and common_ancestor do not match" do GitPivotalTrackerIntegration::Util::Git.should_receive(:branch_name).and_return("development_branch") GitPivotalTrackerIntegration::Util::Git.should_receive(:get_config).with("root-branch", :branch).and_return("master") GitPivotalTrackerIntegration::Util::Shell.should_receive(:exec).with("git checkout --quiet master") GitPivotalTrackerIntegration::Util::Shell.should_receive(:exec).with("git pull --quiet --ff-only") GitPivotalTrackerIntegration::Util::Shell.should_receive(:exec).with("git checkout --quiet development_branch") GitPivotalTrackerIntegration::Util::Shell.should_receive(:exec).with("git rev-parse master").and_return("root_tip") GitPivotalTrackerIntegration::Util::Shell.should_receive(:exec).with("git merge-base master development_branch").and_return("common_ancestor") lambda { GitPivotalTrackerIntegration::Util::Git.trivial_merge? }.should raise_error(SystemExit) expect($stderr.string).to match(/FAIL/) end it "should pass if root tip and common ancestor match" do GitPivotalTrackerIntegration::Util::Git.should_receive(:branch_name).and_return("development_branch") GitPivotalTrackerIntegration::Util::Git.should_receive(:get_config).with("root-branch", :branch).and_return("master") GitPivotalTrackerIntegration::Util::Shell.should_receive(:exec).with("git checkout --quiet master") GitPivotalTrackerIntegration::Util::Shell.should_receive(:exec).with("git pull --quiet --ff-only") GitPivotalTrackerIntegration::Util::Shell.should_receive(:exec).with("git checkout --quiet development_branch") GitPivotalTrackerIntegration::Util::Shell.should_receive(:exec).with("git rev-parse master").and_return("HEAD") GitPivotalTrackerIntegration::Util::Shell.should_receive(:exec).with("git merge-base master development_branch").and_return("HEAD") GitPivotalTrackerIntegration::Util::Git.trivial_merge? expect($stdout.string).to match(/OK/) end it "should merge and delete branches" do GitPivotalTrackerIntegration::Util::Git.should_receive(:branch_name).and_return("development_branch") GitPivotalTrackerIntegration::Util::Git.should_receive(:get_config).with("root-branch", :branch).and_return("master") GitPivotalTrackerIntegration::Util::Shell.should_receive(:exec).with("git checkout --quiet master") GitPivotalTrackerIntegration::Util::Shell.should_receive(:exec).with("git merge --quiet --no-ff -m \"Merge development_branch to master\n\n[Completes #12345678]\" development_branch") GitPivotalTrackerIntegration::Util::Shell.should_receive(:exec).with("git branch --quiet -D development_branch") GitPivotalTrackerIntegration::Util::Git.merge PivotalTracker::Story.new(:id => 12345678) end it "should push changes without refs" do GitPivotalTrackerIntegration::Util::Git.should_receive(:get_config).with("remote", :branch).and_return("origin") GitPivotalTrackerIntegration::Util::Shell.should_receive(:exec).with("git push --quiet origin ") GitPivotalTrackerIntegration::Util::Git.push end it "should push changes with refs" do GitPivotalTrackerIntegration::Util::Git.should_receive(:get_config).with("remote", :branch).and_return("origin") GitPivotalTrackerIntegration::Util::Shell.should_receive(:exec).with("git push --quiet origin foo bar") GitPivotalTrackerIntegration::Util::Git.push "foo", "bar" end it "should create a commit" do story = PivotalTracker::Story.new(:id => 123456789) GitPivotalTrackerIntegration::Util::Shell.should_receive(:exec).with("git commit --quiet --all --allow-empty --message \"test_message\n\n[#123456789]\"") GitPivotalTrackerIntegration::Util::Git.create_commit "test_message", story end it "should create a release tag" do story = PivotalTracker::Story.new(:id => 123456789) GitPivotalTrackerIntegration::Util::Git.should_receive(:branch_name).and_return("master") GitPivotalTrackerIntegration::Util::Git.should_receive(:create_branch).with("pivotal-tracker-release", false) GitPivotalTrackerIntegration::Util::Git.should_receive(:create_commit).with("1.0.0.RELEASE Release", story) GitPivotalTrackerIntegration::Util::Shell.should_receive(:exec).with("git tag v1.0.0.RELEASE") GitPivotalTrackerIntegration::Util::Shell.should_receive(:exec).with("git checkout --quiet master") GitPivotalTrackerIntegration::Util::Shell.should_receive(:exec).with("git branch --quiet -D pivotal-tracker-release") GitPivotalTrackerIntegration::Util::Git.create_release_tag "1.0.0.RELEASE", story end end