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
end
def full_url
mirror_url = Gitlab::ImportUrl.new(super, credentials: credentials)
mirror_url = Gitlab::ImportUrl.new(url, credentials: credentials)
mirror_url.full_url
end
......
......@@ -217,6 +217,10 @@ class Repository
gitlab_shell.fetch_remote(path_with_namespace, remote, forced: forced, no_tags: no_tags)
end
def remote_tags(remote)
gitlab_shell.list_remote_tags(path_with_namespace, remote)
end
def fetch_remote_forced!(remote)
gitlab_shell.fetch_remote(path_with_namespace, remote, forced: true)
end
......
......@@ -13,8 +13,11 @@ module Projects
errors << "The following branches have diverged from their local counterparts: #{divergent_branches.to_sentence}"
end
push_to_mirror if changed_branches.present?
delete_from_mirror if deleted_branches.present?
push_branches if changed_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
errors << e.message.strip
end
......@@ -28,6 +31,41 @@ module Projects
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
@changed_branches ||= local_branches.each_with_object([]) do |(name, branch), branches|
remote_branch = remote_branches[name]
......@@ -42,46 +80,51 @@ module Projects
end
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)
def divergent_branches
remote_branches.each_with_object([]) do |(name, branch), branches|
if local_branches[name] && repository.upstream_has_diverged?(name, mirror.ref_name)
branches << name
end
end
end
def push_to_mirror
default_branch, branches = changed_branches.partition { |name| project.default_branch == name }
def local_tags
@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.
branches.unshift(*default_branch)
def remote_tags
@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
def delete_from_mirror
repository.delete_remote_branches(project.path_with_namespace, mirror.ref_name, deleted_branches)
def push_tags
repository.push_branches(project.path_with_namespace, mirror.ref_name, changed_tags)
end
def local_branches
@local_branches ||= repository.local_branches.each_with_object({}) do |branch, branches|
branches[branch.name] = branch
end
def delete_tags
repository.delete_remote_branches(project.path_with_namespace, mirror.ref_name, deleted_tags)
end
def remote_branches
@remote_branches ||= repository.remote_branches(mirror.ref_name).each_with_object({}) do |branch, branches|
branches[branch.name] = branch
def changed_tags
@changed_tags ||= local_tags.each_with_object([]) do |(name, tag), tags|
remote_tag_target = remote_tags[name]
if remote_tag_target.nil? || (tag.target != remote_tag_target)
tags << name
end
end
end
def divergent_branches
remote_branches.each_with_object([]) do |(name, branch), branches|
if local_branches[name] && repository.upstream_has_diverged?(name, mirror.ref_name)
branches << name
end
def deleted_tags
@deleted_tags ||= remote_tags.each_with_object([]) do |(name, target), tags|
tags << name if local_tags[name].nil?
end
end
......
......@@ -41,6 +41,23 @@ module Gitlab
true
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
#
# 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