#!/usr/bin/env ruby # coding: utf-8 # http://docs.gitlab.com/ee/workflow/repository_mirroring.html # https://gitlab.com/gitlab-org/gitlab-ee/issues/767 load 'gitmirrorbackend.rb' require 'net/http' require 'uri' require 'cgi' require 'json' class GitLabCE < GitMirrorBackend class Error < RuntimeError def initialize(obj) @obj = obj end def obj return @obj end end def initialize() @connections = {} @projects = {} @config = {} end def connection(uri) key=URI(uri.scheme+":") key.host = uri.host key.port = uri.port @connections[key] ||= Net::HTTP::start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') return @connections[key] end def finish @connections.each do |k,v| v.finish() end @connections = {} super end def config return @config end # Project def project(project_id) unless @projects.has_key?(project_id) @projects[project_id] = Project.new(self, project_id) end return @projects[project_id] end class Project def initialize(gl, project_id) @gl = gl @project_id = project_id @cache = {} end def info unless @cache.has_key?(:info) req = Net::HTTP::Get.new(@gl.config['apiurl'] + "projects/" + CGI::escape(@project_id)) req.add_field("PRIVATE-TOKEN", @gl.config['apikey']) res = @gl.connection(req.uri).request(req) case res.code when "200" @cache[:info] = JSON::parse(res.body) when "404" @cache[:info] = nil else raise Error.new(res) end end return @cache[:info] end def info=(i) @cache[:info] = i end def get_meta return self.info.select{|k,v| @vars.include?(k.to_sym)} end def set_meta(map) mirror = map["mirror"] map.delete("mirror") illegal = map.select{|k,v| not @vars.include?(k.to_sym)} if illegal.count > 0 raise Error.new(illegal) end if info == nil # create req = Net::HTTP::Put.new(@gl.config['apiurl'] + "projects") req.add_field("PRIVATE-TOKEN", @gl.config['apikey']) req.add_field("Content-Type", "application/json") map["path"] = @project_id if not mirror.nil? map["import_url"] = mirror end req.body = JSON::dump(map) res = @gl.connection(req.uri).request(req) if res.code != "201" raise Error.new(res) end info = JSON::parse(res.body) else # update req = Net::HTTP::Put.new(@gl.config['apiurl'] + "projects/" + CGI::escape(info["id"].to_s)) req.add_field("PRIVATE-TOKEN", @gl.config['apikey']) req.add_field("Content-Type", "application/json") req.body = JSON::dump(map) res = @gl.connection(req.uri).request(req) if res.code != "200" raise Error.new(res) end info = JSON::parse(res.body) end return self.get_meta end def repo_mode return "passive" end end # commands def cmd_config(*args) args.each do |arg| key, val = arg.split('=', 2) case key when "apiurl" val = URI(val) unless val.path.end_with?("/") val.path += "/" end end @config[key] = val end end def cmd_get_meta(project_id) return self.project(project_id).get_meta() end def cmd_set_meta(project_id, *pairs) map = {} pairs.each do |pair| key, val = arg.split('=', 2) map[key] = val end return self.project(project_id).set_meta(map) end def cmd_push_url(project_id) return self.project(project_id).info["ssh_url_to_repo"] end def cmd_pull_url(project_id) return self.project(project_id).info["http_url_to_repo"] end def cmd_repo_mode(project_id) return self.project(projecT_id).repo_mode() end def vars # API docs suck, look at `lib/api/projects.rb` instead. return [ :builds_enabled, # create | create-user | edit :container_registry_enabled, # XXX # create | | edit :default_branch, # | create-user | edit :description, # create | create-user | edit #:import_url, # XXX # create | create-user | :issues_enabled, # create | create-user | edit :lfs_enabled, # create | create-user | edit :merge_requests_enabled, # create | create-user | edit :name, # create | create-user | edit #:namespace_id, # create | | :only_allow_merge_if_build_succeeds, # create | create-user | edit #:path, # create | | edit :public, # create | create-user | edit :public_builds, # create | create-user | edit :request_access_enabled, # create | create-user | edit :shared_runners_enabled, # create | create-user | edit :snippets_enabled, # create | create-user | edit :visibility_level, # create | create-user | edit :wiki_enabled, # create | create-user | edit :only_allow_merge_if_all_discussions_are_resolved # create | create-user | edit ] end end if __FILE__ == $0 if ARGV.length != 1 raise "Usage: $0 ACCOUNT_NAME" end GitLabCE.new().repl(ARGV[1]) end