Commit e7de5419 authored by Douwe Maan's avatar Douwe Maan

Merge branch '3843-add-option-to-push-mirror-only-protected-branches' into 'master'

Add option to remote mirrors to only push protected branches

Closes #3843

See merge request gitlab-org/gitlab-ee!3350
parents e075ede8 b5ece117
......@@ -31,6 +31,8 @@ module Projects
def local_branches
@local_branches ||= repository.local_branches.each_with_object({}) do |branch, branches|
next if mirror.only_protected_branches? && !protected_branch?(branch.name)
branches[branch.name] = branch
end
end
......@@ -113,6 +115,7 @@ module Projects
remote_refs.each_with_object([]) do |(name, remote_ref), refs_to_delete|
next if local_refs[name] # skip if branch or tag exist in local repo
next if type == :branches && mirror.only_protected_branches? && !protected_branch?(name)
remote_ref_id = remote_ref.dereferenced_target.try(:id)
......@@ -121,5 +124,9 @@ module Projects
end
end
end
def protected_branch?(name)
ProtectedBranch.protected?(project, name)
end
end
end
---
title: Add option to remote mirrors to only push protected branches
merge_request: 3350
author:
type: added
class AddOnlyProtectedBranchesToRemoteMirrors < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_column_with_default(:remote_mirrors, :only_protected_branches, :boolean, default: false, allow_null: false)
end
def down
remove_column(:remote_mirrors, :only_protected_branches)
end
end
......@@ -1968,6 +1968,7 @@ ActiveRecord::Schema.define(version: 20171114104051) do
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.datetime "last_update_started_at"
t.boolean "only_protected_branches", default: false, null: false
end
add_index "remote_mirrors", ["last_successful_update_at"], name: "index_remote_mirrors_on_last_successful_update_at", using: :btree
......
......@@ -226,6 +226,14 @@ In case of a diverged branch, you will see an error indicated at the
![Diverged branch](repository_mirroring/repository_mirroring_diverged_branch_push.png)
### Push only protected branches
>[Introduced][ee-3350] in Gitlab Enterprise Edition 10.3.
You can choose to only push your protected branches from GitLab to your remote repository.
To use this option go to your project's repository settings page under push mirror.
## Setting up a mirror from GitLab to GitHub
To set up a mirror from GitLab to GitHub, you need to follow these steps:
......@@ -265,6 +273,7 @@ to resolve this issue.
[ee-51]: https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/51
[ee-2551]: https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/2551
[ee-3117]: https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3117
[ee-3350]: https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3350
[perms]: ../user/permissions.md
[hooks]: https://docs.gitlab.com/ee/administration/custom_hooks.html
[deploy-key]: ../ssh/README.md#deploy-keys
......@@ -75,7 +75,7 @@ class Projects::MirrorsController < Projects::ApplicationController
end
def remote_mirror_attributes
{ remote_mirrors_attributes: %i[url id enabled] }
{ remote_mirrors_attributes: %i[url id enabled only_protected_branches] }
end
def mirror_params_attributes
......
......@@ -11,6 +11,8 @@ class RemoteMirror < ActiveRecord::Base
insecure_mode: true,
algorithm: 'aes-256-cbc'
default_value_for :only_protected_branches, true
belongs_to :project, inverse_of: :remote_mirrors
validates :url, presence: true, url: { protocols: %w(ssh git http https), allow_blank: true }
......
......@@ -38,5 +38,13 @@
.form-group.has-feedback
= rm_form.label :url, "Git repository URL", class: "label-light"
= rm_form.text_field :url, class: "form-control", placeholder: 'https://username:password@gitlab.company.com/group/project.git'
= render "projects/mirrors/instructions"
.form-group
= rm_form.check_box :only_protected_branches, class: 'pull-left'
.prepend-left-20
= rm_form.label :only_protected_branches, class: 'label-light'
= link_to icon('question-circle'), help_page_path('user/project/protected_branches')
= f.submit 'Save changes', class: 'btn btn-create', name: 'update_remote_mirror'
......@@ -4,7 +4,7 @@ describe Projects::UpdateRemoteMirrorService do
let(:project) { create(:project, :repository) }
let(:remote_project) { create(:forked_project_with_submodules) }
let(:repository) { project.repository }
let(:remote_mirror) { project.remote_mirrors.create!(url: remote_project.http_url_to_repo, enabled: true) }
let(:remote_mirror) { project.remote_mirrors.create!(url: remote_project.http_url_to_repo, enabled: true, only_protected_branches: false) }
subject { described_class.new(project, project.creator) }
......@@ -81,6 +81,40 @@ describe Projects::UpdateRemoteMirrorService do
subject.execute(remote_mirror)
end
context 'when push only protected branches option is set' do
let(:protected_branch_name) { project.repository.branch_names.first }
let!(:protected_branch) do
create(:protected_branch, project: project, name: protected_branch_name)
end
before do
project.reload
remote_mirror.only_protected_branches = true
end
it "sync updated protected branches" do
allow(repository).to receive(:fetch_remote) do
sync_remote(repository, remote_mirror.ref_name, local_branch_names)
update_branch(repository, protected_branch_name)
end
expect(repository).to receive(:push_remote_branches).with(remote_mirror.ref_name, [protected_branch_name])
subject.execute(remote_mirror)
end
it 'does not sync unprotected branches' do
allow(repository).to receive(:fetch_remote) do
sync_remote(repository, remote_mirror.ref_name, local_branch_names)
update_branch(repository, 'existing-branch')
end
expect(repository).not_to receive(:push_remote_branches).with(remote_mirror.ref_name, ['existing-branch'])
subject.execute(remote_mirror)
end
end
context 'when branch exists in local and remote repo' do
context 'when it has diverged' do
it 'syncs branches' do
......@@ -110,14 +144,89 @@ describe Projects::UpdateRemoteMirrorService do
end
end
context 'when push only protected branches option is set' do
before do
remote_mirror.only_protected_branches = true
end
context 'when branch exists in local and remote repo' do
let!(:protected_branch_name) { local_branch_names.first }
before do
create(:protected_branch, project: project, name: protected_branch_name)
project.reload
end
it 'deletes the protected branch from remote repo' do
allow(repository).to receive(:fetch_remote) do
sync_remote(repository, remote_mirror.ref_name, local_branch_names)
delete_branch(repository, protected_branch_name)
end
expect(repository).not_to receive(:delete_remote_branches).with(remote_mirror.ref_name, [protected_branch_name])
subject.execute(remote_mirror)
end
it 'does not delete the unprotected branch from remote repo' do
allow(repository).to receive(:fetch_remote) do
sync_remote(repository, remote_mirror.ref_name, local_branch_names)
delete_branch(repository, 'existing-branch')
end
expect(repository).not_to receive(:delete_remote_branches).with(remote_mirror.ref_name, ['existing-branch'])
subject.execute(remote_mirror)
end
end
context 'when branch only exists on remote repo' do
let!(:protected_branch_name) { 'remote-branch' }
before do
create(:protected_branch, project: project, name: protected_branch_name)
end
context 'when it has diverged' do
it 'does not delete the remote branch' do
allow(repository).to receive(:fetch_remote) do
sync_remote(repository, remote_mirror.ref_name, local_branch_names)
rev = repository.find_branch('markdown').dereferenced_target
create_remote_branch(repository, remote_mirror.ref_name, 'remote-branch', rev.id)
end
expect(repository).not_to receive(:delete_remote_branches)
subject.execute(remote_mirror)
end
end
context 'when it has not diverged' do
it 'deletes the remote branch' do
allow(repository).to receive(:fetch_remote) do
sync_remote(repository, remote_mirror.ref_name, local_branch_names)
masterrev = repository.find_branch('master').dereferenced_target
create_remote_branch(repository, remote_mirror.ref_name, protected_branch_name, masterrev.id)
end
expect(repository).to receive(:delete_remote_branches).with(remote_mirror.ref_name, [protected_branch_name])
subject.execute(remote_mirror)
end
end
end
end
context 'when branch only exists on remote repo' do
context 'when it has diverged' do
it 'does not delete the remote branch' do
allow(repository).to receive(:fetch_remote) do
sync_remote(repository, remote_mirror.ref_name, local_branch_names)
blob_id = 'c74175afd117781cbc983664339a0f599b5bb34e'
create_remote_branch(repository, remote_mirror.ref_name, 'remote-branch', blob_id)
rev = repository.find_branch('markdown').dereferenced_target
create_remote_branch(repository, remote_mirror.ref_name, 'remote-branch', rev.id)
end
expect(repository).not_to receive(:delete_remote_branches)
......
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