summaryrefslogtreecommitdiff
path: root/backends
diff options
context:
space:
mode:
Diffstat (limited to 'backends')
-rwxr-xr-xbackends/github1
-rwxr-xr-xbackends/gitlab-ce152
-rwxr-xr-xbackends/gitlab-ee99
3 files changed, 252 insertions, 0 deletions
diff --git a/backends/github b/backends/github
new file mode 100755
index 0000000..49ffd26
--- /dev/null
+++ b/backends/github
@@ -0,0 +1 @@
+#!/usr/bin/env ruby
diff --git a/backends/gitlab-ce b/backends/gitlab-ce
new file mode 100755
index 0000000..3b6cc90
--- /dev/null
+++ b/backends/gitlab-ce
@@ -0,0 +1,152 @@
+#!/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
+
+require 'net/http'
+require 'uri'
+require 'cgi'
+require 'json'
+
+class GitLabCE
+ def initialize(api_uri, api_key, project_id)
+ @api_uri = URI(api_uri)
+ unless @api_uri.path.end_with?("/")
+ @api_uri.path += "/"
+ end
+ @api_key = api_key.to_s
+ @project_id = project_id.to_s
+
+ @connections = {}
+ @cache = {}
+
+ # API docs suck, just look at `lib/api/projects.rb`
+ @vars = [
+ :builds_enabled, # create | create-user | edit
+ :container_registry_enabled, # create | | edit
+ :default_branch # | create-user | edit
+ :description, # create | create-user | edit
+ :import_url, # 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
+ ]
+
+ @vars = [
+ "builds_enabled",
+ "container_registry_enabled",
+ "default_branch",
+ "description",
+ "issues_enabled",
+ "lfs_enabled",
+ "merge_requests_enabled",
+ "name",
+ "only_allow_merge_if_all_discussions_are_resolved",
+ "only_allow_merge_if_build_succeeds",
+ "path",
+ "public",
+ "public_builds",
+ "request_access_enabled",
+ "shared_runners_enabled",
+ "snippets_enabled",
+ "visibility_level",
+ "wiki_enabled",
+ ]
+ 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
+ unless @cache.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)
+ if res.code != "200"
+ throw res
+ end
+ @cache[:info] = JSON::parse(res.body)
+ end
+ return @cache[:info]
+ end
+
+ def get_meta
+ return _info.select{|k,v| @vars.include?(k)}
+ end
+
+ def set_meta(map)
+ illegal = map.select{|k,v| not @vars.include?(k)}
+ if illegal.count > 0
+ throw illegal
+ end
+
+ 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"
+ throw res
+ end
+ @cache[:info] = JSON::parse(res.body)
+ return get_meta
+ end
+
+ def pushURL
+ return _info["ssh_url_to_repo"]
+ end
+
+ def pullURL
+ return _info["http_url_to_repo"]
+ end
+
+ def create(id, map)
+ if map.has_key?("mirror")
+ map["import_url"] = map["mirror"]
+ map.delete("mirror")
+ end
+ req = Net::HTTP::Post.new(@api_uri + "projects")
+ 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)
+ end
+
+ def capabilities
+ return [
+ [ "get-meta", @vars ].flatten,
+ [ "set-meta", @vars ].flatten,
+ [ "push-url" ],
+ [ "pull-url" ],
+ ]
+ end
+
+ def finish
+ @connections.each do |k,v|
+ v.finish()
+ end
+ @connections = {}
+ end
+end
diff --git a/backends/gitlab-ee b/backends/gitlab-ee
new file mode 100755
index 0000000..d0db8b9
--- /dev/null
+++ b/backends/gitlab-ee
@@ -0,0 +1,99 @@
+#!/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