Skip to content
This repository has been archived by the owner on Feb 7, 2020. It is now read-only.

Use git push --force during promotion #87

Merged
merged 2 commits into from
Jun 13, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 15 additions & 14 deletions lib/build_strategies/production_build_strategy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,14 @@ class << self
# The primary function of promote_build is to update the branches specified
# in on_green_update field of Repository.
#
# A feature of promote build is that it will not cause the promotion ref to move
# backwards. For instance, if build 1 finishes after build 2, we don't cause the promotion ref to move
# backwards by overwriting promotion_ref with build 1
# A feature of promote_build is that it will not cause the promotion ref to
# move backwards. For instance, if build 1 finishes after build 2, we don't
# cause the promotion ref to move backwards by overwriting promotion_ref
# with build 1
#
# promote_build does use a force push in order to overwrite experimental
# branches that may have been manually placed on the promotion ref by a
# developer for testing.
def promote_build(build_ref, repository)
repository.promotion_refs.each do |promotion_ref|
unless included_in_promotion_ref?(build_ref, promotion_ref)
Expand Down Expand Up @@ -44,22 +49,18 @@ def merge_ref(build)
end

def update_branch(branch_name, ref_to_promote)
Cocaine::CommandLine.new("git push", "origin #{ref_to_promote}:refs/heads/#{branch_name}").run
Cocaine::CommandLine.new("git push", "--force origin #{ref_to_promote}:refs/heads/#{branch_name}").run
end

private

def included_in_promotion_ref?(build_ref, promotion_ref)
return unless ref_exists?(promotion_ref)

cherry_cmd = Cocaine::CommandLine.new("git cherry", "origin/#{promotion_ref} #{build_ref}")
cherry_cmd.run.lines.count == 0
# --is-ancestor was added in git 1.8.0
# exit -> 1: not an ancestor
# exit -> 128: the commit does not exist
ancestor_cmd = Cocaine::CommandLine.new("git merge-base", "--is-ancestor #{build_ref} origin/#{promotion_ref}", :expected_outcodes => [0, 1, 128])
ancestor_cmd.run
ancestor_cmd.exit_status == 0
end

def ref_exists?(promotion_ref)
show_ref = Cocaine::CommandLine.new("git show-ref", promotion_ref, :expected_outcodes => [0,1])
show_ref.run.present?
end

end
end
25 changes: 8 additions & 17 deletions spec/lib/build_strategies/production_build_strategy_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,30 +38,21 @@
describe "#promote_build" do
subject { described_class.promote_build(build.ref, project.repository) }

context "when pushing to a ref that doesn't exist" do
context "when the ref is an ancestor" do
before(:each) {
mock_show_ref_command = double
expect(mock_show_ref_command).to receive(:run).and_return "deadbeef refs/remote/origin/branch"
allow(Cocaine::CommandLine).to receive(:new).with("git show-ref", anything, anything).and_return mock_show_ref_command

mock_cherry_command = double
expect(mock_cherry_command).to receive(:run).and_return "+ deadbeef"
allow(Cocaine::CommandLine).to receive(:new).with("git cherry", "origin/#{project.repository.promotion_refs.first} #{build.ref}").and_return mock_cherry_command
expect(described_class).to receive(:included_in_promotion_ref?).and_return(true)
}
it "pushes the ref" do
expect(described_class).to receive(:update_branch).with(project.repository.promotion_refs.first, build.ref)
it "does not perform an update" do
expect(described_class).to_not receive(:update_branch)
subject
end
end

context "when pushing to a ref that doesn't exist" do
context "when the ref is not an ancestor" do
before(:each) {
mock_git_command = double
expect(mock_git_command).to receive(:run).and_return ""
allow(Cocaine::CommandLine).to receive(:new).with("git show-ref", anything, anything).and_return mock_git_command
expect(described_class).to receive(:included_in_promotion_ref?).and_return(false)
}

it "fails gracefully if the ref is undefined" do
it "should update the promotion branch" do
expect(described_class).to receive(:update_branch).with(project.repository.promotion_refs.first, build.ref)
subject
end
Expand All @@ -76,7 +67,7 @@
it "should promote a sha" do
mock_git_command = double
expect(mock_git_command).to receive(:run).and_return ""
expect(Cocaine::CommandLine).to receive(:new).with("git push", "origin abc123:refs/heads/last-green").and_return mock_git_command
expect(Cocaine::CommandLine).to receive(:new).with("git push", "--force origin abc123:refs/heads/last-green").and_return mock_git_command

subject
end
Expand Down