diff options
Diffstat (limited to 'ruby/lib/gitlab/git')
-rw-r--r-- | ruby/lib/gitlab/git/gitlab_projects.rb | 16 | ||||
-rw-r--r-- | ruby/lib/gitlab/git/remote_mirror.rb | 146 | ||||
-rw-r--r-- | ruby/lib/gitlab/git/repository.rb | 31 | ||||
-rw-r--r-- | ruby/lib/gitlab/git/repository_mirroring.rb | 113 |
4 files changed, 0 insertions, 306 deletions
diff --git a/ruby/lib/gitlab/git/gitlab_projects.rb b/ruby/lib/gitlab/git/gitlab_projects.rb index 9c11e4815..d90bf7ae8 100644 --- a/ruby/lib/gitlab/git/gitlab_projects.rb +++ b/ruby/lib/gitlab/git/gitlab_projects.rb @@ -76,22 +76,6 @@ module Gitlab true end - def delete_remote_branches(remote_name, branch_names, env: {}) - branch_names.each_slice(BRANCHES_PER_PUSH) do |branches| - logger.info "Pushing #{branches.count} deleted branches from #{repository_absolute_path} to remote #{remote_name}" - - cmd = %W(#{Gitlab.config.git.bin_path} push -- #{remote_name}) - branches.each { |branch| cmd << ":#{branch}" } - - unless run(cmd, repository_absolute_path, env) - logger.error("Pushing deleted branches to remote #{remote_name} failed.") - return false - end - end - - true - end - protected def run(*args) diff --git a/ruby/lib/gitlab/git/remote_mirror.rb b/ruby/lib/gitlab/git/remote_mirror.rb deleted file mode 100644 index 48f60f28f..000000000 --- a/ruby/lib/gitlab/git/remote_mirror.rb +++ /dev/null @@ -1,146 +0,0 @@ -module Gitlab - module Git - class RemoteMirror - attr_reader :repository, :remote_name, :ssh_auth, :only_branches_matching - - # An Array of local refnames that have diverged on the remote - # - # Only populated when `keep_divergent_refs` is enabled - attr_reader :divergent_refs - - def initialize(repository, remote_name, ssh_auth:, only_branches_matching:, keep_divergent_refs:) - @repository = repository - @remote_name = remote_name - @ssh_auth = ssh_auth - @only_branches_matching = only_branches_matching - @keep_divergent_refs = keep_divergent_refs - - @divergent_refs = [] - end - - def update - ssh_auth.setup do |env| - # Retrieve the remote branches first since they may take a while to load, - # and the local branches may have changed during this time. - remote_branch_list = remote_branches(env: env) - updated_branches = changed_refs(local_branches, remote_branch_list) - push_refs(default_branch_first(updated_branches.keys), env: env) - delete_refs(local_branches, remote_branches(env: env), env: env) - - local_tags = refs_obj(repository.tags) - remote_tags = refs_obj(repository.remote_tags(remote_name, env: env)) - - updated_tags = changed_refs(local_tags, remote_tags) - push_refs(updated_tags.keys, env: env) - delete_refs(local_tags, remote_tags, env: env) - end - end - - private - - def ref_matchers - @ref_matchers ||= only_branches_matching.map do |ref| - GitLab::RefMatcher.new(ref) - end - end - - def local_branches - @local_branches ||= refs_obj( - repository.local_branches, - match_refs: true - ) - end - - def remote_branches(env:) - @remote_branches ||= refs_obj( - repository.remote_branches(remote_name, env: env), - match_refs: true - ) - end - - def refs_obj(refs, match_refs: false) - refs.each_with_object({}) do |ref, refs| - next if match_refs && !include_ref?(ref.name) - - key = ref.is_a?(Gitlab::Git::Tag) ? ref.refname : ref.name - refs[key] = ref - end - end - - def changed_refs(local_refs, remote_refs) - local_refs.select do |ref_name, ref| - remote_ref = remote_refs[ref_name] - - # Ref doesn't exist on the remote, it should be created - next true if remote_ref.nil? - - local_target = ref.dereferenced_target - remote_target = remote_ref.dereferenced_target - - if local_target == remote_target - # Ref is identical on the remote, no point mirroring - false - elsif @keep_divergent_refs - # Mirror the ref if its remote counterpart hasn't diverged - if repository.ancestor?(remote_target&.id, local_target&.id) - true - else - Gitlab::GitLogger.info("Divergent ref `#{ref_name}` in #{repository.path} due to ancestry -- remote: #{remote_target&.id}, local: #{local_target&.id}") - @divergent_refs << ref.refname - false - end - else - # Attempt to overwrite whatever's on the remote; push rules and - # protected branches may still prevent this - true - end - end - end - - # Put the default branch first so it works fine when remote mirror is empty. - def default_branch_first(branches) - return unless branches.present? - - default_branch, branches = branches.partition do |branch| - repository.root_ref == branch - end - - branches.unshift(*default_branch) - end - - def push_refs(refs, env:) - return unless refs.present? - - repository.push_remote_branches(remote_name, refs, env: env) - end - - def delete_refs(local_refs, remote_refs, env:) - return if @keep_divergent_refs - - refs = refs_to_delete(local_refs, remote_refs) - - return unless refs.present? - - repository.delete_remote_branches(remote_name, refs.keys, env: env) - end - - def refs_to_delete(local_refs, remote_refs) - default_branch_id = repository.commit.id - - remote_refs.select do |remote_ref_name, remote_ref| - next false if local_refs[remote_ref_name] # skip if branch or tag exist in local repo - - remote_ref_id = remote_ref.dereferenced_target.try(:id) - - repository.ancestor?(remote_ref_id, default_branch_id) - end - end - - def include_ref?(ref_name) - return true unless ref_matchers.present? - - ref_matchers.any? { |matcher| matcher.matches?(ref_name) } - end - end - end -end diff --git a/ruby/lib/gitlab/git/repository.rb b/ruby/lib/gitlab/git/repository.rb index ae84b5300..02b9e05e9 100644 --- a/ruby/lib/gitlab/git/repository.rb +++ b/ruby/lib/gitlab/git/repository.rb @@ -4,7 +4,6 @@ module Gitlab module Git # These are monkey patches on top of the vendored version of Repository. class Repository - include Gitlab::Git::RepositoryMirroring include Gitlab::Git::Popen include Gitlab::EncodingHelper include Gitlab::Utils::StrongMemoize @@ -126,10 +125,6 @@ module Gitlab branches_filter end - def local_branches(sort_by: nil) - branches_filter(filter: :local, sort_by: sort_by) - end - # Git repository can contains some hidden refs like: # /refs/notes/* # /refs/git-as-svn/* @@ -193,14 +188,6 @@ module Gitlab end end - def ancestor?(from, to) - return false if from.nil? || to.nil? - - merge_base(from, to) == from - rescue Rugged::OdbError - false - end - def diff_exists?(sha1, sha2) rugged.diff(sha1, sha2).size.positive? end @@ -354,24 +341,6 @@ module Gitlab Ref.dereference_object(obj) end - def add_remote(remote_name, url, mirror_refmap: nil) - rugged.remotes.create(remote_name, url) - - set_remote_as_mirror(remote_name, refmap: mirror_refmap) if mirror_refmap - rescue Rugged::ConfigError - remote_update(remote_name, url: url) - end - - # Update the specified remote using the values in the +options+ hash - # - # Example - # repo.update_remote("origin", url: "path/to/repo") - def remote_update(remote_name, url:) - # TODO: Implement other remote options - rugged.remotes.set_url(remote_name, url) - nil - end - def commit(ref = nil) ref ||= root_ref Gitlab::Git::Commit.find(self, ref) diff --git a/ruby/lib/gitlab/git/repository_mirroring.rb b/ruby/lib/gitlab/git/repository_mirroring.rb deleted file mode 100644 index 79073ecb1..000000000 --- a/ruby/lib/gitlab/git/repository_mirroring.rb +++ /dev/null @@ -1,113 +0,0 @@ -module Gitlab - module Git - module RepositoryMirroring - GITLAB_PROJECTS_TIMEOUT = 10800 - - RemoteError = Class.new(StandardError) - - REFMAPS = { - # With `:all_refs`, the repository is equivalent to the result of `git clone --mirror` - all_refs: '+refs/*:refs/*', - heads: '+refs/heads/*:refs/heads/*', - tags: '+refs/tags/*:refs/tags/*' - }.freeze - - def remote_branches(remote_name, env:) - list_remote_refs(remote_name, env: env).map do |line| - target, refname = line.strip.split("\t") - - if target.nil? || refname.nil? - Rails.logger.info("Empty or invalid list of heads for remote: #{remote_name}") - break [] - end - - next unless refname.start_with?('refs/heads/') - - target_commit = Gitlab::Git::Commit.find(self, target) - Gitlab::Git::Branch.new(self, refname, target, target_commit) - end.compact - end - - def push_remote_branches(remote_name, branch_names, forced: true, env: {}) - success = @gitlab_projects.push_branches(remote_name, GITLAB_PROJECTS_TIMEOUT, forced, branch_names, env: env) - - success || gitlab_projects_error - end - - def delete_remote_branches(remote_name, branch_names, env: {}) - success = @gitlab_projects.delete_remote_branches(remote_name, branch_names, env: env) - - success || gitlab_projects_error - end - - def set_remote_as_mirror(remote_name, refmap: :all_refs) - set_remote_refmap(remote_name, refmap) - - rugged.config["remote.#{remote_name}.mirror"] = true - rugged.config["remote.#{remote_name}.prune"] = true - end - - def remote_tags(remote, env: {}) - # Each line has this format: "dc872e9fa6963f8f03da6c8f6f264d0845d6b092\trefs/tags/v1.10.0\n" - # We want to convert it to: [{ 'v1.10.0' => 'dc872e9fa6963f8f03da6c8f6f264d0845d6b092' }, ...] - list_remote_refs(remote, env: env).map do |line| - target, refname = line.strip.split("\t") - - # When the remote repo does not have tags. - if target.nil? || refname.nil? - Rails.logger.info "Empty or invalid list of tags for remote: #{remote}" - break [] - end - - next unless refname.start_with?('refs/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 refname.end_with?('^{}') - - target_commit = Gitlab::Git::Commit.find(self, target) - Gitlab::Git::Tag.new(self, - name: refname, - target: target, - target_commit: target_commit) - end.compact - end - - private - - 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 - - def list_remote_refs(remote, env:) - @list_remote_refs ||= {} - @list_remote_refs[remote] ||= begin - ref_list, exit_code, error = nil - - # List heads and tags, ignoring stuff like `refs/merge-requests` and `refs/pull` - cmd = %W[#{Gitlab.config.git.bin_path} --git-dir=#{path} ls-remote --heads --tags #{remote}] - - Open3.popen3(env, *cmd) do |_stdin, stdout, stderr, wait_thr| - ref_list = stdout.read - error = stderr.read - exit_code = wait_thr.value.exitstatus - end - - raise RemoteError, error unless exit_code.zero? - - ref_list.each_line(chomp: true) - end - end - end - end -end |