#!/usr/bin/env ruby # coding: utf-8 # GitLab EE supports configuring a "project" (GitLab's term for a # repository+metadata) to display as a mirror of another repository. # # http://docs.gitlab.com/ee/workflow/repository_mirroring.html # # Unfortunately, the JSON API doesn't support this # # https://gitlab.com/gitlab-org/gitlab-ee/issues/767 # # So, we must use the (undocumented!) HTTP API, which is actually # pretty clean, except that screen-scraping the reads (via nokogiri) # is gross, and that the error messages are unhelpful. load 'gitlab-ce' require 'net/http' require 'uri' require 'nokogiri' class GitLabEE < GitLabCE def _mirrorURL unless @cache.has_key?(:mirror) req = Net::HTTP::Get.new(URI(_info["web_url"]+"/mirror")) req.add_field("PRIVATE-TOKEN", @api_key) con = _connection(req.uri) res = con.request(req) if res.code != "200" throw res end @cache[:mirror_res]=res doc = Nokogiri::HTML(res.body) @cache[:mirror_cookie] = res["set-cookie"] @cache[:mirror_token] = doc.css('input[name="authenticity_token"]').first["value"] is_mirror = doc.css("#project_mirror").first["checked"] if !is_mirror @cache[:mirror] = nil else @cache[:mirror] = URI(doc.css("#project_import_url").first["value"]) end end return @cache[:mirror] end def _mirrorURL=(url) _mirrorURL req = Net::HTTP::Patch.new(URI(_info["web_url"]+"/mirror")) req.add_field("PRIVATE-TOKEN", @api_key) # authenticate req.add_field("Cookie", @cache[:mirror_cookie]) # session id req.form_data = { "utf8" => "✓", "authenticity_token" => @cache[:mirror_token], # session state "project[mirror]" => (url.nil? ? "0" : "1"), "project[import_url]" => url.to_s, } con = _connection(req.uri) res = con.request(req) if res.code != "302" throw res end @cache.delete(:mirror) @cache.delete(:mirror_token) @cache.delete(:mirror_cookie) return URI(url) end def get_meta map = super map["mirror"] = _mirrorURL.to_s return map end def set_meta(map) if map.has_key?("mirror") self._mirrorURL=map["mirror"] map.delete("mirror") end return super(map) end def create(id, map) super(id, map) self._mirrorURL=map["mirror"] end def capabilities return super.map{|c| if c[0] == "get-meta" or c[0] == "set-meta" c << "mirror" end c } end end