tinybucket2 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rubocop.yml +86 -0
- data/Gemfile +32 -0
- data/LICENSE +21 -0
- data/README.md +387 -0
- data/Rakefile +47 -0
- data/lib/faraday_middleware/follow_oauth_redirects.rb +71 -0
- data/lib/tinybucket.rb +76 -0
- data/lib/tinybucket/api.rb +26 -0
- data/lib/tinybucket/api/base_api.rb +44 -0
- data/lib/tinybucket/api/branch_restrictions_api.rb +51 -0
- data/lib/tinybucket/api/branches_api.rb +48 -0
- data/lib/tinybucket/api/build_status_api.rb +69 -0
- data/lib/tinybucket/api/comments_api.rb +81 -0
- data/lib/tinybucket/api/commits_api.rb +97 -0
- data/lib/tinybucket/api/diff_api.rb +40 -0
- data/lib/tinybucket/api/helper.rb +27 -0
- data/lib/tinybucket/api/helper/api_helper.rb +39 -0
- data/lib/tinybucket/api/helper/branch_restrictions_helper.rb +29 -0
- data/lib/tinybucket/api/helper/branches_helper.rb +29 -0
- data/lib/tinybucket/api/helper/build_status_helper.rb +46 -0
- data/lib/tinybucket/api/helper/comments_helper.rb +51 -0
- data/lib/tinybucket/api/helper/commits_helper.rb +42 -0
- data/lib/tinybucket/api/helper/diff_helper.rb +31 -0
- data/lib/tinybucket/api/helper/issues_helper.rb +29 -0
- data/lib/tinybucket/api/helper/projects_helper.rb +28 -0
- data/lib/tinybucket/api/helper/pull_requests_helper.rb +58 -0
- data/lib/tinybucket/api/helper/repo_helper.rb +31 -0
- data/lib/tinybucket/api/helper/repos_helper.rb +23 -0
- data/lib/tinybucket/api/helper/team_helper.rb +45 -0
- data/lib/tinybucket/api/helper/user_helper.rb +33 -0
- data/lib/tinybucket/api/issues_api.rb +48 -0
- data/lib/tinybucket/api/projects_api.rb +26 -0
- data/lib/tinybucket/api/pull_requests_api.rb +117 -0
- data/lib/tinybucket/api/repo_api.rb +56 -0
- data/lib/tinybucket/api/repos_api.rb +28 -0
- data/lib/tinybucket/api/team_api.rb +91 -0
- data/lib/tinybucket/api/user_api.rb +66 -0
- data/lib/tinybucket/api_factory.rb +21 -0
- data/lib/tinybucket/client.rb +107 -0
- data/lib/tinybucket/config.rb +10 -0
- data/lib/tinybucket/connection.rb +84 -0
- data/lib/tinybucket/constants.rb +7 -0
- data/lib/tinybucket/enumerator.rb +47 -0
- data/lib/tinybucket/error.rb +12 -0
- data/lib/tinybucket/error/base_error.rb +14 -0
- data/lib/tinybucket/error/conflict.rb +8 -0
- data/lib/tinybucket/error/not_found.rb +8 -0
- data/lib/tinybucket/error/service_error.rb +26 -0
- data/lib/tinybucket/iterator.rb +79 -0
- data/lib/tinybucket/model.rb +25 -0
- data/lib/tinybucket/model/base.rb +45 -0
- data/lib/tinybucket/model/branch.rb +48 -0
- data/lib/tinybucket/model/branch_restriction.rb +46 -0
- data/lib/tinybucket/model/build_status.rb +57 -0
- data/lib/tinybucket/model/comment.rb +67 -0
- data/lib/tinybucket/model/commit.rb +114 -0
- data/lib/tinybucket/model/concerns.rb +19 -0
- data/lib/tinybucket/model/concerns/acceptable_attributes.rb +34 -0
- data/lib/tinybucket/model/concerns/api_callable.rb +21 -0
- data/lib/tinybucket/model/concerns/enumerable.rb +20 -0
- data/lib/tinybucket/model/concerns/reloadable.rb +41 -0
- data/lib/tinybucket/model/concerns/repository_keys.rb +45 -0
- data/lib/tinybucket/model/error_response.rb +24 -0
- data/lib/tinybucket/model/issue.rb +48 -0
- data/lib/tinybucket/model/page.rb +45 -0
- data/lib/tinybucket/model/profile.rb +70 -0
- data/lib/tinybucket/model/project.rb +44 -0
- data/lib/tinybucket/model/pull_request.rb +160 -0
- data/lib/tinybucket/model/repository.rb +219 -0
- data/lib/tinybucket/model/team.rb +96 -0
- data/lib/tinybucket/null_logger.rb +37 -0
- data/lib/tinybucket/parser.rb +15 -0
- data/lib/tinybucket/parser/collection_parser.rb +17 -0
- data/lib/tinybucket/parser/object_parser.rb +17 -0
- data/lib/tinybucket/request.rb +59 -0
- data/lib/tinybucket/resource.rb +75 -0
- data/lib/tinybucket/resource/base.rb +35 -0
- data/lib/tinybucket/resource/branch_restrictions.rb +47 -0
- data/lib/tinybucket/resource/branches.rb +35 -0
- data/lib/tinybucket/resource/commit/base.rb +14 -0
- data/lib/tinybucket/resource/commit/build_statuses.rb +50 -0
- data/lib/tinybucket/resource/commit/comments.rb +34 -0
- data/lib/tinybucket/resource/commits.rb +46 -0
- data/lib/tinybucket/resource/forks.rb +24 -0
- data/lib/tinybucket/resource/issues.rb +35 -0
- data/lib/tinybucket/resource/projects.rb +49 -0
- data/lib/tinybucket/resource/pull_request/base.rb +20 -0
- data/lib/tinybucket/resource/pull_request/comments.rb +32 -0
- data/lib/tinybucket/resource/pull_request/commits.rb +19 -0
- data/lib/tinybucket/resource/pull_requests.rb +50 -0
- data/lib/tinybucket/resource/repos.rb +40 -0
- data/lib/tinybucket/resource/team/base.rb +24 -0
- data/lib/tinybucket/resource/team/followers.rb +15 -0
- data/lib/tinybucket/resource/team/following.rb +15 -0
- data/lib/tinybucket/resource/team/members.rb +15 -0
- data/lib/tinybucket/resource/team/repos.rb +15 -0
- data/lib/tinybucket/resource/teams.rb +22 -0
- data/lib/tinybucket/resource/user/base.rb +26 -0
- data/lib/tinybucket/resource/user/followers.rb +15 -0
- data/lib/tinybucket/resource/user/following.rb +15 -0
- data/lib/tinybucket/resource/user/repos.rb +15 -0
- data/lib/tinybucket/resource/watchers.rb +24 -0
- data/lib/tinybucket/response.rb +9 -0
- data/lib/tinybucket/response/handler.rb +23 -0
- data/lib/tinybucket/version.rb +5 -0
- data/tinybucket.gemspec +30 -0
- metadata +248 -0
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tinybucket
|
4
|
+
module Api
|
5
|
+
# Commits Api client
|
6
|
+
#
|
7
|
+
# @!attribute [rw] repo_owner
|
8
|
+
# @return [String] repository owner name.
|
9
|
+
# @!attribute [rw] repo_slug
|
10
|
+
# @return [String] {https://developer.atlassian.com/bitbucket/api/2/reference/resource/repositories/%7Busername%7D/%7Brepo_slug%7D repository slug}.
|
11
|
+
class CommitsApi < BaseApi
|
12
|
+
include Tinybucket::Api::Helper::CommitsHelper
|
13
|
+
|
14
|
+
attr_accessor :repo_owner, :repo_slug
|
15
|
+
|
16
|
+
# Send 'GET a commits list for a repository' request
|
17
|
+
#
|
18
|
+
# @see https://developer.atlassian.com/bitbucket/api/2/reference/resource/repositories/%7Busername%7D/%7Brepo_slug%7D/commits#get
|
19
|
+
# GET a commits list for a repository
|
20
|
+
#
|
21
|
+
# @note This method does not support 'compare commits across branches'
|
22
|
+
# API call, yet.
|
23
|
+
#
|
24
|
+
# @param options [Hash]
|
25
|
+
# @return [Tinybucket::Model::Page]
|
26
|
+
def list(options = {})
|
27
|
+
get_path(
|
28
|
+
path_to_list,
|
29
|
+
options,
|
30
|
+
get_parser(:collection, Tinybucket::Model::Commit)
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Send 'GET an individual commit' request
|
35
|
+
#
|
36
|
+
# @see https://developer.atlassian.com/bitbucket/api/2/reference/resource/repositories/%7Busername%7D/%7Brepo_slug%7D/commits/%7Brevision%7D#get
|
37
|
+
# GET an individual commit
|
38
|
+
#
|
39
|
+
# @param revision [String] A SHA1 value for the commit.
|
40
|
+
# @param options [Hash]
|
41
|
+
# @return [Tinybucket::Model::Commit]
|
42
|
+
def find(revision, options = {})
|
43
|
+
get_path(
|
44
|
+
path_to_find(revision),
|
45
|
+
options,
|
46
|
+
get_parser(:object, Tinybucket::Model::Commit)
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Send 'POST a commit approval' request
|
51
|
+
# @see https://developer.atlassian.com/bitbucket/api/2/reference/resource/repositories/%7Busername%7D/%7Brepo_slug%7D/commit/%7Bnode%7D/approve#post
|
52
|
+
# POST a commit approval request
|
53
|
+
#
|
54
|
+
# @param revision [String]
|
55
|
+
# @param options [Hash]
|
56
|
+
# @return [true, false]
|
57
|
+
def approve(revision, options = {})
|
58
|
+
result = post_path(path_to_approve(revision), options)
|
59
|
+
(result['approved'] == true)
|
60
|
+
rescue Tinybucket::Error::Conflict => e
|
61
|
+
logger.debug 'Already approved: ' + e.inspect
|
62
|
+
true
|
63
|
+
end
|
64
|
+
|
65
|
+
# Send 'DELETE a commit approval' request
|
66
|
+
# @see https://developer.atlassian.com/bitbucket/api/2/reference/resource/repositories/%7Busername%7D/%7Brepo_slug%7D/commit/%7Bnode%7D/approve#delete
|
67
|
+
# DELETE a commit approval (unapprove the commit)
|
68
|
+
#
|
69
|
+
# @param revision [String]
|
70
|
+
# @param options [Hash]
|
71
|
+
# @return [true, false]
|
72
|
+
def unapprove(revision, options = {})
|
73
|
+
delete_path(path_to_approve(revision), options)
|
74
|
+
true
|
75
|
+
rescue Tinybucket::Error::NotFound => e
|
76
|
+
logger.debug 'Already unapproved: ' + e.inspect
|
77
|
+
true
|
78
|
+
end
|
79
|
+
|
80
|
+
# Send 'GET commits for a branch' request
|
81
|
+
#
|
82
|
+
# @see https://developer.atlassian.com/bitbucket/api/2/reference/resource/repositories/%7Busername%7D/%7Brepo_slug%7D/commits
|
83
|
+
# GET an individual commit
|
84
|
+
#
|
85
|
+
# @param name [String] The branch name or a SHA1 value for the commit.
|
86
|
+
# @param options [Hash]
|
87
|
+
# @return [Tinybucket::Model::Commit]
|
88
|
+
def branch(name, options = {})
|
89
|
+
get_path(
|
90
|
+
path_to_branch(name),
|
91
|
+
options,
|
92
|
+
get_parser(:collection, Tinybucket::Model::Commit)
|
93
|
+
)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tinybucket
|
4
|
+
module Api
|
5
|
+
# Diff Api client
|
6
|
+
#
|
7
|
+
# @see https://developer.atlassian.com/bitbucket/api/2/reference/resource/repositories/%7Busername%7D/%7Brepo_slug%7D/diff/%7Bspec%7D
|
8
|
+
# diff Resource
|
9
|
+
#
|
10
|
+
# @!attribute [rw] repo_owner
|
11
|
+
# @return [String] repository owner name.
|
12
|
+
# @!attribute [rw] repo_slug
|
13
|
+
# @return [String] {https://developer.atlassian.com/bitbucket/api/2/reference/resource/repositories/%7Busername%7D/%7Brepo_slug%7D repository slug}.
|
14
|
+
class DiffApi < BaseApi
|
15
|
+
include Tinybucket::Api::Helper::DiffHelper
|
16
|
+
|
17
|
+
attr_accessor :repo_owner, :repo_slug
|
18
|
+
|
19
|
+
# Send 'GET a diff' request
|
20
|
+
#
|
21
|
+
# @param spec [String] A specification such as a branch name,
|
22
|
+
# revision, or commit SHA.
|
23
|
+
# @param options [Hash]
|
24
|
+
# @return [String] diff as raw text
|
25
|
+
def find(spec, options = {})
|
26
|
+
get_path(path_to_find(spec), options)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Send 'GET a patch' request
|
30
|
+
#
|
31
|
+
# @param spec [String] A specification such as a branch name,
|
32
|
+
# revision, or commit SHA.
|
33
|
+
# @param options [Hash]
|
34
|
+
# @return [String] patch as raw text
|
35
|
+
def find_patch(spec, options = {})
|
36
|
+
get_path(path_to_patch(spec), options)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tinybucket
|
4
|
+
module Api
|
5
|
+
module Helper
|
6
|
+
extend ActiveSupport::Autoload
|
7
|
+
|
8
|
+
[
|
9
|
+
:ApiHelper,
|
10
|
+
:BranchesHelper,
|
11
|
+
:BranchRestrictionsHelper,
|
12
|
+
:BuildStatusHelper,
|
13
|
+
:CommitsHelper,
|
14
|
+
:CommentsHelper,
|
15
|
+
:DiffHelper,
|
16
|
+
:ReposHelper,
|
17
|
+
:RepoHelper,
|
18
|
+
:PullRequestsHelper,
|
19
|
+
:ProjectsHelper,
|
20
|
+
:TeamHelper,
|
21
|
+
:UserHelper
|
22
|
+
].each do |klass_name|
|
23
|
+
autoload klass_name
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tinybucket
|
4
|
+
module Api
|
5
|
+
module Helper
|
6
|
+
module ApiHelper
|
7
|
+
private
|
8
|
+
|
9
|
+
def next_proc(method, options)
|
10
|
+
lambda do |next_options|
|
11
|
+
send(method, options.merge(next_options))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def urlencode(v, key)
|
16
|
+
if v.blank? || (escaped = CGI.escape(v.to_s)).blank?
|
17
|
+
msg = "Invalid #{key} parameter. (#{v})"
|
18
|
+
raise ArgumentError, msg
|
19
|
+
end
|
20
|
+
|
21
|
+
escaped
|
22
|
+
end
|
23
|
+
|
24
|
+
def build_path(base_path, *components)
|
25
|
+
components.reduce(base_path) do |path, component|
|
26
|
+
part = if component.is_a?(Array)
|
27
|
+
urlencode(*component)
|
28
|
+
else
|
29
|
+
component.to_s
|
30
|
+
end
|
31
|
+
path + '/' + part
|
32
|
+
end
|
33
|
+
rescue ArgumentError => e
|
34
|
+
raise ArgumentError, "Failed to build request URL: #{e}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tinybucket
|
4
|
+
module Api
|
5
|
+
module Helper
|
6
|
+
module BranchRestrictionsHelper
|
7
|
+
include ::Tinybucket::Api::Helper::ApiHelper
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def path_to_list
|
12
|
+
base_path
|
13
|
+
end
|
14
|
+
|
15
|
+
def path_to_find(restriction_id)
|
16
|
+
build_path(base_path,
|
17
|
+
[restriction_id, 'restriction_id'])
|
18
|
+
end
|
19
|
+
|
20
|
+
def base_path
|
21
|
+
build_path('/repositories',
|
22
|
+
[repo_owner, 'repo_owner'],
|
23
|
+
[repo_slug, 'repo_slug'],
|
24
|
+
'branch-restrictions')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tinybucket
|
4
|
+
module Api
|
5
|
+
module Helper
|
6
|
+
module BranchesHelper
|
7
|
+
include ::Tinybucket::Api::Helper::ApiHelper
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def path_to_list
|
12
|
+
build_path(base_path)
|
13
|
+
end
|
14
|
+
|
15
|
+
def path_to_find(branch)
|
16
|
+
build_path(base_path,
|
17
|
+
[branch, 'branch'])
|
18
|
+
end
|
19
|
+
|
20
|
+
def base_path
|
21
|
+
build_path('/repositories',
|
22
|
+
[repo_owner, 'repo_owner'],
|
23
|
+
[repo_slug, 'repo_slug'],
|
24
|
+
'refs', 'branches')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tinybucket
|
4
|
+
module Api
|
5
|
+
module Helper
|
6
|
+
module BuildStatusHelper
|
7
|
+
include ::Tinybucket::Api::Helper::ApiHelper
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def path_to_list
|
12
|
+
build_path('/repositories',
|
13
|
+
[repo_owner, 'repo_owner'],
|
14
|
+
[repo_slug, 'repo_slug'],
|
15
|
+
'commit',
|
16
|
+
[revision, 'revision'],
|
17
|
+
'statuses')
|
18
|
+
end
|
19
|
+
|
20
|
+
def path_to_find(revision, key)
|
21
|
+
build_path(base_path(revision),
|
22
|
+
[key, 'key'])
|
23
|
+
end
|
24
|
+
|
25
|
+
def path_to_post(revision)
|
26
|
+
base_path(revision)
|
27
|
+
end
|
28
|
+
|
29
|
+
def path_to_put(revision, key)
|
30
|
+
build_path(base_path(revision),
|
31
|
+
[key, 'key'])
|
32
|
+
end
|
33
|
+
|
34
|
+
def base_path(revision)
|
35
|
+
build_path('/repositories',
|
36
|
+
[repo_owner, 'repo_owner'],
|
37
|
+
[repo_slug, 'repo_slug'],
|
38
|
+
'commit',
|
39
|
+
[revision, 'revision'],
|
40
|
+
'statuses',
|
41
|
+
'build')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tinybucket
|
4
|
+
module Api
|
5
|
+
module Helper
|
6
|
+
module CommentsHelper
|
7
|
+
include ::Tinybucket::Api::Helper::ApiHelper
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def path_to_list
|
12
|
+
base_path
|
13
|
+
end
|
14
|
+
|
15
|
+
def path_to_find(comment_id)
|
16
|
+
build_path(base_path,
|
17
|
+
[comment_id, 'comment_id'])
|
18
|
+
end
|
19
|
+
|
20
|
+
def base_path
|
21
|
+
case commented_to
|
22
|
+
when Tinybucket::Model::Commit
|
23
|
+
base_path_of_commit
|
24
|
+
when Tinybucket::Model::PullRequest
|
25
|
+
base_path_of_pullrequest
|
26
|
+
else
|
27
|
+
raise ArgumentError, 'commented_to must be a pull_request or commit'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def base_path_of_commit
|
32
|
+
build_path('/repositories',
|
33
|
+
[repo_owner, 'repo_owner'],
|
34
|
+
[repo_slug, 'repo_slug'],
|
35
|
+
'commit',
|
36
|
+
[commented_to.hash, 'revision'],
|
37
|
+
'comments')
|
38
|
+
end
|
39
|
+
|
40
|
+
def base_path_of_pullrequest
|
41
|
+
build_path('/repositories',
|
42
|
+
[repo_owner, 'repo_owner'],
|
43
|
+
[repo_slug, 'repo_slug'],
|
44
|
+
'pullrequests',
|
45
|
+
[commented_to.id, 'pull_request_id'],
|
46
|
+
'comments')
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tinybucket
|
4
|
+
module Api
|
5
|
+
module Helper
|
6
|
+
module CommitsHelper
|
7
|
+
include ::Tinybucket::Api::Helper::ApiHelper
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def path_to_list
|
12
|
+
build_path(base_path, 'commits')
|
13
|
+
end
|
14
|
+
|
15
|
+
def path_to_find(revision)
|
16
|
+
build_path(base_path,
|
17
|
+
'commit',
|
18
|
+
[revision, 'revision'])
|
19
|
+
end
|
20
|
+
|
21
|
+
def path_to_branch(branch)
|
22
|
+
build_path(base_path,
|
23
|
+
'commits',
|
24
|
+
[branch, 'branch'])
|
25
|
+
end
|
26
|
+
|
27
|
+
def path_to_approve(revision)
|
28
|
+
build_path(base_path,
|
29
|
+
'commit',
|
30
|
+
[revision, 'revision'],
|
31
|
+
'approve')
|
32
|
+
end
|
33
|
+
|
34
|
+
def base_path
|
35
|
+
build_path('/repositories',
|
36
|
+
[repo_owner, 'repo_owner'],
|
37
|
+
[repo_slug, 'repo_slug'])
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tinybucket
|
4
|
+
module Api
|
5
|
+
module Helper
|
6
|
+
module DiffHelper
|
7
|
+
include ::Tinybucket::Api::Helper::ApiHelper
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def path_to_find(spec)
|
12
|
+
build_path(base_path,
|
13
|
+
'diff',
|
14
|
+
[spec, 'spec'])
|
15
|
+
end
|
16
|
+
|
17
|
+
def path_to_patch(spec)
|
18
|
+
build_path(base_path,
|
19
|
+
'patch',
|
20
|
+
[spec, 'spec'])
|
21
|
+
end
|
22
|
+
|
23
|
+
def base_path
|
24
|
+
build_path('/repositories',
|
25
|
+
[repo_owner, 'repo_owner'],
|
26
|
+
[repo_slug, 'repo_slug'])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|