gitlab 3.3.0 → 3.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -1
  3. data/CHANGELOG.md +157 -0
  4. data/LICENSE.txt +1 -1
  5. data/README.md +16 -10
  6. data/lib/gitlab.rb +1 -1
  7. data/lib/gitlab/api.rb +5 -3
  8. data/lib/gitlab/cli.rb +21 -3
  9. data/lib/gitlab/cli_helpers.rb +46 -79
  10. data/lib/gitlab/client.rb +2 -1
  11. data/lib/gitlab/client/branches.rb +16 -1
  12. data/lib/gitlab/client/groups.rb +1 -0
  13. data/lib/gitlab/client/issues.rb +1 -0
  14. data/lib/gitlab/client/labels.rb +2 -0
  15. data/lib/gitlab/client/merge_requests.rb +12 -10
  16. data/lib/gitlab/client/milestones.rb +15 -0
  17. data/lib/gitlab/client/notes.rb +22 -6
  18. data/lib/gitlab/client/projects.rb +18 -0
  19. data/lib/gitlab/client/repositories.rb +4 -1
  20. data/lib/gitlab/client/repository_files.rb +72 -0
  21. data/lib/gitlab/client/snippets.rb +1 -11
  22. data/lib/gitlab/client/system_hooks.rb +1 -0
  23. data/lib/gitlab/client/users.rb +2 -0
  24. data/lib/gitlab/configuration.rb +3 -1
  25. data/lib/gitlab/error.rb +0 -3
  26. data/lib/gitlab/help.rb +77 -31
  27. data/lib/gitlab/objectified_hash.rb +6 -0
  28. data/lib/gitlab/request.rb +31 -15
  29. data/lib/gitlab/shell.rb +57 -58
  30. data/lib/gitlab/version.rb +1 -1
  31. data/spec/fixtures/branch_delete.json +3 -0
  32. data/spec/fixtures/merge_request_changes.json +1 -0
  33. data/spec/fixtures/milestone_issues.json +1 -0
  34. data/spec/fixtures/project_search.json +1 -0
  35. data/spec/fixtures/repository_file.json +1 -0
  36. data/spec/gitlab/cli_helpers_spec.rb +58 -0
  37. data/spec/gitlab/cli_spec.rb +1 -2
  38. data/spec/gitlab/client/branches_spec.rb +15 -0
  39. data/spec/gitlab/client/merge_requests_spec.rb +20 -12
  40. data/spec/gitlab/client/milestones_spec.rb +16 -0
  41. data/spec/gitlab/client/notes_spec.rb +17 -0
  42. data/spec/gitlab/client/projects_spec.rb +45 -8
  43. data/spec/gitlab/client/repository_files_spec.rb +45 -0
  44. data/spec/gitlab/help_spec.rb +44 -0
  45. data/spec/gitlab/objectified_hash_spec.rb +7 -0
  46. data/spec/gitlab/request_spec.rb +45 -6
  47. data/spec/gitlab/shell_spec.rb +80 -0
  48. data/spec/gitlab_spec.rb +12 -0
  49. metadata +23 -3
@@ -6,14 +6,15 @@ module Gitlab
6
6
  include Branches
7
7
  include Groups
8
8
  include Issues
9
+ include Labels
9
10
  include MergeRequests
10
11
  include Milestones
11
12
  include Notes
12
13
  include Projects
13
14
  include Repositories
15
+ include RepositoryFiles
14
16
  include Snippets
15
17
  include SystemHooks
16
18
  include Users
17
- include Labels
18
19
  end
19
20
  end
@@ -1,5 +1,6 @@
1
1
  class Gitlab::Client
2
2
  # Defines methods related to repositories.
3
+ # @see https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/branches.md
3
4
  module Branches
4
5
  # Gets a list of project repositiory branches.
5
6
  #
@@ -28,7 +29,7 @@ class Gitlab::Client
28
29
  def branch(project, branch)
29
30
  get("/projects/#{project}/repository/branches/#{branch}")
30
31
  end
31
-
32
+
32
33
  alias_method :repo_branch, :branch
33
34
 
34
35
  # Protects a repository branch.
@@ -74,6 +75,20 @@ class Gitlab::Client
74
75
  end
75
76
  alias_method :repo_create_branch, :create_branch
76
77
 
78
+ # Deletes a repository branch. Requires Gitlab >= 6.8.x
79
+ #
80
+ # @example
81
+ # Gitlab.delete_branch(3, 'api')
82
+ # Gitlab.repo_delete_branch(5, 'master')
83
+ #
84
+ # @param [Integer] project The ID of a project.
85
+ # @param [String] branch The name of the branch to delete
86
+ # @return [Gitlab::ObjectifiedHash]
87
+ def delete_branch(project, branch)
88
+ delete("/projects/#{project}/repository/branches/#{branch}")
89
+ end
90
+ alias_method :repo_delete_branch, :delete_branch
91
+
77
92
  end
78
93
  end
79
94
 
@@ -1,5 +1,6 @@
1
1
  class Gitlab::Client
2
2
  # Defines methods related to groups.
3
+ # @see https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/groups.md
3
4
  module Groups
4
5
  # Gets a list of groups.
5
6
  #
@@ -1,5 +1,6 @@
1
1
  class Gitlab::Client
2
2
  # Defines methods related to issues.
3
+ # @see https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/issues.md
3
4
  module Issues
4
5
  # Gets a list of user's issues.
5
6
  # Will return a list of project's issues if project ID passed.
@@ -1,4 +1,6 @@
1
1
  class Gitlab::Client
2
+ # Defines methods related to labels.
3
+ # @see https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/labels.md
2
4
  module Labels
3
5
  # Gets a list of project's labels.
4
6
  #
@@ -1,5 +1,6 @@
1
1
  class Gitlab::Client
2
2
  # Defines methods related to merge requests.
3
+ # @see https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/merge_requests.md
3
4
  module MergeRequests
4
5
  # Gets a list of project merge requests.
5
6
  #
@@ -42,10 +43,9 @@ class Gitlab::Client
42
43
  # @option options [String] :source_branch (required) The source branch name.
43
44
  # @option options [String] :target_branch (required) The target branch name.
44
45
  # @option options [Integer] :assignee_id (optional) The ID of a user to assign merge request.
46
+ # @option options [Integer] :target_project_id (optional) The target project ID.
45
47
  # @return [Gitlab::ObjectifiedHash] Information about created merge request.
46
48
  def create_merge_request(project, title, options={})
47
- check_attributes!(options, [:source_branch, :target_branch])
48
-
49
49
  body = {:title => title}.merge(options)
50
50
  post("/projects/#{project}/merge_requests", :body => body)
51
51
  end
@@ -112,14 +112,16 @@ class Gitlab::Client
112
112
  get("/projects/#{project}/merge_request/#{id}/comments", :query => options)
113
113
  end
114
114
 
115
- private
116
-
117
- def check_attributes!(options, attrs)
118
- attrs.each do |attr|
119
- unless options.has_key?(attr) || options.has_key?(attr.to_s)
120
- raise Gitlab::Error::MissingAttributes.new("Missing '#{attr}' parameter")
121
- end
122
- end
115
+ # Gets the changes of a merge request.
116
+ #
117
+ # @example
118
+ # Gitlab.merge_request_changes(5, 1)
119
+ #
120
+ # @param [Integer] project The ID of a project.
121
+ # @param [Integer] id The ID of a merge request.
122
+ # @return [Gitlab::ObjectifiedHash] The merge request's changes.
123
+ def merge_request_changes(project, id)
124
+ get("/projects/#{project}/merge_request/#{id}/changes")
123
125
  end
124
126
  end
125
127
  end
@@ -1,5 +1,6 @@
1
1
  class Gitlab::Client
2
2
  # Defines methods related to milestones.
3
+ # @see https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/milestones.md
3
4
  module Milestones
4
5
  # Gets a list of project's milestones.
5
6
  #
@@ -27,6 +28,20 @@ class Gitlab::Client
27
28
  get("/projects/#{project}/milestones/#{id}")
28
29
  end
29
30
 
31
+ # Gets the issues of a given milestone.
32
+ #
33
+ # @example
34
+ # Gitlab.milestone_issues(5, 2)
35
+ #
36
+ # @param [Integer, String] project The ID of a project.
37
+ # @param [Integer, String] milestone The ID of a milestone.
38
+ # @option options [Integer] :page The page number.
39
+ # @option options [Integer] :per_page The number of results per page.
40
+ # @return [Array<Gitlab::ObjectifiedHash>]
41
+ def milestone_issues(project, milestone, options={})
42
+ get("/projects/#{project}/milestones/#{milestone}/issues", :query => options)
43
+ end
44
+
30
45
  # Creates a new milestone.
31
46
  #
32
47
  # @param [Integer] project The ID of a project.
@@ -1,5 +1,6 @@
1
1
  class Gitlab::Client
2
2
  # Defines methods related to notes.
3
+ # @see https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/notes.md
3
4
  module Notes
4
5
  # Gets a list of projects notes.
5
6
  #
@@ -7,9 +8,11 @@ class Gitlab::Client
7
8
  # Gitlab.notes(5)
8
9
  #
9
10
  # @param [Integer] project The ID of a project.
11
+ # @option options [Integer] :page The page number.
12
+ # @option options [Integer] :per_page The number of results per page.
10
13
  # @return [Array<Gitlab::ObjectifiedHash>]
11
- def notes(project)
12
- get("/projects/#{project}/notes")
14
+ def notes(project, options={})
15
+ get("/projects/#{project}/notes", :query => options)
13
16
  end
14
17
 
15
18
  # Gets a list of notes for a issue.
@@ -19,9 +22,11 @@ class Gitlab::Client
19
22
  #
20
23
  # @param [Integer] project The ID of a project.
21
24
  # @param [Integer] issue The ID of an issue.
25
+ # @option options [Integer] :page The page number.
26
+ # @option options [Integer] :per_page The number of results per page.
22
27
  # @return [Array<Gitlab::ObjectifiedHash>]
23
- def issue_notes(project, issue)
24
- get("/projects/#{project}/issues/#{issue}/notes")
28
+ def issue_notes(project, issue, options={})
29
+ get("/projects/#{project}/issues/#{issue}/notes", :query => options)
25
30
  end
26
31
 
27
32
  # Gets a list of notes for a snippet.
@@ -31,9 +36,11 @@ class Gitlab::Client
31
36
  #
32
37
  # @param [Integer] project The ID of a project.
33
38
  # @param [Integer] snippet The ID of a snippet.
39
+ # @option options [Integer] :page The page number.
40
+ # @option options [Integer] :per_page The number of results per page.
34
41
  # @return [Array<Gitlab::ObjectifiedHash>]
35
- def snippet_notes(project, snippet)
36
- get("/projects/#{project}/snippets/#{snippet}/notes")
42
+ def snippet_notes(project, snippet, options={})
43
+ get("/projects/#{project}/snippets/#{snippet}/notes", :query => options)
37
44
  end
38
45
 
39
46
  # Gets a single wall note.
@@ -102,5 +109,14 @@ class Gitlab::Client
102
109
  def create_snippet_note(project, snippet, body)
103
110
  post("/projects/#{project}/snippets/#{snippet}/notes", :body => {:body => body})
104
111
  end
112
+
113
+ # Creates a new note for a single merge request.
114
+ #
115
+ # @param [Integer] project The ID of a project.
116
+ # @param [Integer] merge_request The ID of a merge request.
117
+ # @param [String] body The content of a note.
118
+ def create_merge_request_note(project, merge_request, body)
119
+ post("/projects/#{project}/merge_requests/#{merge_request}/notes", :body => {:body => body})
120
+ end
105
121
  end
106
122
  end
@@ -1,5 +1,6 @@
1
1
  class Gitlab::Client
2
2
  # Defines methods related to projects.
3
+ # @see https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/projects.md
3
4
  module Projects
4
5
  # Gets a list of projects owned by the authenticated user.
5
6
  #
@@ -19,6 +20,23 @@ class Gitlab::Client
19
20
  end
20
21
  end
21
22
 
23
+ # Search for projects by name
24
+ #
25
+ # @example
26
+ # Gitlab.project_search('gitlab')
27
+ # Gitlab.project_search('gitlab', :order_by => 'last_activity_at')
28
+ #
29
+ # @param [Hash] options A customizable set of options.
30
+ # @option options [String] :per_page Number of projects to return per page
31
+ # @option options [String] :page The page to retrieve
32
+ # @option options [String] :order_by Return requests ordered by id, name, created_at or last_activity_at fields
33
+ # @option options [String] :sort Return requests sorted in asc or desc order
34
+ # @return [Array<Gitlab::ObjectifiedHash>]
35
+ def project_search(query, options={})
36
+ get("/projects/search/#{query}", :query => options)
37
+ end
38
+
39
+
22
40
  # Gets information about a project.
23
41
  #
24
42
  # @example
@@ -1,5 +1,6 @@
1
1
  class Gitlab::Client
2
2
  # Defines methods related to repositories.
3
+ # @see https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/repositories.md
3
4
  module Repositories
4
5
  # Gets a list of project repository tags.
5
6
  #
@@ -19,7 +20,8 @@ class Gitlab::Client
19
20
  # Creates a new project repository tag.
20
21
  #
21
22
  # @example
22
- # Gitlab.create_tag(42,'new_tag','master')
23
+ # Gitlab.create_tag(42, 'new_tag', 'master')
24
+ # Gitlab.create_tag(42, 'v1.0', 'master', 'Release 1.0')
23
25
  #
24
26
  # @param [Integer] project The ID of a project.
25
27
  # @param [String] tag_name The name of the new tag.
@@ -87,6 +89,7 @@ class Gitlab::Client
87
89
  # @param [String] ref The name of a repository branch or tag or if not given the default branch.
88
90
  # @return [String]
89
91
  def file_contents(project, filepath, ref = 'master')
92
+ ref = URI.encode(ref, /\W/)
90
93
  get "/projects/#{project}/repository/blobs/#{ref}?filepath=#{filepath}",
91
94
  format: nil,
92
95
  headers: { Accept: 'text/plain' },
@@ -0,0 +1,72 @@
1
+ require 'base64'
2
+
3
+ class Gitlab::Client
4
+ # Defines methods related to repository files.
5
+ # @see https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/repository_files.md
6
+ module RepositoryFiles
7
+ # Creates a new repository file.
8
+ #
9
+ # @example
10
+ # Gitlab.create_file(42, "path", "branch", "content", "commit message")
11
+ #
12
+ # @param [Integer] project The ID of a project.
13
+ # @param [String] full path to new file.
14
+ # @param [String] the name of the branch.
15
+ # @param [String] file content.
16
+ # @param [String] commit message.
17
+ # @return [Gitlab::ObjectifiedHash]
18
+ def create_file(project, path, branch, content, commit_message)
19
+ post("/projects/#{project}/repository/files", body: {
20
+ file_path: path,
21
+ branch_name: branch,
22
+ commit_message: commit_message,
23
+ }.merge(encoded_content_attributes(content)))
24
+ end
25
+
26
+ # Edits an existing repository file.
27
+ #
28
+ # @example
29
+ # Gitlab.edit_file(42, "path", "branch", "content", "commit message")
30
+ #
31
+ # @param [Integer] project The ID of a project.
32
+ # @param [String] full path to new file.
33
+ # @param [String] the name of the branch.
34
+ # @param [String] file content.
35
+ # @param [String] commit message.
36
+ # @return [Gitlab::ObjectifiedHash]
37
+ def edit_file(project, path, branch, content, commit_message)
38
+ put("/projects/#{project}/repository/files", body: {
39
+ file_path: path,
40
+ branch_name: branch,
41
+ commit_message: commit_message,
42
+ }.merge(encoded_content_attributes(content)))
43
+ end
44
+
45
+ # Removes an existing repository file.
46
+ #
47
+ # @example
48
+ # Gitlab.remove_file(42, "path", "branch", "commit message")
49
+ #
50
+ # @param [Integer] project The ID of a project.
51
+ # @param [String] full path to new file.
52
+ # @param [String] the name of the branch.
53
+ # @param [String] commit message.
54
+ # @return [Gitlab::ObjectifiedHash]
55
+ def remove_file(project, path, branch, commit_message)
56
+ delete("/projects/#{project}/repository/files", body: {
57
+ file_path: path,
58
+ branch_name: branch,
59
+ commit_message: commit_message,
60
+ })
61
+ end
62
+
63
+ private
64
+
65
+ def encoded_content_attributes(content)
66
+ {
67
+ encoding: 'base64',
68
+ content: Base64.encode64(content),
69
+ }
70
+ end
71
+ end
72
+ end
@@ -1,5 +1,6 @@
1
1
  class Gitlab::Client
2
2
  # Defines methods related to snippets.
3
+ # @see https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/project_snippets.md
3
4
  module Snippets
4
5
  # Gets a list of project's snippets.
5
6
  #
@@ -40,7 +41,6 @@ class Gitlab::Client
40
41
  # @option options [String] :lifetime (optional) The expiration date of a snippet.
41
42
  # @return [Gitlab::ObjectifiedHash] Information about created snippet.
42
43
  def create_snippet(project, options={})
43
- check_attributes!(options, [:title, :file_name, :code])
44
44
  post("/projects/#{project}/snippets", :body => options)
45
45
  end
46
46
 
@@ -72,15 +72,5 @@ class Gitlab::Client
72
72
  def delete_snippet(project, id)
73
73
  delete("/projects/#{project}/snippets/#{id}")
74
74
  end
75
-
76
- private
77
-
78
- def check_attributes!(options, attrs)
79
- attrs.each do |attr|
80
- unless options.has_key?(attr) || options.has_key?(attr.to_s)
81
- raise Gitlab::Error::MissingAttributes.new("Missing '#{attr}' parameter")
82
- end
83
- end
84
- end
85
75
  end
86
76
  end
@@ -1,5 +1,6 @@
1
1
  class Gitlab::Client
2
2
  # Defines methods related to system hooks.
3
+ # @see https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/system_hooks.md
3
4
  module SystemHooks
4
5
  # Gets a list of system hooks.
5
6
  #
@@ -1,5 +1,7 @@
1
1
  class Gitlab::Client
2
2
  # Defines methods related to users.
3
+ # @see https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/users.md
4
+ # @see https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/session.md
3
5
  module Users
4
6
  # Gets a list of users.
5
7
  #
@@ -9,6 +9,8 @@ module Gitlab
9
9
 
10
10
  # @private
11
11
  attr_accessor(*VALID_OPTIONS_KEYS)
12
+ # @private
13
+ alias_method :auth_token=, :private_token=
12
14
 
13
15
  # Sets all configuration options to their default values
14
16
  # when this module is extended.
@@ -31,7 +33,7 @@ module Gitlab
31
33
  # Resets all configuration options to the defaults.
32
34
  def reset
33
35
  self.endpoint = ENV['GITLAB_API_ENDPOINT']
34
- self.private_token = ENV['GITLAB_API_PRIVATE_TOKEN']
36
+ self.private_token = ENV['GITLAB_API_PRIVATE_TOKEN'] || ENV['GITLAB_API_AUTH_TOKEN']
35
37
  self.sudo = nil
36
38
  self.user_agent = DEFAULT_USER_AGENT
37
39
  end
@@ -3,9 +3,6 @@ module Gitlab
3
3
  # Custom error class for rescuing from all Gitlab errors.
4
4
  class Error < StandardError; end
5
5
 
6
- # Raise when attributes are missing.
7
- class MissingAttributes < Error; end
8
-
9
6
  # Raised when API endpoint credentials not configured.
10
7
  class MissingCredentials < Error; end
11
8
 
@@ -4,41 +4,87 @@ require 'gitlab/cli_helpers'
4
4
  module Gitlab::Help
5
5
  extend Gitlab::CLI::Helpers
6
6
 
7
- def self.get_help(methods,cmd=nil)
8
- help = ''
9
-
10
- if cmd.nil? || cmd == 'help'
11
- help = actions_table
12
- else
13
- ri_cmd = `which ri`.chomp
14
-
15
- if $? == 0
16
- namespace = methods.select {|m| m[:name] === cmd }.map {|m| m[:owner]+'.'+m[:name] }.shift
17
-
18
- if namespace
19
- begin
20
- ri_output = `#{ri_cmd} -T #{namespace} 2>&1`.chomp
21
-
22
- if $? == 0
23
- ri_output.gsub!(/#{cmd}\((.*?)\)/m, cmd+' \1')
24
- ri_output.gsub!(/Gitlab\./, 'gitlab> ')
25
- ri_output.gsub!(/Gitlab\..+$/, '')
26
- ri_output.gsub!(/\,[\s]*/, ' ')
27
- help = ri_output
28
- else
29
- help = "Ri docs not found for #{namespace}, please install the docs to use 'help'"
30
- end
31
- rescue => e
32
- puts e.message
33
- end
7
+ class << self
8
+
9
+ # Returns the (modified) help from the 'ri' command or returns an error.
10
+ #
11
+ # @return [String]
12
+ def get_help(cmd)
13
+ cmd_namespace = namespace cmd
14
+
15
+ if cmd_namespace
16
+ ri_output = `#{ri_cmd} -T #{cmd_namespace} 2>&1`.chomp
17
+
18
+ if $? == 0
19
+ change_help_output! cmd, ri_output
20
+ yield ri_output if block_given?
21
+
22
+ ri_output
34
23
  else
35
- help = "Unknown command: #{cmd}"
24
+ "Ri docs not found for #{cmd}, please install the docs to use 'help'."
36
25
  end
37
26
  else
38
- help = "'ri' tool not found in your PATH, please install it to use the help."
27
+ "Unknown command: #{cmd}."
28
+ end
29
+ end
30
+
31
+ # Finds the location of 'ri' on a system.
32
+ #
33
+ # @return [String]
34
+ def ri_cmd
35
+ which_ri = `which ri`.chomp
36
+ if which_ri.empty?
37
+ raise "'ri' tool not found in $PATH. Please install it to use the help."
39
38
  end
39
+
40
+ which_ri
40
41
  end
41
42
 
42
- puts help
43
- end
43
+ # A hash map that contains help topics (Branches, Groups, etc.)
44
+ # and a list of commands that are defined under a topic (create_branch,
45
+ # branches, protect_branch, etc.).
46
+ #
47
+ # @return [Hash<Array>]
48
+ def help_map
49
+ @help_map ||= begin
50
+ actions.each_with_object({}) do |action, hsh|
51
+ key = client.method(action).
52
+ owner.to_s.gsub(/Gitlab::(?:Client::)?/, '')
53
+ hsh[key] ||= []
54
+ hsh[key] << action.to_s
55
+ end
56
+ end
57
+ end
58
+
59
+ # Table with available commands.
60
+ #
61
+ # @return [Terminal::Table]
62
+ def actions_table(topic = nil)
63
+ rows = topic ? help_map[topic] : help_map.keys
64
+ table do |t|
65
+ t.title = topic || "Help Topics"
66
+
67
+ # add_row expects an array and we have strings hence the map.
68
+ rows.sort.map { |r| [r] }.each_with_index do |row, index|
69
+ t.add_row row
70
+ t.add_separator unless rows.size - 1 == index
71
+ end
72
+ end
73
+ end
74
+
75
+ # Returns full namespace of a command (e.g. Gitlab::Client::Branches.cmd)
76
+ def namespace(cmd)
77
+ method_owners.select { |method| method[:name] === cmd }.
78
+ map { |method| method[:owner] + '.' + method[:name] }.
79
+ shift
80
+ end
81
+
82
+ # Massage output from 'ri'.
83
+ def change_help_output!(cmd, output_str)
84
+ output_str.gsub!(/#{cmd}\((.*?)\)/m, cmd+' \1')
85
+ output_str.gsub!(/\,[\s]*/, ' ')
86
+ end
87
+
88
+ end # class << self
44
89
  end
90
+