gitlab 4.2.0 → 4.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (271) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +4 -2
  3. data/LICENSE.txt +1 -1
  4. data/README.md +96 -25
  5. data/exe/gitlab +5 -1
  6. data/lib/gitlab/api.rb +8 -3
  7. data/lib/gitlab/cli.rb +15 -15
  8. data/lib/gitlab/cli_helpers.rb +63 -61
  9. data/lib/gitlab/client/access_requests.rb +103 -0
  10. data/lib/gitlab/client/application_settings.rb +172 -0
  11. data/lib/gitlab/client/avatar.rb +21 -0
  12. data/lib/gitlab/client/award_emojis.rb +5 -3
  13. data/lib/gitlab/client/boards.rb +62 -4
  14. data/lib/gitlab/client/branches.rb +53 -14
  15. data/lib/gitlab/client/broadcast_messages.rb +75 -0
  16. data/lib/gitlab/client/build_variables.rb +78 -9
  17. data/lib/gitlab/client/builds.rb +13 -11
  18. data/lib/gitlab/client/commits.rb +89 -19
  19. data/lib/gitlab/client/container_registry.rb +85 -0
  20. data/lib/gitlab/client/deployments.rb +34 -0
  21. data/lib/gitlab/client/environments.rb +5 -3
  22. data/lib/gitlab/client/epic_issues.rb +23 -0
  23. data/lib/gitlab/client/epics.rb +73 -0
  24. data/lib/gitlab/client/events.rb +60 -0
  25. data/lib/gitlab/client/features.rb +48 -0
  26. data/lib/gitlab/client/group_badges.rb +88 -0
  27. data/lib/gitlab/client/group_boards.rb +141 -0
  28. data/lib/gitlab/client/group_labels.rb +88 -0
  29. data/lib/gitlab/client/group_milestones.rb +94 -0
  30. data/lib/gitlab/client/groups.rb +197 -17
  31. data/lib/gitlab/client/issue_links.rb +48 -0
  32. data/lib/gitlab/client/issues.rb +98 -4
  33. data/lib/gitlab/client/jobs.rb +96 -8
  34. data/lib/gitlab/client/keys.rb +13 -0
  35. data/lib/gitlab/client/labels.rb +7 -5
  36. data/lib/gitlab/client/lint.rb +19 -0
  37. data/lib/gitlab/client/markdown.rb +23 -0
  38. data/lib/gitlab/client/merge_request_approvals.rb +265 -0
  39. data/lib/gitlab/client/merge_requests.rb +237 -9
  40. data/lib/gitlab/client/milestones.rb +19 -5
  41. data/lib/gitlab/client/namespaces.rb +4 -2
  42. data/lib/gitlab/client/notes.rb +58 -12
  43. data/lib/gitlab/client/pipeline_schedules.rb +147 -0
  44. data/lib/gitlab/client/pipeline_triggers.rb +12 -10
  45. data/lib/gitlab/client/pipelines.rb +40 -3
  46. data/lib/gitlab/client/project_badges.rb +85 -0
  47. data/lib/gitlab/client/project_clusters.rb +83 -0
  48. data/lib/gitlab/client/project_release_links.rb +76 -0
  49. data/lib/gitlab/client/project_releases.rb +79 -0
  50. data/lib/gitlab/client/projects.rb +280 -47
  51. data/lib/gitlab/client/protected_tags.rb +59 -0
  52. data/lib/gitlab/client/remote_mirrors.rb +51 -0
  53. data/lib/gitlab/client/repositories.rb +60 -6
  54. data/lib/gitlab/client/repository_files.rb +23 -5
  55. data/lib/gitlab/client/repository_submodules.rb +27 -0
  56. data/lib/gitlab/client/resource_label_events.rb +82 -0
  57. data/lib/gitlab/client/resource_state_events.rb +57 -0
  58. data/lib/gitlab/client/runners.rb +111 -15
  59. data/lib/gitlab/client/search.rb +66 -0
  60. data/lib/gitlab/client/services.rb +4 -1
  61. data/lib/gitlab/client/sidekiq.rb +39 -0
  62. data/lib/gitlab/client/snippets.rb +8 -4
  63. data/lib/gitlab/client/system_hooks.rb +9 -7
  64. data/lib/gitlab/client/tags.rb +15 -14
  65. data/lib/gitlab/client/templates.rb +100 -0
  66. data/lib/gitlab/client/todos.rb +7 -5
  67. data/lib/gitlab/client/user_snippets.rb +114 -0
  68. data/lib/gitlab/client/users.rb +166 -30
  69. data/lib/gitlab/client/versions.rb +18 -0
  70. data/lib/gitlab/client/wikis.rb +79 -0
  71. data/lib/gitlab/client.rb +49 -12
  72. data/lib/gitlab/configuration.rb +8 -6
  73. data/lib/gitlab/error.rb +74 -5
  74. data/lib/gitlab/file_response.rb +5 -3
  75. data/lib/gitlab/help.rb +19 -20
  76. data/lib/gitlab/objectified_hash.rb +27 -10
  77. data/lib/gitlab/page_links.rb +11 -9
  78. data/lib/gitlab/paginated_response.rb +37 -24
  79. data/lib/gitlab/request.rb +42 -53
  80. data/lib/gitlab/shell.rb +11 -12
  81. data/lib/gitlab/shell_history.rb +11 -13
  82. data/lib/gitlab/version.rb +3 -1
  83. data/lib/gitlab.rb +19 -8
  84. metadata +50 -395
  85. data/.gitignore +0 -22
  86. data/.travis.yml +0 -8
  87. data/CONTRIBUTING.md +0 -195
  88. data/Gemfile +0 -4
  89. data/Rakefile +0 -9
  90. data/bin/console +0 -10
  91. data/bin/setup +0 -6
  92. data/gitlab.gemspec +0 -31
  93. data/spec/fixtures/board_list.json +0 -1
  94. data/spec/fixtures/board_lists.json +0 -1
  95. data/spec/fixtures/boards.json +0 -1
  96. data/spec/fixtures/branch.json +0 -1
  97. data/spec/fixtures/branch_delete.json +0 -3
  98. data/spec/fixtures/branches.json +0 -1
  99. data/spec/fixtures/build.json +0 -38
  100. data/spec/fixtures/build_artifacts.json +0 -0
  101. data/spec/fixtures/build_cancel.json +0 -24
  102. data/spec/fixtures/build_erase.json +0 -24
  103. data/spec/fixtures/build_retry.json +0 -24
  104. data/spec/fixtures/builds.json +0 -78
  105. data/spec/fixtures/builds_commits.json +0 -64
  106. data/spec/fixtures/compare_merge_request_diff.json +0 -31
  107. data/spec/fixtures/empty.json +0 -0
  108. data/spec/fixtures/environment.json +0 -6
  109. data/spec/fixtures/environments.json +0 -14
  110. data/spec/fixtures/error_already_exists.json +0 -1
  111. data/spec/fixtures/error_project_not_found.json +0 -1
  112. data/spec/fixtures/get_repository_file.json +0 -1
  113. data/spec/fixtures/group.json +0 -60
  114. data/spec/fixtures/group_create.json +0 -1
  115. data/spec/fixtures/group_create_with_description.json +0 -1
  116. data/spec/fixtures/group_delete.json +0 -1
  117. data/spec/fixtures/group_member.json +0 -1
  118. data/spec/fixtures/group_member_delete.json +0 -1
  119. data/spec/fixtures/group_member_edit.json +0 -1
  120. data/spec/fixtures/group_members.json +0 -1
  121. data/spec/fixtures/group_projects.json +0 -44
  122. data/spec/fixtures/group_search.json +0 -2
  123. data/spec/fixtures/groups.json +0 -2
  124. data/spec/fixtures/issue.json +0 -1
  125. data/spec/fixtures/issue_award_emoji.json +0 -16
  126. data/spec/fixtures/issue_award_emojis.json +0 -34
  127. data/spec/fixtures/issues.json +0 -1
  128. data/spec/fixtures/job.json +0 -43
  129. data/spec/fixtures/job_trace.json +0 -1
  130. data/spec/fixtures/jobs.json +0 -91
  131. data/spec/fixtures/key.json +0 -1
  132. data/spec/fixtures/keys.json +0 -1
  133. data/spec/fixtures/label.json +0 -1
  134. data/spec/fixtures/label_unsubscribe.json +0 -1
  135. data/spec/fixtures/labels.json +0 -1
  136. data/spec/fixtures/merge_request.json +0 -1
  137. data/spec/fixtures/merge_request_award_emoji.json +0 -16
  138. data/spec/fixtures/merge_request_award_emojis.json +0 -34
  139. data/spec/fixtures/merge_request_changes.json +0 -1
  140. data/spec/fixtures/merge_request_closes_issues.json +0 -1
  141. data/spec/fixtures/merge_request_comment.json +0 -1
  142. data/spec/fixtures/merge_request_comments.json +0 -1
  143. data/spec/fixtures/merge_request_commits.json +0 -1
  144. data/spec/fixtures/merge_requests.json +0 -1
  145. data/spec/fixtures/milestone.json +0 -1
  146. data/spec/fixtures/milestone_issues.json +0 -1
  147. data/spec/fixtures/milestone_merge_requests.json +0 -1
  148. data/spec/fixtures/milestones.json +0 -1
  149. data/spec/fixtures/namespaces.json +0 -1
  150. data/spec/fixtures/note.json +0 -1
  151. data/spec/fixtures/note_award_emoji.json +0 -16
  152. data/spec/fixtures/note_award_emojis.json +0 -18
  153. data/spec/fixtures/notes.json +0 -1
  154. data/spec/fixtures/pipeline.json +0 -23
  155. data/spec/fixtures/pipeline_cancel.json +0 -23
  156. data/spec/fixtures/pipeline_create.json +0 -23
  157. data/spec/fixtures/pipeline_jobs.json +0 -91
  158. data/spec/fixtures/pipeline_retry.json +0 -23
  159. data/spec/fixtures/pipelines.json +0 -48
  160. data/spec/fixtures/project.json +0 -1
  161. data/spec/fixtures/project_commit.json +0 -13
  162. data/spec/fixtures/project_commit_comment.json +0 -1
  163. data/spec/fixtures/project_commit_comments.json +0 -1
  164. data/spec/fixtures/project_commit_create.json +0 -22
  165. data/spec/fixtures/project_commit_diff.json +0 -10
  166. data/spec/fixtures/project_commit_status.json +0 -42
  167. data/spec/fixtures/project_commits.json +0 -1
  168. data/spec/fixtures/project_edit.json +0 -21
  169. data/spec/fixtures/project_events.json +0 -1
  170. data/spec/fixtures/project_for_user.json +0 -1
  171. data/spec/fixtures/project_fork.json +0 -50
  172. data/spec/fixtures/project_fork_link.json +0 -1
  173. data/spec/fixtures/project_forked_for_user.json +0 -50
  174. data/spec/fixtures/project_hook.json +0 -1
  175. data/spec/fixtures/project_hooks.json +0 -1
  176. data/spec/fixtures/project_issues.json +0 -1
  177. data/spec/fixtures/project_key.json +0 -6
  178. data/spec/fixtures/project_keys.json +0 -6
  179. data/spec/fixtures/project_runner_enable.json +0 -7
  180. data/spec/fixtures/project_runners.json +0 -16
  181. data/spec/fixtures/project_search.json +0 -1
  182. data/spec/fixtures/project_star.json +0 -44
  183. data/spec/fixtures/project_tag_annotated.json +0 -1
  184. data/spec/fixtures/project_tag_lightweight.json +0 -1
  185. data/spec/fixtures/project_tags.json +0 -1
  186. data/spec/fixtures/project_unstar.json +0 -44
  187. data/spec/fixtures/project_update_commit_status.json +0 -20
  188. data/spec/fixtures/projects.json +0 -1
  189. data/spec/fixtures/push_rule.json +0 -1
  190. data/spec/fixtures/raw_file.json +0 -2
  191. data/spec/fixtures/release_create.json +0 -1
  192. data/spec/fixtures/release_update.json +0 -1
  193. data/spec/fixtures/repository_file.json +0 -1
  194. data/spec/fixtures/run_trigger.json +0 -1
  195. data/spec/fixtures/runner.json +0 -26
  196. data/spec/fixtures/runner_delete.json +0 -7
  197. data/spec/fixtures/runner_edit.json +0 -26
  198. data/spec/fixtures/runners.json +0 -16
  199. data/spec/fixtures/runners_all.json +0 -30
  200. data/spec/fixtures/service.json +0 -1
  201. data/spec/fixtures/session.json +0 -1
  202. data/spec/fixtures/shell_history.json +0 -2
  203. data/spec/fixtures/snippet.json +0 -1
  204. data/spec/fixtures/snippet_award_emoji.json +0 -16
  205. data/spec/fixtures/snippet_award_emojis.json +0 -34
  206. data/spec/fixtures/snippet_content.json +0 -3
  207. data/spec/fixtures/snippets.json +0 -1
  208. data/spec/fixtures/system_hook.json +0 -1
  209. data/spec/fixtures/system_hooks.json +0 -1
  210. data/spec/fixtures/tag.json +0 -1
  211. data/spec/fixtures/tag_create.json +0 -1
  212. data/spec/fixtures/tag_create_with_description.json +0 -1
  213. data/spec/fixtures/tag_delete.json +0 -1
  214. data/spec/fixtures/tags.json +0 -1
  215. data/spec/fixtures/team_member.json +0 -1
  216. data/spec/fixtures/team_members.json +0 -1
  217. data/spec/fixtures/todo.json +0 -73
  218. data/spec/fixtures/todos.json +0 -148
  219. data/spec/fixtures/tree.json +0 -1
  220. data/spec/fixtures/trigger.json +0 -10
  221. data/spec/fixtures/triggers.json +0 -12
  222. data/spec/fixtures/user.json +0 -1
  223. data/spec/fixtures/user_block_unblock.json +0 -1
  224. data/spec/fixtures/user_email.json +0 -1
  225. data/spec/fixtures/user_emails.json +0 -1
  226. data/spec/fixtures/user_search.json +0 -1
  227. data/spec/fixtures/users.json +0 -1
  228. data/spec/fixtures/variable.json +0 -4
  229. data/spec/fixtures/variables.json +0 -10
  230. data/spec/gitlab/cli_helpers_spec.rb +0 -57
  231. data/spec/gitlab/cli_spec.rb +0 -119
  232. data/spec/gitlab/client/award_emojis_spec.rb +0 -391
  233. data/spec/gitlab/client/boards_spec.rb +0 -94
  234. data/spec/gitlab/client/branches_spec.rb +0 -116
  235. data/spec/gitlab/client/build_variables_spec.rb +0 -86
  236. data/spec/gitlab/client/builds_spec.rb +0 -148
  237. data/spec/gitlab/client/client_spec.rb +0 -11
  238. data/spec/gitlab/client/commits_spec.rb +0 -168
  239. data/spec/gitlab/client/environments_spec.rb +0 -132
  240. data/spec/gitlab/client/groups_spec.rb +0 -195
  241. data/spec/gitlab/client/issues_spec.rb +0 -186
  242. data/spec/gitlab/client/jobs_spec.rb +0 -135
  243. data/spec/gitlab/client/keys_spec.rb +0 -19
  244. data/spec/gitlab/client/labels_spec.rb +0 -100
  245. data/spec/gitlab/client/merge_requests_spec.rb +0 -224
  246. data/spec/gitlab/client/milestones_spec.rb +0 -98
  247. data/spec/gitlab/client/namespaces_spec.rb +0 -22
  248. data/spec/gitlab/client/notes_spec.rb +0 -333
  249. data/spec/gitlab/client/pipeline_triggers_spec.rb +0 -157
  250. data/spec/gitlab/client/pipelines_spec.rb +0 -95
  251. data/spec/gitlab/client/projects_spec.rb +0 -613
  252. data/spec/gitlab/client/repositories_spec.rb +0 -94
  253. data/spec/gitlab/client/repository_files_spec.rb +0 -95
  254. data/spec/gitlab/client/runners_spec.rb +0 -185
  255. data/spec/gitlab/client/services_spec.rb +0 -55
  256. data/spec/gitlab/client/snippets_spec.rb +0 -100
  257. data/spec/gitlab/client/system_hooks_spec.rb +0 -69
  258. data/spec/gitlab/client/tags_spec.rb +0 -109
  259. data/spec/gitlab/client/todos_spec.rb +0 -45
  260. data/spec/gitlab/client/users_spec.rb +0 -418
  261. data/spec/gitlab/error_spec.rb +0 -45
  262. data/spec/gitlab/file_response_spec.rb +0 -33
  263. data/spec/gitlab/help_spec.rb +0 -46
  264. data/spec/gitlab/objectified_hash_spec.rb +0 -48
  265. data/spec/gitlab/page_links_spec.rb +0 -16
  266. data/spec/gitlab/paginated_response_spec.rb +0 -60
  267. data/spec/gitlab/request_spec.rb +0 -73
  268. data/spec/gitlab/shell_history_spec.rb +0 -53
  269. data/spec/gitlab/shell_spec.rb +0 -80
  270. data/spec/gitlab_spec.rb +0 -97
  271. data/spec/spec_helper.rb +0 -74
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Gitlab::Client
4
+ # Defines methods related to wikis.
5
+ # @see https://docs.gitlab.com/ce/api/wikis.html
6
+ module Wikis
7
+ # Get all wiki pages for a given project.
8
+ #
9
+ # @example
10
+ # Gitlab.wikis(3)
11
+ # Gitlab.wikis(3, {with_content: 'Some wiki content'})
12
+ #
13
+ # @param [Integer, String] project The ID or name of a project.
14
+ # @param [Hash] options A customizable set of options.
15
+ # @option options [String] with_content(optional) Include pages content
16
+ # @return [Array<Gitlab::ObjectifiedHash>]
17
+ def wikis(project, options = {})
18
+ get("/projects/#{url_encode project}/wikis", query: options)
19
+ end
20
+
21
+ # Get a wiki page for a given project.
22
+ #
23
+ # @example
24
+ # Gitlab.wiki(3, 'home')
25
+ #
26
+ # @param [Integer, String] project The ID or name of a project.
27
+ # @param [String] slug The slug (a unique string) of the wiki page
28
+ # @return [Gitlab::ObjectifiedHash]
29
+ def wiki(project, slug)
30
+ get("/projects/#{url_encode project}/wikis/#{slug}")
31
+ end
32
+
33
+ # Creates a new wiki page for the given repository with the given title, slug, and content.
34
+ #
35
+ # @example
36
+ # Gitlab.create_wiki(3, 'Some Title', 'Some Content')
37
+ # Gitlab.create_wiki(3, 'Some Title', 'Some Content', { format: 'rdoc' })
38
+ #
39
+ # @param [Integer, String] project The ID or name of a project.
40
+ # @param [String] content The content of the wiki page.
41
+ # @param [String] title The title of the wiki page.
42
+ # @param [Hash] options A customizable set of options.
43
+ # @option options [String] format (optional) The format of the wiki page. Available formats are: markdown (default), rdoc, and asciidoc.
44
+ # @return [Gitlab::ObjectifiedHash] Information about created wiki page.
45
+ def create_wiki(project, title, content, options = {})
46
+ body = { content: content, title: title }.merge(options)
47
+ post("/projects/#{url_encode project}/wikis", body: body)
48
+ end
49
+
50
+ # Updates an existing wiki page. At least one parameter is required to update the wiki page.
51
+ #
52
+ # @example
53
+ # Gitlab.update_wiki(6, 'home', { title: 'New title' })
54
+ # Gitlab.update_wiki(6, 'home', { title: 'New title', content: 'New Message', format: 'rdoc' })
55
+ #
56
+ # @param [Integer, String] project The ID or name of a project.
57
+ # @param [String] slug The slug (a unique string) of the wiki page.
58
+ # @param [Hash] options A customizable set of options.
59
+ # @option options [String] content The content of the wiki page.
60
+ # @option options [String] title The title of the wiki page.
61
+ # @option options [String] format (optional) The format of the wiki page. Available formats are: markdown (default), rdoc, and asciidoc.
62
+ # @return [Gitlab::ObjectifiedHash] Information about updated wiki page.
63
+ def update_wiki(project, slug, options = {})
64
+ put("/projects/#{url_encode project}/wikis/#{slug}", body: options)
65
+ end
66
+
67
+ # Deletes a wiki page with a given slug.
68
+ #
69
+ # @example
70
+ # Gitlab.delete_wiki(42, 'foo')
71
+ #
72
+ # @param [Integer, String] project The ID or name of a project.
73
+ # @param [String] slug The slug (a unique string) of the wiki page.
74
+ # @return [Gitlab::ObjectifiedHash] An empty objectified hash
75
+ def delete_wiki(project, slug)
76
+ delete("/projects/#{url_encode project}/wikis/#{slug}")
77
+ end
78
+ end
79
+ end
data/lib/gitlab/client.rb CHANGED
@@ -1,58 +1,95 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Gitlab
2
4
  # Wrapper for the Gitlab REST API.
3
5
  class Client < API
4
- Dir[File.expand_path('../client/*.rb', __FILE__)].each { |f| require f }
6
+ Dir[File.expand_path('client/*.rb', __dir__)].each { |f| require f }
5
7
 
8
+ # Please keep in alphabetical order
9
+ include AccessRequests
10
+ include ApplicationSettings
11
+ include Avatar
6
12
  include AwardEmojis
7
13
  include Boards
8
14
  include Branches
9
- include Builds
15
+ include BroadcastMessages
10
16
  include BuildVariables
17
+ include Builds
11
18
  include Commits
19
+ include ContainerRegistry
20
+ include Deployments
12
21
  include Environments
22
+ include EpicIssues
23
+ include Epics
24
+ include Events
25
+ include Features
26
+ include GroupBadges
27
+ include GroupBoards
28
+ include GroupLabels
29
+ include GroupMilestones
13
30
  include Groups
31
+ include IssueLinks
14
32
  include Issues
33
+ include Jobs
15
34
  include Keys
16
35
  include Labels
36
+ include Lint
37
+ include Markdown
38
+ include MergeRequestApprovals
17
39
  include MergeRequests
18
40
  include Milestones
19
41
  include Namespaces
20
42
  include Notes
21
- include Pipelines
43
+ include PipelineSchedules
22
44
  include PipelineTriggers
45
+ include Pipelines
46
+ include ProjectBadges
47
+ include ProjectClusters
48
+ include ProjectReleaseLinks
49
+ include ProjectReleases
23
50
  include Projects
51
+ include ProtectedTags
52
+ include RemoteMirrors
24
53
  include Repositories
25
54
  include RepositoryFiles
55
+ include RepositorySubmodules
56
+ include ResourceLabelEvents
57
+ include ResourceStateEvents
26
58
  include Runners
59
+ include Search
27
60
  include Services
61
+ include Sidekiq
28
62
  include Snippets
29
63
  include SystemHooks
30
64
  include Tags
65
+ include Templates
31
66
  include Todos
32
67
  include Users
33
- include Jobs
68
+ include UserSnippets
69
+ include Versions
70
+ include Wikis
34
71
 
35
72
  # Text representation of the client, masking private token.
36
73
  #
37
74
  # @return [String]
38
75
  def inspect
39
76
  inspected = super
40
-
41
- if @private_token
42
- inspected = inspected.sub! @private_token, only_show_last_four_chars(@private_token)
43
- end
44
-
77
+ inspected.sub! @private_token, only_show_last_four_chars(@private_token) if @private_token
45
78
  inspected
46
79
  end
47
80
 
48
- def url_encode(s)
49
- ERB::Util.url_encode(s)
81
+ # Utility method for URL encoding of a string.
82
+ # Copied from https://ruby-doc.org/stdlib-2.7.0/libdoc/erb/rdoc/ERB/Util.html
83
+ #
84
+ # @return [String]
85
+ def url_encode(url)
86
+ url.to_s.b.gsub(/[^a-zA-Z0-9_\-.~]/n) { |m| sprintf('%%%02X', m.unpack1('C')) } # rubocop:disable Style/FormatString
50
87
  end
51
88
 
52
89
  private
53
90
 
54
91
  def only_show_last_four_chars(token)
55
- "#{'*'*(token.size - 4)}#{token[-4..-1]}"
92
+ "#{'*' * (token.size - 4)}#{token[-4..-1]}"
56
93
  end
57
94
  end
58
95
  end
@@ -1,17 +1,19 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'gitlab/cli_helpers'
2
4
  module Gitlab
3
5
  # Defines constants and methods related to configuration.
4
6
  module Configuration
5
7
  # An array of valid keys in the options hash when configuring a Gitlab::API.
6
- VALID_OPTIONS_KEYS = [:endpoint, :private_token, :user_agent, :sudo, :httparty].freeze
8
+ VALID_OPTIONS_KEYS = %i[endpoint private_token user_agent sudo httparty].freeze
7
9
 
8
10
  # The user agent that will be sent to the API endpoint if none is set.
9
- DEFAULT_USER_AGENT = "Gitlab Ruby Gem #{Gitlab::VERSION}".freeze
11
+ DEFAULT_USER_AGENT = "Gitlab Ruby Gem #{Gitlab::VERSION}"
10
12
 
11
13
  # @private
12
14
  attr_accessor(*VALID_OPTIONS_KEYS)
13
15
  # @private
14
- alias_method :auth_token=, :private_token=
16
+ alias auth_token= private_token=
15
17
 
16
18
  # Sets all configuration options to their default values
17
19
  # when this module is extended.
@@ -33,7 +35,7 @@ module Gitlab
33
35
 
34
36
  # Resets all configuration options to the defaults.
35
37
  def reset
36
- self.endpoint = ENV['GITLAB_API_ENDPOINT']
38
+ self.endpoint = ENV['GITLAB_API_ENDPOINT'] || ENV['CI_API_V4_URL']
37
39
  self.private_token = ENV['GITLAB_API_PRIVATE_TOKEN'] || ENV['GITLAB_API_AUTH_TOKEN']
38
40
  self.httparty = get_httparty_config(ENV['GITLAB_API_HTTPARTY_OPTIONS'])
39
41
  self.sudo = nil
@@ -44,11 +46,11 @@ module Gitlab
44
46
 
45
47
  # Allows HTTParty config to be specified in ENV using YAML hash.
46
48
  def get_httparty_config(options)
47
- return options if options.nil?
49
+ return if options.nil?
48
50
 
49
51
  httparty = Gitlab::CLI::Helpers.yaml_load(options)
52
+ raise ArgumentError, 'HTTParty config should be a Hash.' unless httparty.is_a? Hash
50
53
 
51
- raise ArgumentError, "HTTParty config should be a Hash." unless httparty.is_a? Hash
52
54
  Gitlab::CLI::Helpers.symbolize_keys httparty
53
55
  end
54
56
  end
data/lib/gitlab/error.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Gitlab
2
4
  module Error
3
5
  # Custom error class for rescuing from all Gitlab errors.
@@ -11,38 +13,83 @@ module Gitlab
11
13
 
12
14
  # Custom error class for rescuing from HTTP response errors.
13
15
  class ResponseError < Error
16
+ POSSIBLE_MESSAGE_KEYS = %i[message error_description error].freeze
17
+
14
18
  def initialize(response)
15
19
  @response = response
16
20
  super(build_error_message)
17
21
  end
18
22
 
19
- # Status code returned in the http response.
23
+ # Status code returned in the HTTP response.
20
24
  #
21
25
  # @return [Integer]
22
26
  def response_status
23
27
  @response.code
24
28
  end
25
29
 
30
+ # Body content returned in the HTTP response
31
+ #
32
+ # @return [String]
33
+ def response_message
34
+ @response.parsed_response.message
35
+ end
36
+
37
+ # Additional error context returned by some API endpoints
38
+ #
39
+ # @return [String]
40
+ def error_code
41
+ if @response.respond_to?(:error_code)
42
+ @response.error_code
43
+ else
44
+ ''
45
+ end
46
+ end
47
+
26
48
  private
27
49
 
28
50
  # Human friendly message.
29
51
  #
30
52
  # @return [String]
31
53
  def build_error_message
32
- parsed_response = @response.parsed_response
33
- message = parsed_response.message || parsed_response.error
34
-
54
+ parsed_response = classified_response
55
+ message = check_error_keys(parsed_response)
35
56
  "Server responded with code #{@response.code}, message: " \
36
57
  "#{handle_message(message)}. " \
37
58
  "Request URI: #{@response.request.base_uri}#{@response.request.path}"
38
59
  end
39
60
 
61
+ # Error keys vary across the API, find the first key that the parsed_response
62
+ # object responds to and return that, otherwise return the original.
63
+ def check_error_keys(resp)
64
+ key = POSSIBLE_MESSAGE_KEYS.find { |k| resp.respond_to?(k) }
65
+ key ? resp.send(key) : resp
66
+ end
67
+
68
+ # Parse the body based on the classification of the body content type
69
+ #
70
+ # @return parsed response
71
+ def classified_response
72
+ if @response.respond_to?('headers')
73
+ @response.headers['content-type'] == 'text/plain' ? { message: @response.to_s } : @response.parsed_response
74
+ else
75
+ @response.parsed_response
76
+ end
77
+ rescue Gitlab::Error::Parsing
78
+ # Return stringified response when receiving a
79
+ # parsing error to avoid obfuscation of the
80
+ # api error.
81
+ #
82
+ # note: The Gitlab API does not always return valid
83
+ # JSON when there are errors.
84
+ @response.to_s
85
+ end
86
+
40
87
  # Handle error response message in case of nested hashes
41
88
  def handle_message(message)
42
89
  case message
43
90
  when Gitlab::ObjectifiedHash
44
91
  message.to_h.sort.map do |key, val|
45
- "'#{key}' #{(val.is_a?(Hash) ? val.sort.map { |k, v| "(#{k}: #{v.join(' ')})" } : val).join(' ')}"
92
+ "'#{key}' #{(val.is_a?(Hash) ? val.sort.map { |k, v| "(#{k}: #{v.join(' ')})" } : [val].flatten).join(' ')}"
46
93
  end.join(', ')
47
94
  when Array
48
95
  message.join(' ')
@@ -67,12 +114,18 @@ module Gitlab
67
114
  # Raised when API endpoint returns the HTTP status code 405.
68
115
  class MethodNotAllowed < ResponseError; end
69
116
 
117
+ # Raised when API endpoint returns the HTTP status code 406.
118
+ class NotAcceptable < ResponseError; end
119
+
70
120
  # Raised when API endpoint returns the HTTP status code 409.
71
121
  class Conflict < ResponseError; end
72
122
 
73
123
  # Raised when API endpoint returns the HTTP status code 422.
74
124
  class Unprocessable < ResponseError; end
75
125
 
126
+ # Raised when API endpoint returns the HTTP status code 429.
127
+ class TooManyRequests < ResponseError; end
128
+
76
129
  # Raised when API endpoint returns the HTTP status code 500.
77
130
  class InternalServerError < ResponseError; end
78
131
 
@@ -81,5 +134,21 @@ module Gitlab
81
134
 
82
135
  # Raised when API endpoint returns the HTTP status code 503.
83
136
  class ServiceUnavailable < ResponseError; end
137
+
138
+ # HTTP status codes mapped to error classes.
139
+ STATUS_MAPPINGS = {
140
+ 400 => BadRequest,
141
+ 401 => Unauthorized,
142
+ 403 => Forbidden,
143
+ 404 => NotFound,
144
+ 405 => MethodNotAllowed,
145
+ 406 => NotAcceptable,
146
+ 409 => Conflict,
147
+ 422 => Unprocessable,
148
+ 429 => TooManyRequests,
149
+ 500 => InternalServerError,
150
+ 502 => BadGateway,
151
+ 503 => ServiceUnavailable
152
+ }.freeze
84
153
  end
85
154
  end
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Gitlab
2
4
  # Wrapper class of file response.
3
5
  class FileResponse
4
- HEADER_CONTENT_DISPOSITION = 'Content-Disposition'.freeze
6
+ HEADER_CONTENT_DISPOSITION = 'Content-Disposition'
5
7
 
6
8
  attr_reader :filename
7
9
 
@@ -18,7 +20,7 @@ module Gitlab
18
20
  def to_hash
19
21
  { filename: @filename, data: @file }
20
22
  end
21
- alias_method :to_h, :to_hash
23
+ alias to_h to_hash
22
24
 
23
25
  # @return [String] Formatted string with the class name, object id and filename.
24
26
  def inspect
@@ -39,7 +41,7 @@ module Gitlab
39
41
 
40
42
  # Parse filename from the 'Content Disposition' header.
41
43
  def parse_headers!(headers)
42
- @filename = headers[HEADER_CONTENT_DISPOSITION].split("filename=")[1]
44
+ @filename = headers[HEADER_CONTENT_DISPOSITION].split('filename=')[1]
43
45
  @filename = @filename[1...-1] if @filename[0] == '"' # Unquote filenames
44
46
  end
45
47
  end
data/lib/gitlab/help.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'gitlab'
2
4
  require 'gitlab/cli_helpers'
3
5
 
@@ -32,9 +34,7 @@ module Gitlab::Help
32
34
  # @return [String]
33
35
  def ri_cmd
34
36
  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
37
+ raise "'ri' tool not found in $PATH. Please install it to use the help." if which_ri.empty?
38
38
 
39
39
  which_ri
40
40
  end
@@ -45,23 +45,22 @@ module Gitlab::Help
45
45
  #
46
46
  # @return [Hash<Array>]
47
47
  def help_map
48
- @help_map ||= begin
48
+ @help_map ||=
49
49
  actions.each_with_object({}) do |action, hsh|
50
- key = client.method(action).
51
- owner.to_s.gsub(/Gitlab::(?:Client::)?/, '')
50
+ key = client.method(action)
51
+ .owner.to_s.gsub(/Gitlab::(?:Client::)?/, '')
52
52
  hsh[key] ||= []
53
53
  hsh[key] << action.to_s
54
54
  end
55
- end
56
55
  end
57
56
 
58
57
  # Table with available commands.
59
58
  #
60
59
  # @return [Terminal::Table]
61
- def actions_table(topic=nil)
60
+ def actions_table(topic = nil)
62
61
  rows = topic ? help_map[topic] : help_map.keys
63
62
  table do |t|
64
- t.title = topic || "Help Topics"
63
+ t.title = topic || 'Help Topics'
65
64
 
66
65
  # add_row expects an array and we have strings hence the map.
67
66
  rows.sort.map { |r| [r] }.each_with_index do |row, index|
@@ -73,23 +72,23 @@ module Gitlab::Help
73
72
 
74
73
  # Returns full namespace of a command (e.g. Gitlab::Client::Branches.cmd)
75
74
  def namespace(cmd)
76
- method_owners.select { |method| method[:name] === cmd }.
77
- map { |method| method[:owner] + '.' + method[:name] }.
78
- shift
75
+ method_owners.select { |method| method[:name] == cmd }
76
+ .map { |method| "#{method[:owner]}.#{method[:name]}" }
77
+ .shift
79
78
  end
80
79
 
81
80
  # Massage output from 'ri'.
82
81
  def change_help_output!(cmd, output_str)
83
- output_str.gsub!(/#{cmd}\((.*?)\)/m, cmd + ' \1')
84
- output_str.gsub!(/\,[\s]*/, ' ')
85
-
82
+ output_str = +output_str
83
+ output_str.gsub!(/#{cmd}(\(.*?\))/m, "#{cmd}\\1")
84
+ output_str.gsub!(/,\s*/, ', ')
85
+
86
86
  # Ensure @option descriptions are on a single line
87
87
  output_str.gsub!(/\n\[/, " \[")
88
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
-
89
+ output_str.gsub!(/(\])\n(:)/, '\\1 \\2')
90
+ output_str.gsub!(/(:.*)(\n)(.*\.)/, '\\1 \\3')
91
+ output_str.gsub!(/\{(.+)\}/, '"{\\1}"')
93
92
  end
94
- end # class << self
93
+ end
95
94
  end
@@ -1,34 +1,51 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Gitlab
2
4
  # Converts hashes to the objects.
3
5
  class ObjectifiedHash
4
6
  # Creates a new ObjectifiedHash object.
5
7
  def initialize(hash)
6
8
  @hash = hash
7
- @data = hash.inject({}) do |data, (key, value)|
8
- value = ObjectifiedHash.new(value) if value.is_a? Hash
9
+ @data = hash.each_with_object({}) do |(key, value), data|
10
+ value = self.class.new(value) if value.is_a? Hash
11
+ value = value.map { |v| v.is_a?(Hash) ? self.class.new(v) : v } if value.is_a? Array
9
12
  data[key.to_s] = value
10
- data
11
13
  end
12
14
  end
13
15
 
14
16
  # @return [Hash] The original hash.
15
17
  def to_hash
16
- @hash
18
+ hash
17
19
  end
18
- alias_method :to_h, :to_hash
20
+ alias to_h to_hash
19
21
 
20
22
  # @return [String] Formatted string with the class name, object id and original hash.
21
23
  def inspect
22
- "#<#{self.class}:#{object_id} {hash: #{@hash.inspect}}"
24
+ "#<#{self.class}:#{object_id} {hash: #{hash.inspect}}"
25
+ end
26
+
27
+ def [](key)
28
+ data[key]
23
29
  end
24
30
 
25
- # Delegate to ObjectifiedHash.
26
- def method_missing(key)
27
- @data.key?(key.to_s) ? @data[key.to_s] : nil
31
+ private
32
+
33
+ attr_reader :hash, :data
34
+
35
+ # Respond to messages for which `self.data` has a key
36
+ def method_missing(method_name, *args, &block)
37
+ if data.key?(method_name.to_s)
38
+ data[method_name.to_s]
39
+ elsif data.respond_to?(method_name)
40
+ warn 'WARNING: Please convert ObjectifiedHash object to hash before calling Hash methods on it.'
41
+ data.send(method_name, *args, &block)
42
+ else
43
+ super
44
+ end
28
45
  end
29
46
 
30
47
  def respond_to_missing?(method_name, include_private = false)
31
- @hash.keys.map(&:to_sym).include?(method_name.to_sym) || super
48
+ hash.keys.map(&:to_sym).include?(method_name.to_sym) || super
32
49
  end
33
50
  end
34
51
  end
@@ -1,21 +1,21 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Gitlab
2
4
  # Parses link header.
3
5
  #
4
6
  # @private
5
7
  class PageLinks
6
- HEADER_LINK = 'Link'.freeze
7
- DELIM_LINKS = ','.freeze
8
- LINK_REGEX = /<([^>]+)>; rel=\"([^\"]+)\"/
9
- METAS = %w(last next first prev)
8
+ HEADER_LINK = 'Link'
9
+ DELIM_LINKS = ','
10
+ LINK_REGEX = /<([^>]+)>; rel="([^"]+)"/.freeze
11
+ METAS = %w[last next first prev].freeze
10
12
 
11
13
  attr_accessor(*METAS)
12
14
 
13
15
  def initialize(headers)
14
16
  link_header = headers[HEADER_LINK]
15
17
 
16
- if link_header && link_header =~ /(next|first|last|prev)/
17
- extract_links(link_header)
18
- end
18
+ extract_links(link_header) if link_header && link_header =~ /(next|first|last|prev)/
19
19
  end
20
20
 
21
21
  private
@@ -23,9 +23,11 @@ module Gitlab
23
23
  def extract_links(header)
24
24
  header.split(DELIM_LINKS).each do |link|
25
25
  LINK_REGEX.match(link.strip) do |match|
26
- url, meta = match[1], match[2]
26
+ url = match[1]
27
+ meta = match[2]
27
28
  next if !url || !meta || METAS.index(meta).nil?
28
- self.send("#{meta}=", url)
29
+
30
+ send("#{meta}=", url)
29
31
  end
30
32
  end
31
33
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Gitlab
2
4
  # Wrapper class of paginated response.
3
5
  class PaginatedResponse
@@ -40,58 +42,69 @@ module Gitlab
40
42
  end
41
43
  end
42
44
 
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
45
+ def lazy_paginate
46
+ to_enum(:each_page).lazy.flat_map(&:to_ary)
47
+ end
48
+
49
+ def auto_paginate(&block)
50
+ return lazy_paginate.to_a unless block
51
+
52
+ lazy_paginate.each(&block)
53
+ end
54
+
55
+ def paginate_with_limit(limit, &block)
56
+ return lazy_paginate.take(limit).to_a unless block
57
+
58
+ lazy_paginate.take(limit).each(&block)
55
59
  end
56
60
 
57
- def has_last_page?
61
+ def last_page?
58
62
  !(@links.nil? || @links.last.nil?)
59
63
  end
64
+ alias has_last_page? last_page?
60
65
 
61
66
  def last_page
62
67
  return nil if @client.nil? || !has_last_page?
63
- path = @links.last.sub(/#{@client.endpoint}/, '')
64
- @client.get(path)
68
+
69
+ @client.get(client_relative_path(@links.last))
65
70
  end
66
71
 
67
- def has_first_page?
72
+ def first_page?
68
73
  !(@links.nil? || @links.first.nil?)
69
74
  end
75
+ alias has_first_page? first_page?
70
76
 
71
77
  def first_page
72
78
  return nil if @client.nil? || !has_first_page?
73
- path = @links.first.sub(/#{@client.endpoint}/, '')
74
- @client.get(path)
79
+
80
+ @client.get(client_relative_path(@links.first))
75
81
  end
76
82
 
77
- def has_next_page?
83
+ def next_page?
78
84
  !(@links.nil? || @links.next.nil?)
79
85
  end
86
+ alias has_next_page? next_page?
80
87
 
81
88
  def next_page
82
89
  return nil if @client.nil? || !has_next_page?
83
- path = @links.next.sub(/#{@client.endpoint}/, '')
84
- @client.get(path)
90
+
91
+ @client.get(client_relative_path(@links.next))
85
92
  end
86
93
 
87
- def has_prev_page?
94
+ def prev_page?
88
95
  !(@links.nil? || @links.prev.nil?)
89
96
  end
97
+ alias has_prev_page? prev_page?
90
98
 
91
99
  def prev_page
92
100
  return nil if @client.nil? || !has_prev_page?
93
- path = @links.prev.sub(/#{@client.endpoint}/, '')
94
- @client.get(path)
101
+
102
+ @client.get(client_relative_path(@links.prev))
103
+ end
104
+
105
+ def client_relative_path(link)
106
+ client_endpoint_path = URI.parse(@client.endpoint).request_uri # api/v4
107
+ URI.parse(link).request_uri.sub(client_endpoint_path, '')
95
108
  end
96
109
  end
97
110
  end