Commit 359ad736 authored by Douglas Barbosa Alexandre's avatar Douglas Barbosa Alexandre Committed by Stan Hu

Synchronize the default branch when updating a pull mirror

parent 48ce8a0a
...@@ -10,7 +10,7 @@ module EE ...@@ -10,7 +10,7 @@ module EE
MIRROR_REMOTE = "upstream".freeze MIRROR_REMOTE = "upstream".freeze
included do included do
delegate :checksum, :find_remote_root_ref, to: :raw_repository delegate :checksum, to: :raw_repository
end end
# Transiently sets a configuration variable # Transiently sets a configuration variable
......
...@@ -45,10 +45,8 @@ module Geo ...@@ -45,10 +45,8 @@ module Geo
project.ensure_repository project.ensure_repository
end end
# Update the default branch querying the remote to determine its HEAD
def update_root_ref def update_root_ref
root_ref = repository.find_remote_root_ref(GEO_REMOTE_NAME) project.update_root_ref(GEO_REMOTE_NAME)
project.change_head(root_ref) if root_ref.present? && root_ref != project.default_branch
end end
def schedule_repack def schedule_repack
......
...@@ -17,6 +17,7 @@ module Projects ...@@ -17,6 +17,7 @@ module Projects
end end
update_branches update_branches
update_root_ref
success success
rescue Gitlab::Shell::Error, UpdateError => e rescue Gitlab::Shell::Error, UpdateError => e
...@@ -60,6 +61,11 @@ module Projects ...@@ -60,6 +61,11 @@ module Projects
end end
end end
# Update the default branch querying the remote to determine its HEAD
def update_root_ref
project.update_root_ref(::Repository::MIRROR_REMOTE)
end
def update_tags(&block) def update_tags(&block)
old_tags = repository_tags_with_target.each_with_object({}) { |tag, tags| tags[tag.name] = tag } old_tags = repository_tags_with_target.each_with_object({}) { |tag, tags| tags[tag.name] = tag }
......
...@@ -1763,4 +1763,38 @@ describe Project do ...@@ -1763,4 +1763,38 @@ describe Project do
it { is_expected.to be true } it { is_expected.to be true }
end end
describe '#update_root_ref' do
let(:project) { create(:project, :repository) }
it 'updates the default branch when HEAD has changed' do
stub_find_remote_root_ref(project, ref: 'feature')
expect { project.update_root_ref('origin') }
.to change { project.default_branch }
.from('master')
.to('feature')
end
it 'does not update the default branch when HEAD does not change' do
stub_find_remote_root_ref(project, ref: 'master')
expect { project.update_root_ref('origin') }
.not_to change { project.default_branch }
end
it 'does not update the default branch when HEAD does not exist' do
stub_find_remote_root_ref(project, ref: 'foo')
expect { project.update_root_ref('origin') }
.not_to change { project.default_branch }
end
def stub_find_remote_root_ref(project, ref:)
allow(project.repository)
.to receive(:find_remote_root_ref)
.with('origin')
.and_return(ref)
end
end
end end
...@@ -5,6 +5,8 @@ describe Projects::UpdateMirrorService do ...@@ -5,6 +5,8 @@ describe Projects::UpdateMirrorService do
create(:project, :repository, :mirror, import_url: Project::UNKNOWN_IMPORT_URL, only_mirror_protected_branches: false) create(:project, :repository, :mirror, import_url: Project::UNKNOWN_IMPORT_URL, only_mirror_protected_branches: false)
end end
subject(:service) { described_class.new(project, project.owner) }
describe "#execute" do describe "#execute" do
context 'unlicensed' do context 'unlicensed' do
before do before do
...@@ -14,55 +16,61 @@ describe Projects::UpdateMirrorService do ...@@ -14,55 +16,61 @@ describe Projects::UpdateMirrorService do
it 'does nothing' do it 'does nothing' do
expect(project).not_to receive(:fetch_mirror) expect(project).not_to receive(:fetch_mirror)
result = described_class.new(project, project.owner).execute result = service.execute
expect(result[:status]).to eq(:success) expect(result[:status]).to eq(:success)
end end
end end
it "fetches the upstream repository" do it "fetches the upstream repository" do
stub_find_remote_root_ref(project)
expect(project).to receive(:fetch_mirror) expect(project).to receive(:fetch_mirror)
described_class.new(project, project.owner).execute service.execute
end end
it 'rescues exceptions from Repository#ff_merge' do it 'rescues exceptions from Repository#ff_merge' do
stub_fetch_mirror(project) stub_fetch_mirror(project)
stub_find_remote_root_ref(project)
expect(project.repository).to receive(:ff_merge).and_raise(Gitlab::Git::PreReceiveError) expect(project.repository).to receive(:ff_merge).and_raise(Gitlab::Git::PreReceiveError)
expect { described_class.new(project, project.owner).execute }.not_to raise_error expect { service.execute }.not_to raise_error
end end
it "succeeds" do it "returns success when updated succeeds" do
stub_fetch_mirror(project) stub_fetch_mirror(project)
stub_find_remote_root_ref(project)
result = described_class.new(project, project.owner).execute result = service.execute
expect(result[:status]).to eq(:success) expect(result[:status]).to eq(:success)
end end
describe "updating tags" do context "updating tags" do
it "creates new tags" do it "creates new tags" do
stub_fetch_mirror(project) stub_fetch_mirror(project)
stub_find_remote_root_ref(project)
described_class.new(project, project.owner).execute service.execute
expect(project.repository.tag_names).to include('new-tag') expect(project.repository.tag_names).to include('new-tag')
end end
it "only invokes GitTagPushService for tags pointing to commits" do it "only invokes GitTagPushService for tags pointing to commits" do
stub_fetch_mirror(project) stub_fetch_mirror(project)
stub_find_remote_root_ref(project)
expect(GitTagPushService).to receive(:new) expect(GitTagPushService).to receive(:new)
.with(project, project.owner, hash_including(ref: 'refs/tags/new-tag')).and_return(double(execute: true)) .with(project, project.owner, hash_including(ref: 'refs/tags/new-tag'))
.and_return(double(execute: true))
described_class.new(project, project.owner).execute service.execute
end end
end end
describe "updating branches" do context "updating branches" do
subject { described_class.new(project, project.owner) }
context 'when mirror only protected branches option is set' do context 'when mirror only protected branches option is set' do
let(:new_protected_branch_name) { 'new-branch' } let(:new_protected_branch_name) { 'new-branch' }
let(:protected_branch_name) { 'existing-branch' } let(:protected_branch_name) { 'existing-branch' }
...@@ -76,16 +84,18 @@ describe Projects::UpdateMirrorService do ...@@ -76,16 +84,18 @@ describe Projects::UpdateMirrorService do
project.reload project.reload
stub_fetch_mirror(project) stub_fetch_mirror(project)
stub_find_remote_root_ref(project)
subject.execute service.execute
expect(project.repository.branch_names).to include(new_protected_branch_name) expect(project.repository.branch_names).to include(new_protected_branch_name)
end end
it 'does not create an unprotected branch' do it 'does not create an unprotected branch' do
stub_fetch_mirror(project) stub_fetch_mirror(project)
stub_find_remote_root_ref(project)
described_class.new(project, project.owner).execute service.execute
expect(project.repository.branch_names).not_to include(new_protected_branch_name) expect(project.repository.branch_names).not_to include(new_protected_branch_name)
end end
...@@ -95,8 +105,9 @@ describe Projects::UpdateMirrorService do ...@@ -95,8 +105,9 @@ describe Projects::UpdateMirrorService do
project.reload project.reload
stub_fetch_mirror(project) stub_fetch_mirror(project)
stub_find_remote_root_ref(project)
subject.execute service.execute
expect(project.repository.find_branch(protected_branch_name).dereferenced_target) expect(project.repository.find_branch(protected_branch_name).dereferenced_target)
.to eq(project.repository.find_branch('master').dereferenced_target) .to eq(project.repository.find_branch('master').dereferenced_target)
...@@ -104,8 +115,9 @@ describe Projects::UpdateMirrorService do ...@@ -104,8 +115,9 @@ describe Projects::UpdateMirrorService do
it "does not update unprotected branches" do it "does not update unprotected branches" do
stub_fetch_mirror(project) stub_fetch_mirror(project)
stub_find_remote_root_ref(project)
subject.execute service.execute
expect(project.repository.find_branch(protected_branch_name).dereferenced_target) expect(project.repository.find_branch(protected_branch_name).dereferenced_target)
.not_to eq(project.repository.find_branch('master').dereferenced_target) .not_to eq(project.repository.find_branch('master').dereferenced_target)
...@@ -114,16 +126,18 @@ describe Projects::UpdateMirrorService do ...@@ -114,16 +126,18 @@ describe Projects::UpdateMirrorService do
it "creates new branches" do it "creates new branches" do
stub_fetch_mirror(project) stub_fetch_mirror(project)
stub_find_remote_root_ref(project)
subject.execute service.execute
expect(project.repository.branch_names).to include('new-branch') expect(project.repository.branch_names).to include('new-branch')
end end
it "updates existing branches" do it "updates existing branches" do
stub_fetch_mirror(project) stub_fetch_mirror(project)
stub_find_remote_root_ref(project)
subject.execute service.execute
expect(project.repository.find_branch('existing-branch').dereferenced_target) expect(project.repository.find_branch('existing-branch').dereferenced_target)
.to eq(project.repository.find_branch('master').dereferenced_target) .to eq(project.repository.find_branch('master').dereferenced_target)
...@@ -132,13 +146,14 @@ describe Projects::UpdateMirrorService do ...@@ -132,13 +146,14 @@ describe Projects::UpdateMirrorService do
context 'with diverged branches' do context 'with diverged branches' do
before do before do
stub_fetch_mirror(project) stub_fetch_mirror(project)
stub_find_remote_root_ref(project)
end end
context 'when mirror_overwrites_diverged_branches is true' do context 'when mirror_overwrites_diverged_branches is true' do
it 'update diverged branches' do it 'update diverged branches' do
project.mirror_overwrites_diverged_branches = true project.mirror_overwrites_diverged_branches = true
subject.execute service.execute
expect(project.repository.find_branch('markdown').dereferenced_target) expect(project.repository.find_branch('markdown').dereferenced_target)
.to eq(project.repository.find_branch('master').dereferenced_target) .to eq(project.repository.find_branch('master').dereferenced_target)
...@@ -149,7 +164,7 @@ describe Projects::UpdateMirrorService do ...@@ -149,7 +164,7 @@ describe Projects::UpdateMirrorService do
it "doesn't update diverged branches" do it "doesn't update diverged branches" do
project.mirror_overwrites_diverged_branches = false project.mirror_overwrites_diverged_branches = false
subject.execute service.execute
expect(project.repository.find_branch('markdown').dereferenced_target) expect(project.repository.find_branch('markdown').dereferenced_target)
.not_to eq(project.repository.find_branch('master').dereferenced_target) .not_to eq(project.repository.find_branch('master').dereferenced_target)
...@@ -160,7 +175,7 @@ describe Projects::UpdateMirrorService do ...@@ -160,7 +175,7 @@ describe Projects::UpdateMirrorService do
it "doesn't update diverged branches" do it "doesn't update diverged branches" do
project.mirror_overwrites_diverged_branches = nil project.mirror_overwrites_diverged_branches = nil
subject.execute service.execute
expect(project.repository.find_branch('markdown').dereferenced_target) expect(project.repository.find_branch('markdown').dereferenced_target)
.not_to eq(project.repository.find_branch('master').dereferenced_target) .not_to eq(project.repository.find_branch('master').dereferenced_target)
...@@ -168,16 +183,16 @@ describe Projects::UpdateMirrorService do ...@@ -168,16 +183,16 @@ describe Projects::UpdateMirrorService do
end end
end end
describe 'when project is empty' do context 'when project is empty' do
let(:project) { create(:project_empty_repo, :mirror, import_url: Project::UNKNOWN_IMPORT_URL) }
it 'does not add a default master branch' do it 'does not add a default master branch' do
project = create(:project_empty_repo, :mirror, import_url: Project::UNKNOWN_IMPORT_URL)
repository = project.repository repository = project.repository
stub_find_remote_root_ref(project)
allow(project).to receive(:fetch_mirror) { create_file(repository) } allow(project).to receive(:fetch_mirror) { create_file(repository) }
expect(CreateBranchService).not_to receive(:create_master_branch) expect(CreateBranchService).not_to receive(:create_master_branch)
subject.execute service.execute
expect(repository.branch_names).not_to include('master') expect(repository.branch_names).not_to include('master')
end end
...@@ -194,37 +209,52 @@ describe Projects::UpdateMirrorService do ...@@ -194,37 +209,52 @@ describe Projects::UpdateMirrorService do
end end
end end
describe "when the mirror user doesn't have access" do it 'updates the default branch when HEAD has changed' do
it "fails" do stub_fetch_mirror(project)
stub_fetch_mirror(project) stub_find_remote_root_ref(project, ref: 'new-branch')
result = described_class.new(project, create(:user)).execute expect { service.execute }.to change { project.default_branch }.from('master').to('new-branch')
end
expect(result[:status]).to eq(:error) it 'does not update the default branch when HEAD does not change' do
end stub_fetch_mirror(project)
stub_find_remote_root_ref(project, ref: 'master')
expect { service.execute }.not_to change { project.default_branch }
end end
describe "when no user is present" do it "fails when the mirror user doesn't have access" do
it "fails" do stub_fetch_mirror(project)
result = described_class.new(project, nil).execute stub_find_remote_root_ref(project)
expect(result[:status]).to eq(:error) result = described_class.new(project, create(:user)).execute
end
expect(result[:status]).to eq(:error)
end end
describe "when is no mirror" do it "fails when no user is present" do
let(:project) { build_stubbed(:project) } result = described_class.new(project, nil).execute
it "success" do expect(result[:status]).to eq(:error)
expect(project.mirror?).to eq(false) end
result = described_class.new(project, create(:user)).execute it "returns success when there is no mirror" do
project = build_stubbed(:project)
user = create(:user)
expect(result[:status]).to eq(:success) result = described_class.new(project, user).execute
end
expect(result[:status]).to eq(:success)
end end
end end
def stub_find_remote_root_ref(project, remote: 'upstream', ref: 'master')
allow(project.repository)
.to receive(:find_remote_root_ref)
.with(remote)
.and_return(ref)
end
def stub_fetch_mirror(project, repository: project.repository) def stub_fetch_mirror(project, repository: project.repository)
allow(project).to receive(:fetch_mirror) { fetch_mirror(repository) } allow(project).to receive(:fetch_mirror) { fetch_mirror(repository) }
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment