2017-10-14 21:52:07 -04:00
|
|
|
module Gitlab
|
|
|
|
module Git
|
|
|
|
module RepositoryMirroring
|
2017-11-23 10:51:55 -05:00
|
|
|
REFMAPS = {
|
|
|
|
# With `:all_refs`, the repository is equivalent to the result of `git clone --mirror`
|
|
|
|
all_refs: '+refs/*:refs/*',
|
2017-11-15 10:46:08 -05:00
|
|
|
heads: '+refs/heads/*:refs/heads/*',
|
|
|
|
tags: '+refs/tags/*:refs/tags/*'
|
|
|
|
}.freeze
|
2017-10-14 21:52:07 -04:00
|
|
|
|
|
|
|
RemoteError = Class.new(StandardError)
|
|
|
|
|
2017-11-23 10:51:55 -05:00
|
|
|
def set_remote_as_mirror(remote_name, refmap: :all_refs)
|
|
|
|
set_remote_refmap(remote_name, refmap)
|
2017-10-14 21:52:07 -04:00
|
|
|
|
|
|
|
rugged.config["remote.#{remote_name}.mirror"] = true
|
|
|
|
rugged.config["remote.#{remote_name}.prune"] = true
|
|
|
|
end
|
|
|
|
|
|
|
|
def remote_tags(remote)
|
|
|
|
# Each line has this format: "dc872e9fa6963f8f03da6c8f6f264d0845d6b092\trefs/tags/v1.10.0\n"
|
|
|
|
# We want to convert it to: [{ 'v1.10.0' => 'dc872e9fa6963f8f03da6c8f6f264d0845d6b092' }, ...]
|
|
|
|
list_remote_tags(remote).map do |line|
|
|
|
|
target, path = line.strip.split("\t")
|
|
|
|
|
|
|
|
# When the remote repo does not have tags.
|
|
|
|
if target.nil? || path.nil?
|
|
|
|
Rails.logger.info "Empty or invalid list of tags for remote: #{remote}. Output: #{output}"
|
2018-04-18 05:19:40 -04:00
|
|
|
break []
|
2017-10-14 21:52:07 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
name = path.split('/', 3).last
|
|
|
|
# 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/
|
|
|
|
|
|
|
|
target_commit = Gitlab::Git::Commit.find(self, target)
|
2018-03-20 15:20:12 -04:00
|
|
|
Gitlab::Git::Tag.new(self, {
|
|
|
|
name: name,
|
|
|
|
target: target,
|
|
|
|
target_commit: target_commit
|
|
|
|
})
|
2017-10-14 21:52:07 -04:00
|
|
|
end.compact
|
|
|
|
end
|
|
|
|
|
|
|
|
def remote_branches(remote_name)
|
|
|
|
branches = []
|
|
|
|
|
|
|
|
rugged.references.each("refs/remotes/#{remote_name}/*").map do |ref|
|
2018-01-27 00:35:53 -05:00
|
|
|
name = ref.name.sub(%r{\Arefs/remotes/#{remote_name}/}, '')
|
2017-10-14 21:52:07 -04:00
|
|
|
|
|
|
|
begin
|
|
|
|
target_commit = Gitlab::Git::Commit.find(self, ref.target)
|
|
|
|
branches << Gitlab::Git::Branch.new(self, name, ref.target, target_commit)
|
|
|
|
rescue Rugged::ReferenceError
|
|
|
|
# Omit invalid branch
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
branches
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
2017-12-06 17:08:29 -05:00
|
|
|
def set_remote_refmap(remote_name, refmap)
|
|
|
|
Array(refmap).each_with_index do |refspec, i|
|
|
|
|
refspec = REFMAPS[refspec] || refspec
|
|
|
|
|
|
|
|
# We need multiple `fetch` entries, but Rugged only allows replacing a config, not adding to it.
|
|
|
|
# To make sure we start from scratch, we set the first using rugged, and use `git` for any others
|
|
|
|
if i == 0
|
|
|
|
rugged.config["remote.#{remote_name}.fetch"] = refspec
|
|
|
|
else
|
|
|
|
run_git(%W[config --add remote.#{remote_name}.fetch #{refspec}])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-10-14 21:52:07 -04:00
|
|
|
def list_remote_tags(remote)
|
|
|
|
tag_list, exit_code, error = nil
|
2017-11-20 04:08:09 -05:00
|
|
|
cmd = %W(#{Gitlab.config.git.bin_path} --git-dir=#{path} ls-remote --tags #{remote})
|
2017-10-14 21:52:07 -04:00
|
|
|
|
|
|
|
Open3.popen3(*cmd) do |stdin, stdout, stderr, wait_thr|
|
|
|
|
tag_list = stdout.read
|
|
|
|
error = stderr.read
|
|
|
|
exit_code = wait_thr.value.exitstatus
|
|
|
|
end
|
|
|
|
|
|
|
|
raise RemoteError, error unless exit_code.zero?
|
|
|
|
|
2017-11-20 04:08:09 -05:00
|
|
|
tag_list.split("\n")
|
2017-10-14 21:52:07 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|