Commit 27899f84 authored by Rubén Dávila's avatar Rubén Dávila

Add ability to sync tags to remote mirror.

parent b23432dc
...@@ -101,7 +101,7 @@ class RemoteMirror < ActiveRecord::Base ...@@ -101,7 +101,7 @@ class RemoteMirror < ActiveRecord::Base
end end
def full_url def full_url
mirror_url = Gitlab::ImportUrl.new(super, credentials: credentials) mirror_url = Gitlab::ImportUrl.new(url, credentials: credentials)
mirror_url.full_url mirror_url.full_url
end end
......
...@@ -217,6 +217,10 @@ class Repository ...@@ -217,6 +217,10 @@ class Repository
gitlab_shell.fetch_remote(path_with_namespace, remote, forced: forced, no_tags: no_tags) gitlab_shell.fetch_remote(path_with_namespace, remote, forced: forced, no_tags: no_tags)
end end
def remote_tags(remote)
gitlab_shell.list_remote_tags(path_with_namespace, remote)
end
def fetch_remote_forced!(remote) def fetch_remote_forced!(remote)
gitlab_shell.fetch_remote(path_with_namespace, remote, forced: true) gitlab_shell.fetch_remote(path_with_namespace, remote, forced: true)
end end
......
...@@ -13,8 +13,11 @@ module Projects ...@@ -13,8 +13,11 @@ module Projects
errors << "The following branches have diverged from their local counterparts: #{divergent_branches.to_sentence}" errors << "The following branches have diverged from their local counterparts: #{divergent_branches.to_sentence}"
end end
push_to_mirror if changed_branches.present? push_branches if changed_branches.present?
delete_from_mirror if deleted_branches.present? delete_branches if deleted_branches.present?
push_tags if changed_tags.present?
delete_tags if deleted_tags.present?
rescue Gitlab::Shell::Error => e rescue Gitlab::Shell::Error => e
errors << e.message.strip errors << e.message.strip
end end
...@@ -28,6 +31,41 @@ module Projects ...@@ -28,6 +31,41 @@ module Projects
private private
def local_branches
@local_branches ||= repository.local_branches.each_with_object({}) do |branch, branches|
branches[branch.name] = branch
end
end
def remote_branches
@remote_branches ||= repository.remote_branches(mirror.ref_name).each_with_object({}) do |branch, branches|
branches[branch.name] = branch
end
end
def push_branches
default_branch, branches = changed_branches.partition { |name| project.default_branch == name }
# Push the default branch first so it works fine when remote mirror is empty.
branches.unshift(*default_branch)
repository.push_branches(project.path_with_namespace, mirror.ref_name, branches)
end
def delete_branches
repository.delete_remote_branches(project.path_with_namespace, mirror.ref_name, deleted_branches)
end
def deleted_branches
@deleted_branches ||= remote_branches.each_with_object([]) do |(name, branch), branches|
local_branch = local_branches[name]
if local_branch.nil? && project.commit(branch.target)
branches << name
end
end
end
def changed_branches def changed_branches
@changed_branches ||= local_branches.each_with_object([]) do |(name, branch), branches| @changed_branches ||= local_branches.each_with_object([]) do |(name, branch), branches|
remote_branch = remote_branches[name] remote_branch = remote_branches[name]
...@@ -42,46 +80,51 @@ module Projects ...@@ -42,46 +80,51 @@ module Projects
end end
end end
def deleted_branches def divergent_branches
@deleted_branches ||= remote_branches.each_with_object([]) do |(name, branch), branches| remote_branches.each_with_object([]) do |(name, branch), branches|
local_branch = local_branches[name] if local_branches[name] && repository.upstream_has_diverged?(name, mirror.ref_name)
if local_branch.nil? && project.commit(branch.target)
branches << name branches << name
end end
end end
end end
def push_to_mirror def local_tags
default_branch, branches = changed_branches.partition { |name| project.default_branch == name } @local_tags ||= repository.tags.each_with_object({}) do |tag, tags|
tags[tag.name] = tag
end
end
# Push the default branch first so it works fine when remote mirror is empty. def remote_tags
branches.unshift(*default_branch) @remote_tags ||= repository.remote_tags(mirror.ref_name).each_with_object({}) do |(name, target), tags|
# We're only interested in tag references
# See: http://stackoverflow.com/questions/15472107/when-listing-git-ls-remote-why-theres-after-the-tag-name
next if name =~ /\^\{\}\Z/
repository.push_branches(project.path_with_namespace, mirror.ref_name, branches) tags[name] = target
end
end end
def delete_from_mirror def push_tags
repository.delete_remote_branches(project.path_with_namespace, mirror.ref_name, deleted_branches) repository.push_branches(project.path_with_namespace, mirror.ref_name, changed_tags)
end end
def local_branches def delete_tags
@local_branches ||= repository.local_branches.each_with_object({}) do |branch, branches| repository.delete_remote_branches(project.path_with_namespace, mirror.ref_name, deleted_tags)
branches[branch.name] = branch
end
end end
def remote_branches def changed_tags
@remote_branches ||= repository.remote_branches(mirror.ref_name).each_with_object({}) do |branch, branches| @changed_tags ||= local_tags.each_with_object([]) do |(name, tag), tags|
branches[branch.name] = branch remote_tag_target = remote_tags[name]
if remote_tag_target.nil? || (tag.target != remote_tag_target)
tags << name
end
end end
end end
def divergent_branches def deleted_tags
remote_branches.each_with_object([]) do |(name, branch), branches| @deleted_tags ||= remote_tags.each_with_object([]) do |(name, target), tags|
if local_branches[name] && repository.upstream_has_diverged?(name, mirror.ref_name) tags << name if local_tags[name].nil?
branches << name
end
end end
end end
......
...@@ -41,6 +41,23 @@ module Gitlab ...@@ -41,6 +41,23 @@ module Gitlab
true true
end end
def list_remote_tags(name, remote)
output, status = Popen::popen([gitlab_shell_projects_path, 'list-remote-tags', "#{name}.git", remote])
raise Error, output unless status.zero?
# Each line has this format: "dc872e9fa6963f8f03da6c8f6f264d0845d6b092\trefs/tags/v1.10.0\n"
# We want to convert it to: [{ 'v1.10.0' => 'dc872e9fa6963f8f03da6c8f6f264d0845d6b092' }, ...]
tags_with_targets = output.lines.flat_map do |line|
target, path = line.strip!.split("\t")
name = path.split('/', 3).last
[name, target]
end
Hash[*tags_with_targets]
end
# Fetch remote for repository # Fetch remote for repository
# #
# name - project path with namespace # name - project path with namespace
......
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