Commit 806fc946 authored by Tiago Botelho's avatar Tiago Botelho

Add option to remote mirrors to only push protected branches

parent 9c97a635
......@@ -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
......@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20171107144726) do
ActiveRecord::Schema.define(version: 20171110152729) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
......@@ -1958,6 +1958,7 @@ ActiveRecord::Schema.define(version: 20171107144726) 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
......@@ -76,7 +76,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