summaryrefslogtreecommitdiff
path: root/git-mirror-gitlab-ee
diff options
context:
space:
mode:
Diffstat (limited to 'git-mirror-gitlab-ee')
-rwxr-xr-xgit-mirror-gitlab-ee105
1 files changed, 105 insertions, 0 deletions
diff --git a/git-mirror-gitlab-ee b/git-mirror-gitlab-ee
new file mode 100755
index 0000000..5467e16
--- /dev/null
+++ b/git-mirror-gitlab-ee
@@ -0,0 +1,105 @@
+#!/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 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 < GitLabCE::Project
+ def mirrorURL
+ unless @cache.has_key?(:mirror)
+ req = Net::HTTP::Get.new(URI(_info["web_url"]+"/mirror"))
+ req.add_field("PRIVATE-TOKEN", @api_key)
+ res = @gl.connection(req.uri).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)
+ self.mirrorURL()
+
+ req = Net::HTTP::Patch.new(URI(self.info["web_url"]+"/mirror"))
+ req.add_field("PRIVATE-TOKEN", @gl.config['apikey']) # 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,
+ }
+
+ res = @gl.connection(req.uri).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"] = self.mirrorURL.to_s
+ return map
+ end
+
+ def set_meta(map)
+ if map.has_key?("mirror")
+ url = map["mirror"]
+ map.delete("mirror")
+ super(map)
+ self.mirrorURL = url
+ else
+ super(map)
+ end
+ end
+
+ def repo_mode
+ return (self.mirrorURL.nil? ? "active" : "passive")
+ end
+ end
+end
+
+if __FILE__ == $0
+ if ARGV.length != 1
+ throw "Usage: $0 ACCOUNT_NAME"
+ end
+ GitLabEE.new().repl(ARGV[1])
+end