#!/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 = {} @cache = {} # API docs suck, look at `lib/api/projects.rb` instead. @vars = [ :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 def finish @connections.each do |k,v| v.finish() end @connections = {} super 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 _info(project_id) @cache[project_id] ||= {} unless @cache[project_id].has_key?(:info) req = Net::HTTP::Get.new(@api_uri + "projects/" + CGI::escape(project_id)) req.add_field("PRIVATE-TOKEN", @api_key) con = _connection(req.uri) res = con.request(req) case res.code when "200" @cache[project_id][:info] = JSON::parse(res.body) when "404" @cache[project_id][:info] = nil else raise Error.new(res) end end return @cache[project_id][:info] end def cmd_config(*args) args.each do |arg| key, val = arg.split('=', 2) case key when "apiurl" @api_uri = URI(val) unless @api_uri.path.end_with?("/") @api_uri.path += "/" end when "apikey" @api_key = val end end end def cmd_get_meta(project_id) return _info(project_id).select{|k,v| @vars.include?(k.to_sym)} end def cmd_set_meta(project_id, *pairs) map = {} pairs.each do |pair| key, val = arg.split('=', 2) map[key] = val end 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 info = self._info(project_id) if info == nil # create req = Net::HTTP::Put.new(@api_uri + "projects")) req.add_field("PRIVATE-TOKEN", @api_key) 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) con = _connection(req.uri) res = con.request(req) if res.code != "201" raise Error.new(res) end @cache[project_id][:info] = JSON::parse(res.body) else # update req = Net::HTTP::Put.new(@api_uri + "projects/" + CGI::escape(info["id"].to_s)) req.add_field("PRIVATE-TOKEN", @api_key) req.add_field("Content-Type", "application/json") req.body = JSON::dump(map) con = _connection(req.uri) res = con.request(req) if res.code != "200" raise Error.new(res) end @cache[project_id][:info] = JSON::parse(res.body) end return get_meta end def cmd_push_url(project_id) return _info(project_id)["ssh_url_to_repo"] end def cmd_pull_url(project_id) return _info(project_id)["http_url_to_repo"] end def cmd_repo_mode return "passive" end end if __FILE__ == $0 if ARGV.length != 1 raise "Usage: $0 ACCOUNT_NAME" end GitLabCE.new().repl(ARGV[1]) end