summaryrefslogtreecommitdiff
path: root/git-mirror-gitlab-ee
blob: 5467e16189546a94fd02b660a77da74695891862 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
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