gitlab-akerl 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/.prospectus +11 -0
- data/.travis.yml +8 -0
- data/CHANGELOG.md +229 -0
- data/CONTRIBUTING.md +195 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +24 -0
- data/README.md +192 -0
- data/Rakefile +9 -0
- data/bin/console +10 -0
- data/bin/setup +6 -0
- data/exe/gitlab +7 -0
- data/gitlab-akerl.gemspec +31 -0
- data/lib/gitlab.rb +45 -0
- data/lib/gitlab/api.rb +19 -0
- data/lib/gitlab/cli.rb +89 -0
- data/lib/gitlab/cli_helpers.rb +241 -0
- data/lib/gitlab/client.rb +48 -0
- data/lib/gitlab/client/branches.rb +91 -0
- data/lib/gitlab/client/build_triggers.rb +51 -0
- data/lib/gitlab/client/build_variables.rb +66 -0
- data/lib/gitlab/client/builds.rb +106 -0
- data/lib/gitlab/client/commits.rb +121 -0
- data/lib/gitlab/client/groups.rb +144 -0
- data/lib/gitlab/client/issues.rb +113 -0
- data/lib/gitlab/client/labels.rb +57 -0
- data/lib/gitlab/client/merge_requests.rb +168 -0
- data/lib/gitlab/client/milestones.rb +78 -0
- data/lib/gitlab/client/namespaces.rb +20 -0
- data/lib/gitlab/client/notes.rb +161 -0
- data/lib/gitlab/client/pipelines.rb +68 -0
- data/lib/gitlab/client/projects.rb +471 -0
- data/lib/gitlab/client/repositories.rb +78 -0
- data/lib/gitlab/client/repository_files.rb +88 -0
- data/lib/gitlab/client/runners.rb +115 -0
- data/lib/gitlab/client/services.rb +50 -0
- data/lib/gitlab/client/snippets.rb +91 -0
- data/lib/gitlab/client/system_hooks.rb +59 -0
- data/lib/gitlab/client/tags.rb +96 -0
- data/lib/gitlab/client/users.rb +250 -0
- data/lib/gitlab/configuration.rb +55 -0
- data/lib/gitlab/error.rb +85 -0
- data/lib/gitlab/file_response.rb +46 -0
- data/lib/gitlab/help.rb +95 -0
- data/lib/gitlab/objectified_hash.rb +34 -0
- data/lib/gitlab/page_links.rb +33 -0
- data/lib/gitlab/paginated_response.rb +97 -0
- data/lib/gitlab/request.rb +117 -0
- data/lib/gitlab/shell.rb +84 -0
- data/lib/gitlab/shell_history.rb +59 -0
- data/lib/gitlab/version.rb +3 -0
- data/spec/fixtures/branch.json +1 -0
- data/spec/fixtures/branch_delete.json +3 -0
- data/spec/fixtures/branches.json +1 -0
- data/spec/fixtures/build.json +38 -0
- data/spec/fixtures/build_artifacts.json +0 -0
- data/spec/fixtures/build_cancel.json +24 -0
- data/spec/fixtures/build_erase.json +24 -0
- data/spec/fixtures/build_retry.json +24 -0
- data/spec/fixtures/builds.json +78 -0
- data/spec/fixtures/builds_commits.json +64 -0
- data/spec/fixtures/compare_merge_request_diff.json +31 -0
- data/spec/fixtures/error_already_exists.json +1 -0
- data/spec/fixtures/error_project_not_found.json +1 -0
- data/spec/fixtures/get_repository_file.json +1 -0
- data/spec/fixtures/git_hook.json +1 -0
- data/spec/fixtures/group.json +60 -0
- data/spec/fixtures/group_create.json +1 -0
- data/spec/fixtures/group_create_with_description.json +1 -0
- data/spec/fixtures/group_delete.json +1 -0
- data/spec/fixtures/group_member.json +1 -0
- data/spec/fixtures/group_member_delete.json +1 -0
- data/spec/fixtures/group_member_edit.json +1 -0
- data/spec/fixtures/group_members.json +1 -0
- data/spec/fixtures/group_projects.json +44 -0
- data/spec/fixtures/group_search.json +2 -0
- data/spec/fixtures/groups.json +2 -0
- data/spec/fixtures/issue.json +1 -0
- data/spec/fixtures/issues.json +1 -0
- data/spec/fixtures/key.json +1 -0
- data/spec/fixtures/keys.json +1 -0
- data/spec/fixtures/label.json +1 -0
- data/spec/fixtures/labels.json +1 -0
- data/spec/fixtures/merge_request.json +1 -0
- data/spec/fixtures/merge_request_changes.json +1 -0
- data/spec/fixtures/merge_request_comment.json +1 -0
- data/spec/fixtures/merge_request_comments.json +1 -0
- data/spec/fixtures/merge_request_commits.json +1 -0
- data/spec/fixtures/merge_requests.json +1 -0
- data/spec/fixtures/milestone.json +1 -0
- data/spec/fixtures/milestone_issues.json +1 -0
- data/spec/fixtures/milestones.json +1 -0
- data/spec/fixtures/namespaces.json +1 -0
- data/spec/fixtures/note.json +1 -0
- data/spec/fixtures/notes.json +1 -0
- data/spec/fixtures/pipeline.json +23 -0
- data/spec/fixtures/pipeline_cancel.json +23 -0
- data/spec/fixtures/pipeline_create.json +23 -0
- data/spec/fixtures/pipeline_retry.json +23 -0
- data/spec/fixtures/pipelines.json +48 -0
- data/spec/fixtures/project.json +1 -0
- data/spec/fixtures/project_commit.json +13 -0
- data/spec/fixtures/project_commit_comment.json +1 -0
- data/spec/fixtures/project_commit_comments.json +1 -0
- data/spec/fixtures/project_commit_diff.json +10 -0
- data/spec/fixtures/project_commit_status.json +42 -0
- data/spec/fixtures/project_commits.json +1 -0
- data/spec/fixtures/project_edit.json +21 -0
- data/spec/fixtures/project_events.json +1 -0
- data/spec/fixtures/project_for_user.json +1 -0
- data/spec/fixtures/project_fork.json +50 -0
- data/spec/fixtures/project_fork_link.json +1 -0
- data/spec/fixtures/project_forked_for_user.json +50 -0
- data/spec/fixtures/project_hook.json +1 -0
- data/spec/fixtures/project_hooks.json +1 -0
- data/spec/fixtures/project_issues.json +1 -0
- data/spec/fixtures/project_key.json +6 -0
- data/spec/fixtures/project_keys.json +6 -0
- data/spec/fixtures/project_runner_enable.json +7 -0
- data/spec/fixtures/project_runners.json +16 -0
- data/spec/fixtures/project_search.json +1 -0
- data/spec/fixtures/project_star.json +44 -0
- data/spec/fixtures/project_tag_annotated.json +1 -0
- data/spec/fixtures/project_tag_lightweight.json +1 -0
- data/spec/fixtures/project_tags.json +1 -0
- data/spec/fixtures/project_unstar.json +44 -0
- data/spec/fixtures/project_update_commit_status.json +20 -0
- data/spec/fixtures/projects.json +1 -0
- data/spec/fixtures/raw_file.json +2 -0
- data/spec/fixtures/release_create.json +1 -0
- data/spec/fixtures/release_update.json +1 -0
- data/spec/fixtures/repository_file.json +1 -0
- data/spec/fixtures/runner.json +26 -0
- data/spec/fixtures/runner_delete.json +7 -0
- data/spec/fixtures/runner_edit.json +26 -0
- data/spec/fixtures/runners.json +16 -0
- data/spec/fixtures/runners_all.json +30 -0
- data/spec/fixtures/service.json +1 -0
- data/spec/fixtures/session.json +1 -0
- data/spec/fixtures/shell_history.json +2 -0
- data/spec/fixtures/snippet.json +1 -0
- data/spec/fixtures/snippet_content.json +3 -0
- data/spec/fixtures/snippets.json +1 -0
- data/spec/fixtures/system_hook.json +1 -0
- data/spec/fixtures/system_hooks.json +1 -0
- data/spec/fixtures/tag.json +1 -0
- data/spec/fixtures/tag_create.json +1 -0
- data/spec/fixtures/tag_create_with_description.json +1 -0
- data/spec/fixtures/tag_delete.json +1 -0
- data/spec/fixtures/tags.json +1 -0
- data/spec/fixtures/team_member.json +1 -0
- data/spec/fixtures/team_members.json +1 -0
- data/spec/fixtures/tree.json +1 -0
- data/spec/fixtures/trigger.json +7 -0
- data/spec/fixtures/triggers.json +16 -0
- data/spec/fixtures/user.json +1 -0
- data/spec/fixtures/user_block_unblock.json +1 -0
- data/spec/fixtures/user_email.json +1 -0
- data/spec/fixtures/user_emails.json +1 -0
- data/spec/fixtures/user_search.json +1 -0
- data/spec/fixtures/users.json +1 -0
- data/spec/fixtures/variable.json +4 -0
- data/spec/fixtures/variables.json +10 -0
- data/spec/gitlab/cli_helpers_spec.rb +57 -0
- data/spec/gitlab/cli_spec.rb +110 -0
- data/spec/gitlab/client/branches_spec.rb +99 -0
- data/spec/gitlab/client/build_triggers_spec.rb +67 -0
- data/spec/gitlab/client/build_variables_spec.rb +86 -0
- data/spec/gitlab/client/builds_spec.rb +148 -0
- data/spec/gitlab/client/client_spec.rb +11 -0
- data/spec/gitlab/client/commits_spec.rb +137 -0
- data/spec/gitlab/client/groups_spec.rb +197 -0
- data/spec/gitlab/client/issues_spec.rb +138 -0
- data/spec/gitlab/client/labels_spec.rb +68 -0
- data/spec/gitlab/client/merge_requests_spec.rb +177 -0
- data/spec/gitlab/client/milestones_spec.rb +82 -0
- data/spec/gitlab/client/namespaces_spec.rb +22 -0
- data/spec/gitlab/client/notes_spec.rb +205 -0
- data/spec/gitlab/client/pipelines_spec.rb +95 -0
- data/spec/gitlab/client/projects_spec.rb +603 -0
- data/spec/gitlab/client/repositories_spec.rb +109 -0
- data/spec/gitlab/client/repository_files_spec.rb +62 -0
- data/spec/gitlab/client/runners_spec.rb +185 -0
- data/spec/gitlab/client/services_spec.rb +55 -0
- data/spec/gitlab/client/snippets_spec.rb +100 -0
- data/spec/gitlab/client/system_hooks_spec.rb +69 -0
- data/spec/gitlab/client/tags_spec.rb +109 -0
- data/spec/gitlab/client/users_spec.rb +418 -0
- data/spec/gitlab/error_spec.rb +45 -0
- data/spec/gitlab/file_response_spec.rb +33 -0
- data/spec/gitlab/help_spec.rb +46 -0
- data/spec/gitlab/objectified_hash_spec.rb +48 -0
- data/spec/gitlab/page_links_spec.rb +16 -0
- data/spec/gitlab/paginated_response_spec.rb +60 -0
- data/spec/gitlab/request_spec.rb +73 -0
- data/spec/gitlab/shell_history_spec.rb +53 -0
- data/spec/gitlab/shell_spec.rb +80 -0
- data/spec/gitlab_spec.rb +97 -0
- data/spec/spec_helper.rb +74 -0
- metadata +476 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
module Gitlab
|
2
|
+
# Wrapper class of file response.
|
3
|
+
class FileResponse
|
4
|
+
HEADER_CONTENT_DISPOSITION = 'Content-Disposition'.freeze
|
5
|
+
|
6
|
+
attr_reader :filename
|
7
|
+
|
8
|
+
def initialize(file)
|
9
|
+
@file = file
|
10
|
+
end
|
11
|
+
|
12
|
+
# @return [bool] Always false
|
13
|
+
def empty?
|
14
|
+
false
|
15
|
+
end
|
16
|
+
|
17
|
+
# @return [Hash] A hash consisting of filename and io object
|
18
|
+
def to_hash
|
19
|
+
{ filename: @filename, data: @file }
|
20
|
+
end
|
21
|
+
alias_method :to_h, :to_hash
|
22
|
+
|
23
|
+
# @return [String] Formatted string with the class name, object id and filename.
|
24
|
+
def inspect
|
25
|
+
"#<#{self.class}:#{object_id} {filename: #{filename.inspect}}>"
|
26
|
+
end
|
27
|
+
|
28
|
+
def method_missing(name, *args, &block)
|
29
|
+
if @file.respond_to?(name)
|
30
|
+
@file.send(name, *args, &block)
|
31
|
+
else
|
32
|
+
super
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def respond_to_missing?(method_name, include_private = false)
|
37
|
+
super || @file.respond_to?(method_name, include_private)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Parse filename from the 'Content Disposition' header.
|
41
|
+
def parse_headers!(headers)
|
42
|
+
@filename = headers[HEADER_CONTENT_DISPOSITION].split("filename=")[1]
|
43
|
+
@filename = @filename[1...-1] if @filename[0] == '"' # Unquote filenames
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/gitlab/help.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'gitlab'
|
2
|
+
require 'gitlab/cli_helpers'
|
3
|
+
|
4
|
+
module Gitlab::Help
|
5
|
+
extend Gitlab::CLI::Helpers
|
6
|
+
|
7
|
+
class << self
|
8
|
+
# Returns the (modified) help from the 'ri' command or returns an error.
|
9
|
+
#
|
10
|
+
# @return [String]
|
11
|
+
def get_help(cmd)
|
12
|
+
cmd_namespace = namespace cmd
|
13
|
+
|
14
|
+
if cmd_namespace
|
15
|
+
ri_output = `#{ri_cmd} -T #{cmd_namespace} 2>&1`.chomp
|
16
|
+
|
17
|
+
if $CHILD_STATUS == 0
|
18
|
+
change_help_output! cmd, ri_output
|
19
|
+
yield ri_output if block_given?
|
20
|
+
|
21
|
+
ri_output
|
22
|
+
else
|
23
|
+
"Ri docs not found for #{cmd}, please install the docs to use 'help'."
|
24
|
+
end
|
25
|
+
else
|
26
|
+
"Unknown command: #{cmd}."
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Finds the location of 'ri' on a system.
|
31
|
+
#
|
32
|
+
# @return [String]
|
33
|
+
def ri_cmd
|
34
|
+
which_ri = `which ri`.chomp
|
35
|
+
if which_ri.empty?
|
36
|
+
fail "'ri' tool not found in $PATH. Please install it to use the help."
|
37
|
+
end
|
38
|
+
|
39
|
+
which_ri
|
40
|
+
end
|
41
|
+
|
42
|
+
# A hash map that contains help topics (Branches, Groups, etc.)
|
43
|
+
# and a list of commands that are defined under a topic (create_branch,
|
44
|
+
# branches, protect_branch, etc.).
|
45
|
+
#
|
46
|
+
# @return [Hash<Array>]
|
47
|
+
def help_map
|
48
|
+
@help_map ||= begin
|
49
|
+
actions.each_with_object({}) do |action, hsh|
|
50
|
+
key = client.method(action).
|
51
|
+
owner.to_s.gsub(/Gitlab::(?:Client::)?/, '')
|
52
|
+
hsh[key] ||= []
|
53
|
+
hsh[key] << action.to_s
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Table with available commands.
|
59
|
+
#
|
60
|
+
# @return [Terminal::Table]
|
61
|
+
def actions_table(topic=nil)
|
62
|
+
rows = topic ? help_map[topic] : help_map.keys
|
63
|
+
table do |t|
|
64
|
+
t.title = topic || "Help Topics"
|
65
|
+
|
66
|
+
# add_row expects an array and we have strings hence the map.
|
67
|
+
rows.sort.map { |r| [r] }.each_with_index do |row, index|
|
68
|
+
t.add_row row
|
69
|
+
t.add_separator unless rows.size - 1 == index
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Returns full namespace of a command (e.g. Gitlab::Client::Branches.cmd)
|
75
|
+
def namespace(cmd)
|
76
|
+
method_owners.select { |method| method[:name] === cmd }.
|
77
|
+
map { |method| method[:owner] + '.' + method[:name] }.
|
78
|
+
shift
|
79
|
+
end
|
80
|
+
|
81
|
+
# Massage output from 'ri'.
|
82
|
+
def change_help_output!(cmd, output_str)
|
83
|
+
output_str.gsub!(/#{cmd}\((.*?)\)/m, cmd + ' \1')
|
84
|
+
output_str.gsub!(/\,[\s]*/, ' ')
|
85
|
+
|
86
|
+
# Ensure @option descriptions are on a single line
|
87
|
+
output_str.gsub!(/\n\[/, " \[")
|
88
|
+
output_str.gsub!(/\s(@)/, "\n@")
|
89
|
+
output_str.gsub!(/(\])\n(\:)/, '\1 \2')
|
90
|
+
output_str.gsub!(/(\:.*)(\n)(.*\.)/, '\1 \3')
|
91
|
+
output_str.gsub!(/\{(.+)\}/, '"{\1}"')
|
92
|
+
|
93
|
+
end
|
94
|
+
end # class << self
|
95
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Gitlab
|
2
|
+
# Converts hashes to the objects.
|
3
|
+
class ObjectifiedHash
|
4
|
+
# Creates a new ObjectifiedHash object.
|
5
|
+
def initialize(hash)
|
6
|
+
@hash = hash
|
7
|
+
@data = hash.inject({}) do |data, (key, value)|
|
8
|
+
value = ObjectifiedHash.new(value) if value.is_a? Hash
|
9
|
+
data[key.to_s] = value
|
10
|
+
data
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# @return [Hash] The original hash.
|
15
|
+
def to_hash
|
16
|
+
@hash
|
17
|
+
end
|
18
|
+
alias_method :to_h, :to_hash
|
19
|
+
|
20
|
+
# @return [String] Formatted string with the class name, object id and original hash.
|
21
|
+
def inspect
|
22
|
+
"#<#{self.class}:#{object_id} {hash: #{@hash.inspect}}"
|
23
|
+
end
|
24
|
+
|
25
|
+
# Delegate to ObjectifiedHash.
|
26
|
+
def method_missing(key)
|
27
|
+
@data.key?(key.to_s) ? @data[key.to_s] : nil
|
28
|
+
end
|
29
|
+
|
30
|
+
def respond_to_missing?(method_name, include_private = false)
|
31
|
+
@hash.keys.map(&:to_sym).include?(method_name.to_sym) || super
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Gitlab
|
2
|
+
# Parses link header.
|
3
|
+
#
|
4
|
+
# @private
|
5
|
+
class PageLinks
|
6
|
+
HEADER_LINK = 'Link'.freeze
|
7
|
+
DELIM_LINKS = ','.freeze
|
8
|
+
LINK_REGEX = /<([^>]+)>; rel=\"([^\"]+)\"/
|
9
|
+
METAS = %w(last next first prev)
|
10
|
+
|
11
|
+
attr_accessor(*METAS)
|
12
|
+
|
13
|
+
def initialize(headers)
|
14
|
+
link_header = headers[HEADER_LINK]
|
15
|
+
|
16
|
+
if link_header && link_header =~ /(next|first|last|prev)/
|
17
|
+
extract_links(link_header)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def extract_links(header)
|
24
|
+
header.split(DELIM_LINKS).each do |link|
|
25
|
+
LINK_REGEX.match(link.strip) do |match|
|
26
|
+
url, meta = match[1], match[2]
|
27
|
+
next if !url || !meta || METAS.index(meta).nil?
|
28
|
+
self.send("#{meta}=", url)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module Gitlab
|
2
|
+
# Wrapper class of paginated response.
|
3
|
+
class PaginatedResponse
|
4
|
+
attr_accessor :client
|
5
|
+
|
6
|
+
def initialize(array)
|
7
|
+
@array = array
|
8
|
+
end
|
9
|
+
|
10
|
+
def ==(other)
|
11
|
+
@array == other
|
12
|
+
end
|
13
|
+
|
14
|
+
def inspect
|
15
|
+
@array.inspect
|
16
|
+
end
|
17
|
+
|
18
|
+
def method_missing(name, *args, &block)
|
19
|
+
if @array.respond_to?(name)
|
20
|
+
@array.send(name, *args, &block)
|
21
|
+
else
|
22
|
+
super
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def respond_to_missing?(method_name, include_private = false)
|
27
|
+
super || @array.respond_to?(method_name, include_private)
|
28
|
+
end
|
29
|
+
|
30
|
+
def parse_headers!(headers)
|
31
|
+
@links = PageLinks.new headers
|
32
|
+
end
|
33
|
+
|
34
|
+
def each_page
|
35
|
+
current = self
|
36
|
+
yield current
|
37
|
+
while current.has_next_page?
|
38
|
+
current = current.next_page
|
39
|
+
yield current
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def auto_paginate
|
44
|
+
response = block_given? ? nil : []
|
45
|
+
each_page do |page|
|
46
|
+
if block_given?
|
47
|
+
page.each do |item|
|
48
|
+
yield item
|
49
|
+
end
|
50
|
+
else
|
51
|
+
response += page
|
52
|
+
end
|
53
|
+
end
|
54
|
+
response
|
55
|
+
end
|
56
|
+
|
57
|
+
def has_last_page?
|
58
|
+
!(@links.nil? || @links.last.nil?)
|
59
|
+
end
|
60
|
+
|
61
|
+
def last_page
|
62
|
+
return nil if @client.nil? || !has_last_page?
|
63
|
+
path = @links.last.sub(/#{@client.endpoint}/, '')
|
64
|
+
@client.get(path)
|
65
|
+
end
|
66
|
+
|
67
|
+
def has_first_page?
|
68
|
+
!(@links.nil? || @links.first.nil?)
|
69
|
+
end
|
70
|
+
|
71
|
+
def first_page
|
72
|
+
return nil if @client.nil? || !has_first_page?
|
73
|
+
path = @links.first.sub(/#{@client.endpoint}/, '')
|
74
|
+
@client.get(path)
|
75
|
+
end
|
76
|
+
|
77
|
+
def has_next_page?
|
78
|
+
!(@links.nil? || @links.next.nil?)
|
79
|
+
end
|
80
|
+
|
81
|
+
def next_page
|
82
|
+
return nil if @client.nil? || !has_next_page?
|
83
|
+
path = @links.next.sub(/#{@client.endpoint}/, '')
|
84
|
+
@client.get(path)
|
85
|
+
end
|
86
|
+
|
87
|
+
def has_prev_page?
|
88
|
+
!(@links.nil? || @links.prev.nil?)
|
89
|
+
end
|
90
|
+
|
91
|
+
def prev_page
|
92
|
+
return nil if @client.nil? || !has_prev_page?
|
93
|
+
path = @links.prev.sub(/#{@client.endpoint}/, '')
|
94
|
+
@client.get(path)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Gitlab
|
5
|
+
# @private
|
6
|
+
class Request
|
7
|
+
include HTTParty
|
8
|
+
format :json
|
9
|
+
headers 'Accept' => 'application/json'
|
10
|
+
parser proc { |body, _| parse(body) }
|
11
|
+
|
12
|
+
attr_accessor :private_token, :endpoint
|
13
|
+
|
14
|
+
# Converts the response body to an ObjectifiedHash.
|
15
|
+
def self.parse(body)
|
16
|
+
body = decode(body)
|
17
|
+
|
18
|
+
if body.is_a? Hash
|
19
|
+
ObjectifiedHash.new body
|
20
|
+
elsif body.is_a? Array
|
21
|
+
PaginatedResponse.new(body.collect! { |e| ObjectifiedHash.new(e) })
|
22
|
+
elsif body
|
23
|
+
true
|
24
|
+
elsif !body
|
25
|
+
false
|
26
|
+
elsif body.nil?
|
27
|
+
false
|
28
|
+
else
|
29
|
+
raise Error::Parsing.new "Couldn't parse a response body"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Decodes a JSON response into Ruby object.
|
34
|
+
def self.decode(response)
|
35
|
+
JSON.load response
|
36
|
+
rescue JSON::ParserError
|
37
|
+
raise Error::Parsing.new "The response is not a valid JSON"
|
38
|
+
end
|
39
|
+
|
40
|
+
def get(path, options={})
|
41
|
+
set_httparty_config(options)
|
42
|
+
set_authorization_header(options)
|
43
|
+
validate self.class.get(@endpoint + path, options)
|
44
|
+
end
|
45
|
+
|
46
|
+
def post(path, options={})
|
47
|
+
set_httparty_config(options)
|
48
|
+
set_authorization_header(options, path)
|
49
|
+
validate self.class.post(@endpoint + path, options)
|
50
|
+
end
|
51
|
+
|
52
|
+
def put(path, options={})
|
53
|
+
set_httparty_config(options)
|
54
|
+
set_authorization_header(options)
|
55
|
+
validate self.class.put(@endpoint + path, options)
|
56
|
+
end
|
57
|
+
|
58
|
+
def delete(path, options={})
|
59
|
+
set_httparty_config(options)
|
60
|
+
set_authorization_header(options)
|
61
|
+
validate self.class.delete(@endpoint + path, options)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Checks the response code for common errors.
|
65
|
+
# Returns parsed response for successful requests.
|
66
|
+
def validate(response)
|
67
|
+
error_klass = case response.code
|
68
|
+
when 400 then Error::BadRequest
|
69
|
+
when 401 then Error::Unauthorized
|
70
|
+
when 403 then Error::Forbidden
|
71
|
+
when 404 then Error::NotFound
|
72
|
+
when 405 then Error::MethodNotAllowed
|
73
|
+
when 409 then Error::Conflict
|
74
|
+
when 422 then Error::Unprocessable
|
75
|
+
when 500 then Error::InternalServerError
|
76
|
+
when 502 then Error::BadGateway
|
77
|
+
when 503 then Error::ServiceUnavailable
|
78
|
+
end
|
79
|
+
|
80
|
+
fail error_klass.new(response) if error_klass
|
81
|
+
|
82
|
+
parsed = response.parsed_response
|
83
|
+
parsed.client = self if parsed.respond_to?(:client=)
|
84
|
+
parsed.parse_headers!(response.headers) if parsed.respond_to?(:parse_headers!)
|
85
|
+
parsed
|
86
|
+
end
|
87
|
+
|
88
|
+
# Sets a base_uri and default_params for requests.
|
89
|
+
# @raise [Error::MissingCredentials] if endpoint not set.
|
90
|
+
def set_request_defaults(sudo=nil)
|
91
|
+
self.class.default_params sudo: sudo
|
92
|
+
raise Error::MissingCredentials.new("Please set an endpoint to API") unless @endpoint
|
93
|
+
self.class.default_params.delete(:sudo) if sudo.nil?
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
# Sets a PRIVATE-TOKEN or Authorization header for requests.
|
99
|
+
# @raise [Error::MissingCredentials] if private_token and auth_token are not set.
|
100
|
+
def set_authorization_header(options, path=nil)
|
101
|
+
unless path == '/session'
|
102
|
+
raise Error::MissingCredentials.new("Please provide a private_token or auth_token for user") unless @private_token
|
103
|
+
if @private_token.length <= 20
|
104
|
+
options[:headers] = { 'PRIVATE-TOKEN' => @private_token }
|
105
|
+
else
|
106
|
+
options[:headers] = { 'Authorization' => "Bearer #{@private_token}" }
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# Set HTTParty configuration
|
112
|
+
# @see https://github.com/jnunemaker/httparty
|
113
|
+
def set_httparty_config(options)
|
114
|
+
options.merge!(httparty) if httparty
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
data/lib/gitlab/shell.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'gitlab'
|
2
|
+
require 'gitlab/help'
|
3
|
+
require 'gitlab/cli_helpers'
|
4
|
+
require 'gitlab/shell_history'
|
5
|
+
require 'readline'
|
6
|
+
require 'shellwords'
|
7
|
+
|
8
|
+
class Gitlab::Shell
|
9
|
+
extend Gitlab::CLI::Helpers
|
10
|
+
|
11
|
+
class << self
|
12
|
+
attr_reader :arguments, :command
|
13
|
+
|
14
|
+
def start
|
15
|
+
trap('INT') { quit_shell } # capture ctrl-c
|
16
|
+
setup
|
17
|
+
|
18
|
+
while buffer = Readline.readline('gitlab> ')
|
19
|
+
begin
|
20
|
+
parse_input buffer
|
21
|
+
|
22
|
+
@arguments.map! { |arg| symbolize_keys(yaml_load(arg)) }
|
23
|
+
|
24
|
+
case buffer
|
25
|
+
when nil, ''
|
26
|
+
next
|
27
|
+
when 'exit'
|
28
|
+
quit_shell
|
29
|
+
when /^\bhelp\b+/
|
30
|
+
puts help(arguments[0]) { |out| out.gsub!(/Gitlab\./, 'gitlab> ') }
|
31
|
+
else
|
32
|
+
history << buffer
|
33
|
+
|
34
|
+
data = execute command, arguments
|
35
|
+
output_table command, arguments, data
|
36
|
+
end
|
37
|
+
rescue => e
|
38
|
+
puts e.message
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
quit_shell # save history if user presses ctrl-d
|
43
|
+
end
|
44
|
+
|
45
|
+
def parse_input(buffer)
|
46
|
+
buf = Shellwords.shellwords(buffer)
|
47
|
+
|
48
|
+
@command = buf.shift
|
49
|
+
@arguments = buf.count > 0 ? buf : []
|
50
|
+
end
|
51
|
+
|
52
|
+
def setup
|
53
|
+
history.load
|
54
|
+
|
55
|
+
Readline.completion_proc = completion
|
56
|
+
Readline.completion_append_character = ' '
|
57
|
+
end
|
58
|
+
|
59
|
+
# Gets called when user hits TAB key to do completion
|
60
|
+
def completion
|
61
|
+
proc { |str| actions.map(&:to_s).grep(/^#{Regexp.escape(str)}/) }
|
62
|
+
end
|
63
|
+
|
64
|
+
# Execute a given command with arguements
|
65
|
+
def execute(cmd=command, args=arguments)
|
66
|
+
if actions.include?(cmd.to_sym)
|
67
|
+
confirm_command(cmd)
|
68
|
+
gitlab_helper(cmd, args)
|
69
|
+
else
|
70
|
+
fail "Unknown command: #{cmd}. " \
|
71
|
+
"See the 'help' for a list of valid commands."
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def quit_shell
|
76
|
+
history.save
|
77
|
+
exit
|
78
|
+
end
|
79
|
+
|
80
|
+
def history
|
81
|
+
@history ||= History.new
|
82
|
+
end
|
83
|
+
end # class << self
|
84
|
+
end
|