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
106
107
108
109
110
111
112
113
114
115
116
117
118
|
#!/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 'git-mirror-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(self.info["web_url"]+"/mirror"))
req.add_field("PRIVATE-TOKEN", @gl.config['apikey'])
res = @gl.connection(req.uri).request(req)
if res.code != "200"
throw res
end
doc = Nokogiri::HTML(res.body)
@cache[:session] = res["set-cookie"]
@cache[:mirror_transaction] = 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)
libremessages('msg2', 'Setting mirror URL for %s', @project_id)
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[:session]) # session id
req.form_data = {
"utf8" => "✓",
"authenticity_token" => @cache[:mirror_transaction], # session state
"project[mirror]" => (url.nil? ? "0" : "1"),
"project[import_url]" => url.to_s,
"project[mirror_user_id]" => @gl.user_id,
}
res = @gl.connection(req.uri).request(req)
if res.code != "302"
throw res
end
@cache.delete(:mirror)
@cache.delete(:mirror_transaction)
@cache.delete(:session)
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
return nil
end
def repo_mode
return (self.mirrorURL.nil? ? "passive" : "active")
end
end
def user_id
req = Net::HTTP::Get.new(self.config['apiurl'] + 'user')
req.add_field("PRIVATE-TOKEN", self.config['apikey'])
res = self.connection(req.uri).request(req)
if res.code != "200"
raise Error.new(res)
end
user = JSON::parse(res.body)
return user["id"]
end
end
if __FILE__ == $0
if ARGV.length != 1
throw "Usage: $0 ACCOUNT_NAME"
end
GitLabEE.new().repl(ARGV[1])
end
|