gerry 0.1.1 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +9 -7
- data/lib/gerry/{client → api}/access.rb +1 -1
- data/lib/gerry/{client → api}/accounts.rb +13 -4
- data/lib/gerry/api/branches.rb +45 -0
- data/lib/gerry/api/changes.rb +38 -0
- data/lib/gerry/{client → api}/groups.rb +2 -2
- data/lib/gerry/{client → api}/projects.rb +31 -1
- data/lib/gerry/api/request.rb +88 -0
- data/lib/gerry/client.rb +38 -12
- data/lib/gerry/version.rb +2 -2
- data/spec/branches_spec.rb +36 -0
- data/spec/changes_spec.rb +6 -0
- data/spec/fixtures/README.md.json +2 -0
- data/spec/fixtures/branch_access.json +50 -0
- data/spec/fixtures/changes_batch_1.json +2 -1
- data/spec/fixtures/changes_batch_2.json +17 -0
- data/spec/fixtures/project_branch.json +6 -0
- data/spec/fixtures/project_branches.json +21 -0
- data/spec/projects_spec.rb +44 -8
- data/spec/request_spec.rb +12 -8
- metadata +55 -27
- data/lib/gerry/client/changes.rb +0 -20
- data/lib/gerry/client/request.rb +0 -113
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 66ad45b3c22d4eb38ac5829b13bf6a9423cf2fbb
|
4
|
+
data.tar.gz: 1047b76e06a51d583ea2b42f66456b1914f67602
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9ba5ebc6c65e04e4c87ee5685a68add849ed53530f7102f4baf84f2224c8c8a319f4617aeda246a363af6c3f5e7c75c0d84895094bcc7c99e5a76244501f88ac
|
7
|
+
data.tar.gz: cf25c860e26863235b9d22f3eda7fc5093ee2f2ef3e6982ba8e47b7fecee467d9e521fd4c38db750092cca37370aad4fa5ffefaf72f87361b67a3597c6d7e886
|
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# gerry[![Build Status](https://travis-ci.org/trumant/gerry.svg)][travis]
|
2
2
|
|
3
|
+
Base Gerrit Version V2.14.6
|
4
|
+
|
3
5
|
Simple Ruby wrapper for the Gerrit Code Review REST-API.
|
4
6
|
|
5
7
|
![Gary from spongebob square pants](http://en.spongepedia.org/images/3/37/Garry.jpg)
|
@@ -39,10 +41,14 @@ client.changes(['q=is:open'])
|
|
39
41
|
=> [{"project"=>"awesome", "branch"=>"master", "id"=>"Ibfedd978...."}]
|
40
42
|
```
|
41
43
|
|
44
|
+
### Authentication type
|
45
|
+
Since 2.14, Gerrit no longer supports digest authentication.
|
46
|
+
Gerry uses basic authentication against gerrit.
|
47
|
+
|
42
48
|
## Licence
|
43
49
|
The MIT Licence
|
44
50
|
|
45
|
-
Copyright (c) Fabian Mettler, Andrew Erickson, Travis Truman, Sebastian Schuberth
|
51
|
+
Copyright (c) Fabian Mettler, Andrew Erickson, Travis Truman, Sebastian Schuberth, Orgad Shaneh
|
46
52
|
|
47
53
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
48
54
|
|
@@ -51,10 +57,6 @@ The above copyright notice and this permission notice shall be included in all c
|
|
51
57
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
52
58
|
|
53
59
|
## References
|
54
|
-
|
55
|
-
|
56
|
-
[gerrit]: http://code.google.com/p/gerrit/
|
57
|
-
|
58
|
-
[https://gerrit-review.googlesource.com/Documentation/rest-api.html][apidocumentation]
|
60
|
+
https://www.gerritcodereview.com/
|
59
61
|
|
60
|
-
|
62
|
+
https://gerrit-review.googlesource.com/Documentation/rest-api.html
|
@@ -1,17 +1,26 @@
|
|
1
1
|
module Gerry
|
2
|
-
|
2
|
+
module Api
|
3
3
|
module Accounts
|
4
|
+
# Get the account info for the specified account ID.
|
5
|
+
#
|
6
|
+
# @param [String] account_id the account.
|
7
|
+
# @return [Hash] the account info.
|
8
|
+
def account_info(account_id)
|
9
|
+
url = "/accounts/#{account_id}"
|
10
|
+
get(url)
|
11
|
+
end
|
12
|
+
|
4
13
|
# Get the global capabilities that are enabled for the calling user.
|
5
14
|
#
|
6
15
|
# @param [Array] options the query parameters.
|
7
16
|
# @return [Hash] the account capabilities.
|
8
17
|
def account_capabilities(options = [])
|
9
18
|
url = '/accounts/self/capabilities'
|
10
|
-
|
19
|
+
|
11
20
|
if options.empty?
|
12
21
|
return get(url)
|
13
22
|
end
|
14
|
-
|
23
|
+
|
15
24
|
options = map_options(options)
|
16
25
|
get("#{url}?#{options}")
|
17
26
|
end
|
@@ -26,4 +35,4 @@ module Gerry
|
|
26
35
|
end
|
27
36
|
end
|
28
37
|
end
|
29
|
-
end
|
38
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gerry
|
4
|
+
module Api
|
5
|
+
module Branches
|
6
|
+
##
|
7
|
+
# Get the branches of project
|
8
|
+
#
|
9
|
+
def branches(project_name)
|
10
|
+
get("/projects/#{project_name}/branches")
|
11
|
+
end
|
12
|
+
|
13
|
+
# Get the projects that start with the specified prefix
|
14
|
+
# and accessible by the caller.
|
15
|
+
#
|
16
|
+
# @param [String] name the project name.
|
17
|
+
# @return [Hash] the projects.
|
18
|
+
def branch(project_name, branch_name)
|
19
|
+
get("/projects/#{project_name}/branches/#{branch_name}")
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
# create branch that derived from branch name or revision
|
24
|
+
#
|
25
|
+
# example: create_branch('foo', 'master', 'stable')
|
26
|
+
# create_branch('foo', 'revision', 'stable')
|
27
|
+
#
|
28
|
+
def create_branch(project_name, source, branch)
|
29
|
+
# try source as ref
|
30
|
+
body = { ref: source }
|
31
|
+
put("/projects/#{project_name}/branches/#{branch}", body)
|
32
|
+
rescue Gerry::Api::Request::RequestError
|
33
|
+
# try source as revision
|
34
|
+
body = { revision: source }
|
35
|
+
put("/projects/#{project_name}/branches/#{branch}", body)
|
36
|
+
end
|
37
|
+
|
38
|
+
##
|
39
|
+
# Gets the reflog of a certain branch.
|
40
|
+
def branch_reflog(project_name, branch, number)
|
41
|
+
get("/projects/#{project_name}/branches/#{branch}/reflog?n=#{number}")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
|
3
|
+
module Gerry
|
4
|
+
module Api
|
5
|
+
module Changes
|
6
|
+
# Get changes visible to the caller.
|
7
|
+
#
|
8
|
+
# @param [Array] options the query parameters.
|
9
|
+
# @return [Hash] the changes.
|
10
|
+
def changes(options = [])
|
11
|
+
endpoint = '/changes/'
|
12
|
+
url = endpoint
|
13
|
+
|
14
|
+
if !options.empty?
|
15
|
+
url += '?' + map_options(options)
|
16
|
+
end
|
17
|
+
|
18
|
+
response = get(url)
|
19
|
+
return response if response.empty? || !response.last.delete('_more_changes')
|
20
|
+
|
21
|
+
# Get the original start parameter, if any, else start from 0.
|
22
|
+
query = URI.parse(url).query
|
23
|
+
query = query ? CGI.parse(query) : { 'S' => ['0'] }
|
24
|
+
start = query['S'].join.to_i
|
25
|
+
|
26
|
+
# Keep getting data until there are no more changes.
|
27
|
+
loop do
|
28
|
+
# Replace the start parameter, using the original start as an offset.
|
29
|
+
query['S'] = ["#{start + response.size}"]
|
30
|
+
url = endpoint + '?' + map_options(query)
|
31
|
+
|
32
|
+
response.concat(get(url))
|
33
|
+
return response if response.empty? || !response.last.delete('_more_changes')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module Gerry
|
2
|
-
|
2
|
+
module Api
|
3
3
|
module Projects
|
4
4
|
# Get the projects accessible by the caller.
|
5
5
|
#
|
@@ -38,6 +38,36 @@ module Gerry
|
|
38
38
|
}
|
39
39
|
put(url, body)
|
40
40
|
end
|
41
|
+
|
42
|
+
##
|
43
|
+
# lists the access rights for signle project
|
44
|
+
def project_access(project)
|
45
|
+
get("/projects/#{project}/access")
|
46
|
+
end
|
47
|
+
|
48
|
+
def create_project_access(project, permissions)
|
49
|
+
access = {
|
50
|
+
'add' => permissions
|
51
|
+
}
|
52
|
+
post("/projects/#{project}/access", access)
|
53
|
+
end
|
54
|
+
|
55
|
+
def remove_project_access(project, permissions)
|
56
|
+
access = {
|
57
|
+
'remove' => permissions
|
58
|
+
}
|
59
|
+
post("/projects/#{project}/access", access)
|
60
|
+
end
|
61
|
+
|
62
|
+
##
|
63
|
+
# Retrieves a commit of a project.
|
64
|
+
def project_commit(project, commit_id)
|
65
|
+
get("/projects/#{project}/commits/#{commit_id}")
|
66
|
+
end
|
67
|
+
|
68
|
+
def project_file(project, commit_id, file_id)
|
69
|
+
get("/projects/#{project}/commits/#{commit_id}/files/#{file_id}/content")
|
70
|
+
end
|
41
71
|
end
|
42
72
|
end
|
43
73
|
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gerry
|
4
|
+
module Api
|
5
|
+
module Request # :nodoc:
|
6
|
+
class RequestError < StandardError
|
7
|
+
end
|
8
|
+
|
9
|
+
# Get the mapped options.
|
10
|
+
#
|
11
|
+
# @param [Array] or [Hash] options the query parameters.
|
12
|
+
# @return [String] the mapped options.
|
13
|
+
def map_options(options)
|
14
|
+
if options.is_a?(Array)
|
15
|
+
options.map { |v| "#{v}" }.join('&')
|
16
|
+
elsif options.is_a?(Hash)
|
17
|
+
options.map { |k,v| "#{k}=#{v.join(',')}" }.join('&')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def options(body = nil, is_json = true)
|
22
|
+
return {} unless body
|
23
|
+
default_options = {
|
24
|
+
headers: {
|
25
|
+
'Content-Type' => is_json ? 'application/json' : 'text/plain'
|
26
|
+
}
|
27
|
+
}
|
28
|
+
default_options[:body] = is_json ? body.to_json : body
|
29
|
+
default_options
|
30
|
+
end
|
31
|
+
|
32
|
+
def get(url)
|
33
|
+
response = self.class.get(auth_url(url))
|
34
|
+
parse(response)
|
35
|
+
end
|
36
|
+
|
37
|
+
def auth_url(url)
|
38
|
+
self.class.default_options[:basic_auth] ? "/a#{url}" : url
|
39
|
+
end
|
40
|
+
|
41
|
+
def put(url, body = nil, is_json = true)
|
42
|
+
response = self.class.put(auth_url(url), options(body, is_json))
|
43
|
+
parse(response)
|
44
|
+
end
|
45
|
+
|
46
|
+
def post(url, body, is_json = true)
|
47
|
+
response = self.class.post(auth_url(url), options(body, is_json))
|
48
|
+
parse(response)
|
49
|
+
end
|
50
|
+
|
51
|
+
def delete(url)
|
52
|
+
self.class.delete(auth_url(url))
|
53
|
+
parse(response)
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def parse(response)
|
59
|
+
unless /2[0-9][0-9]/.match(response.code.to_s)
|
60
|
+
raise_request_error(response)
|
61
|
+
end
|
62
|
+
unless response.body.size.zero?
|
63
|
+
source = remove_magic_prefix(response.body)
|
64
|
+
if source.lines.count == 1 && !source.start_with?('{') && !source.start_with?('[')
|
65
|
+
# Work around the JSON gem not being able to parse top-level values, see
|
66
|
+
# https://github.com/flori/json/issues/206.
|
67
|
+
source.gsub!(/^"|"$/, '')
|
68
|
+
else
|
69
|
+
JSON.parse(source)
|
70
|
+
end
|
71
|
+
else
|
72
|
+
nil
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def raise_request_error(response)
|
77
|
+
raise RequestError.new("There was a request error! Response was: #{response.message}")
|
78
|
+
end
|
79
|
+
|
80
|
+
def remove_magic_prefix(response_body)
|
81
|
+
# We need to strip the magic prefix from the first line of the response, see
|
82
|
+
# https://gerrit-review.googlesource.com/Documentation/rest-api.html#output.
|
83
|
+
# magic prefix: )]}
|
84
|
+
response_body[4..-1].strip!
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/lib/gerry/client.rb
CHANGED
@@ -1,24 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'httparty'
|
2
4
|
require 'json'
|
3
5
|
|
6
|
+
require_relative 'api/access'
|
7
|
+
require_relative 'api/accounts'
|
8
|
+
require_relative 'api/changes'
|
9
|
+
require_relative 'api/groups'
|
10
|
+
require_relative 'api/projects'
|
11
|
+
require_relative 'api/request'
|
12
|
+
require_relative 'api/branches'
|
13
|
+
|
14
|
+
|
4
15
|
module Gerry
|
16
|
+
##
|
17
|
+
# Client for gerrit request api
|
18
|
+
#
|
19
|
+
# - for anonymout user
|
20
|
+
# client = Gerry::Client.new('http://gerrit.example.com')
|
21
|
+
# - for user/password
|
22
|
+
# client = Gerry::Client.new('http://gerrit.example.com', 'username', 'password')
|
23
|
+
#
|
24
|
+
#
|
25
|
+
|
5
26
|
class Client
|
6
27
|
include HTTParty
|
7
28
|
headers 'Accept' => 'application/json'
|
8
29
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
30
|
+
include Api::Access
|
31
|
+
include Api::Accounts
|
32
|
+
include Api::Changes
|
33
|
+
include Api::Groups
|
34
|
+
include Api::Projects
|
35
|
+
include Api::Branches
|
36
|
+
include Api::Request
|
15
37
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
include Groups
|
20
|
-
include Projects
|
21
|
-
include Request
|
38
|
+
def set_auth_type(auth_type)
|
39
|
+
warn 'set_auth_type is deprecated. digest auth is no longer supported'
|
40
|
+
end
|
22
41
|
|
23
42
|
def initialize(url, username = nil, password = nil)
|
24
43
|
self.class.base_uri(url)
|
@@ -26,7 +45,14 @@ module Gerry
|
|
26
45
|
if username && password
|
27
46
|
@username = username
|
28
47
|
@password = password
|
48
|
+
else
|
49
|
+
require 'netrc'
|
50
|
+
@username, @password = Netrc.read[URI.parse(url).host]
|
51
|
+
end
|
52
|
+
if @username && @password
|
53
|
+
self.class.basic_auth(@username, @password)
|
29
54
|
end
|
30
55
|
end
|
31
56
|
end
|
32
57
|
end
|
58
|
+
|
data/lib/gerry/version.rb
CHANGED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'branches' do
|
4
|
+
before(:all) do
|
5
|
+
@client = MockGerry.new
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'fetchs all branches' do
|
9
|
+
stub = stub_get('/projects/foo/branches', 'project_branches.json')
|
10
|
+
|
11
|
+
groups = @client.branches('foo')
|
12
|
+
expect(stub).to have_been_requested
|
13
|
+
|
14
|
+
expect(groups.size).to eq(3)
|
15
|
+
expect(groups.first.fetch('ref')).to eq('master')
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'create branch' do
|
19
|
+
body = {
|
20
|
+
ref: 'master'
|
21
|
+
}
|
22
|
+
response = %Q<)]}'
|
23
|
+
{
|
24
|
+
"ref": "/refs/heads/stable",
|
25
|
+
"revision": "b43",
|
26
|
+
"can_delete": true
|
27
|
+
}
|
28
|
+
>
|
29
|
+
stub = stub_put('/projects/foo/branches/stable', body, response)
|
30
|
+
branch = @client.create_branch('foo', 'master', 'stable')
|
31
|
+
|
32
|
+
expect(stub).to have_been_requested
|
33
|
+
|
34
|
+
expect(branch.fetch('ref')).to eql('/refs/heads/stable')
|
35
|
+
end
|
36
|
+
end
|
data/spec/changes_spec.rb
CHANGED
@@ -20,6 +20,7 @@ describe '.changes' do
|
|
20
20
|
it 'should fetch all changes in batches' do
|
21
21
|
stub_batch_0 = stub_get('/changes/', 'changes_batch_0.json')
|
22
22
|
stub_batch_1 = stub_get('/changes/?S=1', 'changes_batch_1.json')
|
23
|
+
stub_batch_2 = stub_get('/changes/?S=2', 'changes_batch_2.json')
|
23
24
|
|
24
25
|
client = MockGerry.new
|
25
26
|
changes = client.changes
|
@@ -29,10 +30,15 @@ describe '.changes' do
|
|
29
30
|
|
30
31
|
expect(changes[0]['project']).to eq('awesome')
|
31
32
|
expect(changes[0]['branch']).to eq('master')
|
33
|
+
expect(changes[0]['owner']['name']).to eq('The Duke')
|
32
34
|
|
33
35
|
expect(changes[1]['project']).to eq('clean')
|
34
36
|
expect(changes[1]['subject']).to eq('Refactor code')
|
35
37
|
expect(changes[1]['owner']['name']).to eq('Batman')
|
38
|
+
|
39
|
+
expect(changes[2]['project']).to eq('X')
|
40
|
+
expect(changes[2]['subject']).to eq('Remove unused imports')
|
41
|
+
expect(changes[2]['owner']['name']).to eq('Bill')
|
36
42
|
end
|
37
43
|
|
38
44
|
it 'should fetch all open changes' do
|
@@ -0,0 +1,50 @@
|
|
1
|
+
)]}'
|
2
|
+
{
|
3
|
+
"revision": "61157ed63e14d261b6dca40650472a9b0bd88474",
|
4
|
+
"inherits_from": {
|
5
|
+
"id": "All-Projects",
|
6
|
+
"name": "All-Projects",
|
7
|
+
"description": "Access inherited by all other projects."
|
8
|
+
},
|
9
|
+
"local": {
|
10
|
+
"refs/*": {
|
11
|
+
"permissions": {
|
12
|
+
"read": {
|
13
|
+
"rules": {
|
14
|
+
"c2ce4749a32ceb82cd6adcce65b8216e12afb41c": {
|
15
|
+
"action": "ALLOW",
|
16
|
+
"force": false
|
17
|
+
},
|
18
|
+
"global:Anonymous-Users": {
|
19
|
+
"action": "ALLOW",
|
20
|
+
"force": false
|
21
|
+
}
|
22
|
+
}
|
23
|
+
}
|
24
|
+
}
|
25
|
+
}
|
26
|
+
},
|
27
|
+
"is_owner": true,
|
28
|
+
"owner_of": [
|
29
|
+
"refs/*"
|
30
|
+
],
|
31
|
+
"can_upload": true,
|
32
|
+
"can_add": true,
|
33
|
+
"config_visible": true,
|
34
|
+
"groups": {
|
35
|
+
"c2ce4749a32ceb82cd6adcce65b8216e12afb41c": {
|
36
|
+
"url": "#/admin/groups/uuid-c2ce4749a32ceb82cd6adcce65b8216e12afb41c",
|
37
|
+
"options": {},
|
38
|
+
"description": "Users who perform batch actions on Gerrit",
|
39
|
+
"group_id": 2,
|
40
|
+
"owner": "Administrators",
|
41
|
+
"owner_id": "d5b7124af4de52924ed397913e2c3b37bf186948",
|
42
|
+
"created_on": "2009-06-08 23:31:00.000000000",
|
43
|
+
"name": "Non-Interactive Users"
|
44
|
+
},
|
45
|
+
"global:Anonymous-Users": {
|
46
|
+
"options": {},
|
47
|
+
"name": "Anonymous Users"
|
48
|
+
}
|
49
|
+
}
|
50
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
)]}'
|
2
|
+
[
|
3
|
+
{
|
4
|
+
"project": "X",
|
5
|
+
"branch": "default",
|
6
|
+
"id": "Ieb185f4da8725ae35e9f940e614c6eaa7b88eff5",
|
7
|
+
"subject": "Remove unused imports",
|
8
|
+
"status": "NEW",
|
9
|
+
"created": "2016-01-11 15:51:30.605000000",
|
10
|
+
"updated": "2016-02-12 00:45:26.431000000",
|
11
|
+
"_sortkey": "002e4203000187d5",
|
12
|
+
"_number": 4711,
|
13
|
+
"owner": {
|
14
|
+
"name": "Bill"
|
15
|
+
}
|
16
|
+
}
|
17
|
+
]
|
@@ -0,0 +1,21 @@
|
|
1
|
+
)]}'
|
2
|
+
[
|
3
|
+
{
|
4
|
+
"ref": "master",
|
5
|
+
"revision": "b3f3113",
|
6
|
+
"can_delete": "yes",
|
7
|
+
"web_lnks": "ab"
|
8
|
+
},
|
9
|
+
{
|
10
|
+
"ref": "develop",
|
11
|
+
"revision": "b3f3114",
|
12
|
+
"can_delete": "yes",
|
13
|
+
"web_lnks": "ab"
|
14
|
+
},
|
15
|
+
{
|
16
|
+
"ref": "stage",
|
17
|
+
"revision": "b3f3114",
|
18
|
+
"can_delete": "yes",
|
19
|
+
"web_lnks": "ab"
|
20
|
+
}
|
21
|
+
]
|
data/spec/projects_spec.rb
CHANGED
@@ -1,11 +1,15 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'pry'
|
2
3
|
|
3
4
|
describe '.projects' do
|
5
|
+
before(:all) do
|
6
|
+
@client = MockGerry.new
|
7
|
+
end
|
8
|
+
|
4
9
|
it 'should fetch all projects' do
|
5
10
|
stub = stub_get('/projects/', 'projects.json')
|
6
11
|
|
7
|
-
|
8
|
-
projects = client.projects
|
12
|
+
projects = @client.projects
|
9
13
|
|
10
14
|
expect(stub).to have_been_requested
|
11
15
|
|
@@ -16,20 +20,27 @@ describe '.projects' do
|
|
16
20
|
it 'should fetch a project' do
|
17
21
|
stub = stub_get('/projects/awesome', 'projects.json')
|
18
22
|
|
19
|
-
|
20
|
-
projects = client.find_project('awesome')
|
23
|
+
projects = @client.find_project('awesome')
|
21
24
|
|
22
25
|
expect(stub).to have_been_requested
|
23
26
|
|
24
27
|
expect(projects['awesome']['description']).to eq('Awesome project')
|
25
28
|
end
|
26
29
|
|
30
|
+
it 'should fetch file content' do
|
31
|
+
stub = stub_get('/projects/awesome/commits/djfkslj/files/README.md/content','README.md.json')
|
32
|
+
|
33
|
+
file = @client.project_file('awesome','djfkslj','README.md')
|
34
|
+
|
35
|
+
expect(stub).to have_been_requested
|
36
|
+
expect(file).to eq('Hello World!')
|
37
|
+
end
|
38
|
+
|
27
39
|
it 'should resolve the symbolic HEAD ref of a project' do
|
28
40
|
project = 'awesome'
|
29
41
|
stub = stub_get("/projects/#{project}/HEAD", 'project_head.json')
|
30
42
|
|
31
|
-
|
32
|
-
branch = client.get_head(project)
|
43
|
+
branch = @client.get_head(project)
|
33
44
|
|
34
45
|
expect(stub).to have_been_requested
|
35
46
|
|
@@ -44,11 +55,36 @@ describe '.projects' do
|
|
44
55
|
}
|
45
56
|
stub = stub_put("/projects/#{project}/HEAD", input.to_json, get_fixture('project_head.json'))
|
46
57
|
|
47
|
-
|
48
|
-
new_branch = client.set_head(project, branch)
|
58
|
+
new_branch = @client.set_head(project, branch)
|
49
59
|
|
50
60
|
expect(stub).to have_been_requested
|
51
61
|
|
52
62
|
expect(new_branch).to eq('refs/heads/' + branch)
|
53
63
|
end
|
64
|
+
|
65
|
+
it 'list access rights' do
|
66
|
+
stub = stub_get('/projects/foo/access', 'branch_access.json')
|
67
|
+
|
68
|
+
accesses = @client.project_access('foo')
|
69
|
+
expect(stub).to have_been_requested
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'create project access rights' do
|
73
|
+
access_rights = {
|
74
|
+
'refs/heads/*' => {
|
75
|
+
'permissions' => {
|
76
|
+
'read' => {
|
77
|
+
'rules' => {
|
78
|
+
'user:kobe' => {
|
79
|
+
'action' => 'ALLOW'
|
80
|
+
}
|
81
|
+
}
|
82
|
+
}
|
83
|
+
}
|
84
|
+
}
|
85
|
+
}
|
86
|
+
stub = stub_post('/projects/foo/access', 'add' => access_rights)
|
87
|
+
@client.create_project_access('foo', access_rights)
|
88
|
+
expect(stub).to have_been_requested
|
89
|
+
end
|
54
90
|
end
|
data/spec/request_spec.rb
CHANGED
@@ -20,23 +20,27 @@ describe '.get' do
|
|
20
20
|
expect(stub).to have_been_requested
|
21
21
|
end
|
22
22
|
|
23
|
-
it 'should request projects as user' do
|
23
|
+
it 'should request projects as user with basic auth' do
|
24
24
|
username = 'gerry'
|
25
25
|
password = 'whoop'
|
26
26
|
|
27
27
|
body = get_fixture('projects.json')
|
28
|
-
|
29
|
-
stub = stub_request(:get,
|
30
|
-
|
31
|
-
|
28
|
+
|
29
|
+
stub = stub_request(:get, 'http://localhost/a/projects/').
|
30
|
+
with(
|
31
|
+
headers:
|
32
|
+
{
|
33
|
+
'Accept' => 'application/json',
|
34
|
+
'Authorization' => 'Basic Z2Vycnk6d2hvb3A='
|
35
|
+
}
|
36
|
+
).to_return(:status => 200, :body => body, :headers => {})
|
32
37
|
|
33
38
|
client = Gerry.new(MockGerry::URL, 'gerry', 'whoop')
|
34
39
|
projects = client.projects
|
35
40
|
|
36
|
-
|
37
|
-
expect(stub).to have_been_requested.twice
|
41
|
+
expect(stub).to have_been_requested
|
38
42
|
|
39
43
|
expect(projects['awesome']['description']).to eq('Awesome project')
|
40
44
|
expect(projects['clean']['description']).to eq('Clean code!')
|
41
45
|
end
|
42
|
-
end
|
46
|
+
end
|
metadata
CHANGED
@@ -1,17 +1,19 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gerry
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Fabian Mettler
|
8
8
|
- Andrew Erickson
|
9
9
|
- Travis Truman
|
10
10
|
- Sebastian Schuberth
|
11
|
+
- Orgad Shaneh
|
12
|
+
- iiithking
|
11
13
|
autorequire:
|
12
14
|
bindir: bin
|
13
15
|
cert_chain: []
|
14
|
-
date:
|
16
|
+
date: 2020-12-29 00:00:00.000000000 Z
|
15
17
|
dependencies:
|
16
18
|
- !ruby/object:Gem::Dependency
|
17
19
|
name: httparty
|
@@ -45,16 +47,16 @@ dependencies:
|
|
45
47
|
name: rspec
|
46
48
|
requirement: !ruby/object:Gem::Requirement
|
47
49
|
requirements:
|
48
|
-
- - "
|
50
|
+
- - ">="
|
49
51
|
- !ruby/object:Gem::Version
|
50
|
-
version:
|
52
|
+
version: '0'
|
51
53
|
type: :development
|
52
54
|
prerelease: false
|
53
55
|
version_requirements: !ruby/object:Gem::Requirement
|
54
56
|
requirements:
|
55
|
-
- - "
|
57
|
+
- - ">="
|
56
58
|
- !ruby/object:Gem::Version
|
57
|
-
version:
|
59
|
+
version: '0'
|
58
60
|
- !ruby/object:Gem::Dependency
|
59
61
|
name: rack-test
|
60
62
|
requirement: !ruby/object:Gem::Requirement
|
@@ -125,8 +127,21 @@ dependencies:
|
|
125
127
|
- - ">="
|
126
128
|
- !ruby/object:Gem::Version
|
127
129
|
version: '0'
|
128
|
-
|
129
|
-
|
130
|
+
- !ruby/object:Gem::Dependency
|
131
|
+
name: pry
|
132
|
+
requirement: !ruby/object:Gem::Requirement
|
133
|
+
requirements:
|
134
|
+
- - ">="
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: '0'
|
137
|
+
type: :development
|
138
|
+
prerelease: false
|
139
|
+
version_requirements: !ruby/object:Gem::Requirement
|
140
|
+
requirements:
|
141
|
+
- - ">="
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '0'
|
144
|
+
description: " Simple Ruby wrapper for the Gerrit Code Review REST-API.\n"
|
130
145
|
email: trumant@gmail.com
|
131
146
|
executables: []
|
132
147
|
extensions: []
|
@@ -135,26 +150,33 @@ files:
|
|
135
150
|
- README.md
|
136
151
|
- Rakefile
|
137
152
|
- lib/gerry.rb
|
153
|
+
- lib/gerry/api/access.rb
|
154
|
+
- lib/gerry/api/accounts.rb
|
155
|
+
- lib/gerry/api/branches.rb
|
156
|
+
- lib/gerry/api/changes.rb
|
157
|
+
- lib/gerry/api/groups.rb
|
158
|
+
- lib/gerry/api/projects.rb
|
159
|
+
- lib/gerry/api/request.rb
|
138
160
|
- lib/gerry/client.rb
|
139
|
-
- lib/gerry/client/access.rb
|
140
|
-
- lib/gerry/client/accounts.rb
|
141
|
-
- lib/gerry/client/changes.rb
|
142
|
-
- lib/gerry/client/groups.rb
|
143
|
-
- lib/gerry/client/projects.rb
|
144
|
-
- lib/gerry/client/request.rb
|
145
161
|
- lib/gerry/version.rb
|
146
162
|
- spec/access_spec.rb
|
147
163
|
- spec/accounts_spec.rb
|
164
|
+
- spec/branches_spec.rb
|
148
165
|
- spec/changes_spec.rb
|
166
|
+
- spec/fixtures/README.md.json
|
149
167
|
- spec/fixtures/access_rights.json
|
150
168
|
- spec/fixtures/account_groups.json
|
169
|
+
- spec/fixtures/branch_access.json
|
151
170
|
- spec/fixtures/capabilities.json
|
152
171
|
- spec/fixtures/changes.json
|
153
172
|
- spec/fixtures/changes_batch_0.json
|
154
173
|
- spec/fixtures/changes_batch_1.json
|
174
|
+
- spec/fixtures/changes_batch_2.json
|
155
175
|
- spec/fixtures/group_members.json
|
156
176
|
- spec/fixtures/groups.json
|
157
177
|
- spec/fixtures/open_changes.json
|
178
|
+
- spec/fixtures/project_branch.json
|
179
|
+
- spec/fixtures/project_branches.json
|
158
180
|
- spec/fixtures/project_head.json
|
159
181
|
- spec/fixtures/projects.json
|
160
182
|
- spec/fixtures/query_capabilities.json
|
@@ -181,27 +203,33 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
181
203
|
version: '0'
|
182
204
|
requirements: []
|
183
205
|
rubyforge_project:
|
184
|
-
rubygems_version: 2.
|
206
|
+
rubygems_version: 2.6.13
|
185
207
|
signing_key:
|
186
208
|
specification_version: 4
|
187
209
|
summary: Simple Ruby wrapper for the Gerrit Code Review REST-API.
|
188
210
|
test_files:
|
189
|
-
- spec/
|
190
|
-
- spec/accounts_spec.rb
|
211
|
+
- spec/spec_helper.rb
|
191
212
|
- spec/changes_spec.rb
|
192
|
-
- spec/
|
213
|
+
- spec/branches_spec.rb
|
214
|
+
- spec/request_spec.rb
|
215
|
+
- spec/accounts_spec.rb
|
216
|
+
- spec/projects_spec.rb
|
193
217
|
- spec/fixtures/account_groups.json
|
194
|
-
- spec/fixtures/
|
195
|
-
- spec/fixtures/
|
218
|
+
- spec/fixtures/project_head.json
|
219
|
+
- spec/fixtures/open_changes.json
|
220
|
+
- spec/fixtures/README.md.json
|
196
221
|
- spec/fixtures/changes_batch_0.json
|
197
222
|
- spec/fixtures/changes_batch_1.json
|
198
|
-
- spec/fixtures/
|
199
|
-
- spec/fixtures/
|
200
|
-
- spec/fixtures/
|
201
|
-
- spec/fixtures/project_head.json
|
223
|
+
- spec/fixtures/capabilities.json
|
224
|
+
- spec/fixtures/branch_access.json
|
225
|
+
- spec/fixtures/project_branch.json
|
202
226
|
- spec/fixtures/projects.json
|
227
|
+
- spec/fixtures/groups.json
|
203
228
|
- spec/fixtures/query_capabilities.json
|
229
|
+
- spec/fixtures/changes.json
|
230
|
+
- spec/fixtures/changes_batch_2.json
|
231
|
+
- spec/fixtures/access_rights.json
|
232
|
+
- spec/fixtures/group_members.json
|
233
|
+
- spec/fixtures/project_branches.json
|
234
|
+
- spec/access_spec.rb
|
204
235
|
- spec/groups_spec.rb
|
205
|
-
- spec/projects_spec.rb
|
206
|
-
- spec/request_spec.rb
|
207
|
-
- spec/spec_helper.rb
|
data/lib/gerry/client/changes.rb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
module Gerry
|
2
|
-
class Client
|
3
|
-
module Changes
|
4
|
-
# Get changes visible to the caller.
|
5
|
-
#
|
6
|
-
# @param [Array] options the query parameters.
|
7
|
-
# @return [Hash] the changes.
|
8
|
-
def changes(options = [])
|
9
|
-
url = '/changes/'
|
10
|
-
|
11
|
-
if options.empty?
|
12
|
-
return get(url)
|
13
|
-
end
|
14
|
-
|
15
|
-
options = map_options(options)
|
16
|
-
get("#{url}?#{options}")
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
data/lib/gerry/client/request.rb
DELETED
@@ -1,113 +0,0 @@
|
|
1
|
-
require 'cgi'
|
2
|
-
|
3
|
-
module Gerry
|
4
|
-
class Client
|
5
|
-
module Request
|
6
|
-
# Get the mapped options.
|
7
|
-
#
|
8
|
-
# @param [Array] options the query parameters.
|
9
|
-
# @return [String] the mapped options.
|
10
|
-
def map_options(options)
|
11
|
-
options.map{|v| "#{v}"}.join('&')
|
12
|
-
end
|
13
|
-
|
14
|
-
private
|
15
|
-
class RequestError < StandardError
|
16
|
-
end
|
17
|
-
|
18
|
-
def get(url)
|
19
|
-
orig_url = url
|
20
|
-
|
21
|
-
# Get the original start parameter, if any.
|
22
|
-
query = URI.parse(orig_url).query
|
23
|
-
start = query ? CGI.parse(query)['S'].join.to_i : 0
|
24
|
-
|
25
|
-
# Keep requesting data until there are no more changes.
|
26
|
-
all_results = []
|
27
|
-
loop do
|
28
|
-
response = if @username && @password
|
29
|
-
auth = { username: @username, password: @password }
|
30
|
-
self.class.get("/a#{url}", digest_auth: auth)
|
31
|
-
else
|
32
|
-
self.class.get(url)
|
33
|
-
end
|
34
|
-
|
35
|
-
result = parse(response)
|
36
|
-
return result unless result.is_a?(Array) && result.last.is_a?(Hash)
|
37
|
-
|
38
|
-
all_results.concat(result)
|
39
|
-
return all_results unless result.last.delete('_more_changes')
|
40
|
-
|
41
|
-
# Append the start parameter to the URL, overriding any previous start parameter.
|
42
|
-
url = orig_url + "#{query ? '&' : '?'}S=#{start + all_results.size}"
|
43
|
-
end
|
44
|
-
|
45
|
-
all_results
|
46
|
-
end
|
47
|
-
|
48
|
-
def put(url, body)
|
49
|
-
if @username && @password
|
50
|
-
auth = { username: @username, password: @password }
|
51
|
-
response = self.class.put("/a#{url}",
|
52
|
-
body: body.to_json,
|
53
|
-
headers: { 'Content-Type' => 'application/json' },
|
54
|
-
digest_auth: auth
|
55
|
-
)
|
56
|
-
parse(response)
|
57
|
-
else
|
58
|
-
response = self.class.put(url,
|
59
|
-
body: body.to_json,
|
60
|
-
headers: { 'Content-Type' => 'application/json' }
|
61
|
-
)
|
62
|
-
parse(response)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def post(url, body)
|
67
|
-
if @username && @password
|
68
|
-
auth = { username: @username, password: @password }
|
69
|
-
response = self.class.post("/a#{url}",
|
70
|
-
body: body.to_json,
|
71
|
-
headers: { 'Content-Type' => 'application/json' },
|
72
|
-
digest_auth: auth
|
73
|
-
)
|
74
|
-
parse(response)
|
75
|
-
else
|
76
|
-
response = self.class.post(url,
|
77
|
-
body: body.to_json,
|
78
|
-
headers: { 'Content-Type' => 'application/json' }
|
79
|
-
)
|
80
|
-
parse(response)
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def parse(response)
|
85
|
-
unless /2[0-9][0-9]/.match(response.code.to_s)
|
86
|
-
raise_request_error(response)
|
87
|
-
end
|
88
|
-
if response.body
|
89
|
-
source = remove_magic_prefix(response.body)
|
90
|
-
if source.lines.count == 1 && !source.start_with?('{') && !source.start_with?('[')
|
91
|
-
# Work around the JSON gem not being able to parse top-level values, see
|
92
|
-
# https://github.com/flori/json/issues/206.
|
93
|
-
source.gsub!(/^"|"$/, '')
|
94
|
-
else
|
95
|
-
JSON.parse(source)
|
96
|
-
end
|
97
|
-
else
|
98
|
-
nil
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
def raise_request_error(response)
|
103
|
-
raise RequestError.new("There was a request error! Response was: #{response.message}")
|
104
|
-
end
|
105
|
-
|
106
|
-
def remove_magic_prefix(response_body)
|
107
|
-
# We need to strip the magic prefix from the first line of the response, see
|
108
|
-
# https://gerrit-review.googlesource.com/Documentation/rest-api.html#output.
|
109
|
-
response_body.sub(/^\)\]\}'$/, '').strip!
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|