Commit d005242d230b1e0c59e183996f0f3117540130d3

Authored by Dmitriy Zaporozhets
2 parents fe6d122d 4281de36

Merge pull request #1803 from gitlabhq/api_merge_request

Api for merge request
doc/api/merge_requests.md 0 → 100644
... ... @@ -0,0 +1,194 @@
  1 +## List merge requests
  2 +
  3 +Get all MR for this project.
  4 +
  5 +```
  6 +GET /projects/:id/merge_requests
  7 +```
  8 +
  9 +Parameters:
  10 +
  11 ++ `id` (required) - The ID or code name of a project
  12 +
  13 +```json
  14 +[
  15 + {
  16 + "id":1,
  17 + "target_branch":"master",
  18 + "source_branch":"test1",
  19 + "project_id":3,
  20 + "title":"test1",
  21 + "closed":true,
  22 + "merged":false,
  23 + "author":{
  24 + "id":1,
  25 + "email":"admin@local.host",
  26 + "name":"Administrator",
  27 + "blocked":false,
  28 + "created_at":"2012-04-29T08:46:00Z"
  29 + },
  30 + "assignee":{
  31 + "id":1,
  32 + "email":"admin@local.host",
  33 + "name":"Administrator",
  34 + "blocked":false,
  35 + "created_at":"2012-04-29T08:46:00Z"
  36 + }
  37 + }
  38 +]
  39 +```
  40 +
  41 +## Show MR
  42 +
  43 +Show information about MR.
  44 +
  45 +```
  46 +GET /projects/:id/merge_request/:merge_request_id
  47 +```
  48 +
  49 +Parameters:
  50 +
  51 ++ `id` (required) - The ID or code name of a project
  52 ++ `merge_request_id` (required) - The ID of MR
  53 +
  54 +```json
  55 +{
  56 + "id":1,
  57 + "target_branch":"master",
  58 + "source_branch":"test1",
  59 + "project_id":3,
  60 + "title":"test1",
  61 + "closed":true,
  62 + "merged":false,
  63 + "author":{
  64 + "id":1,
  65 + "email":"admin@local.host",
  66 + "name":"Administrator",
  67 + "blocked":false,
  68 + "created_at":"2012-04-29T08:46:00Z"
  69 + },
  70 + "assignee":{
  71 + "id":1,
  72 + "email":"admin@local.host",
  73 + "name":"Administrator",
  74 + "blocked":false,
  75 + "created_at":"2012-04-29T08:46:00Z"
  76 + }
  77 +}
  78 +```
  79 +
  80 +
  81 +## Create MR
  82 +
  83 +Create MR.
  84 +
  85 +```
  86 +POST /projects/:id/merge_requests
  87 +```
  88 +
  89 +Parameters:
  90 +
  91 ++ `id` (required) - The ID or code name of a project
  92 ++ `source_branch` (required) - The source branch
  93 ++ `target_branch` (required) - The target branch
  94 ++ `assignee_id` - Assignee user ID
  95 ++ `title` (required) - Title of MR
  96 +
  97 +```json
  98 +{
  99 + "id":1,
  100 + "target_branch":"master",
  101 + "source_branch":"test1",
  102 + "project_id":3,
  103 + "title":"test1",
  104 + "closed":true,
  105 + "merged":false,
  106 + "author":{
  107 + "id":1,
  108 + "email":"admin@local.host",
  109 + "name":"Administrator",
  110 + "blocked":false,
  111 + "created_at":"2012-04-29T08:46:00Z"
  112 + },
  113 + "assignee":{
  114 + "id":1,
  115 + "email":"admin@local.host",
  116 + "name":"Administrator",
  117 + "blocked":false,
  118 + "created_at":"2012-04-29T08:46:00Z"
  119 + }
  120 +}
  121 +```
  122 +
  123 +## Update MR
  124 +
  125 +Update MR. You can change branches, title, or even close the MR.
  126 +
  127 +```
  128 +PUT /projects/:id/merge_request/:merge_request_id
  129 +```
  130 +
  131 +Parameters:
  132 +
  133 ++ `id` (required) - The ID or code name of a project
  134 ++ `merge_request_id` (required) - ID of MR
  135 ++ `source_branch` - The source branch
  136 ++ `target_branch` - The target branch
  137 ++ `assignee_id` - Assignee user ID
  138 ++ `title` - Title of MR
  139 ++ `closed` - Status of MR. true - closed
  140 +
  141 +
  142 +```json
  143 +{
  144 + "id":1,
  145 + "target_branch":"master",
  146 + "source_branch":"test1",
  147 + "project_id":3,
  148 + "title":"test1",
  149 + "closed":true,
  150 + "merged":false,
  151 + "author":{
  152 + "id":1,
  153 + "email":"admin@local.host",
  154 + "name":"Administrator",
  155 + "blocked":false,
  156 + "created_at":"2012-04-29T08:46:00Z"
  157 + },
  158 + "assignee":{
  159 + "id":1,
  160 + "email":"admin@local.host",
  161 + "name":"Administrator",
  162 + "blocked":false,
  163 + "created_at":"2012-04-29T08:46:00Z"
  164 + }
  165 +}
  166 +```
  167 +## Post comment to MR
  168 +
  169 +Post comment to MR
  170 +
  171 +```
  172 +POST /projects/:id/merge_request/:merge_request_id/comments
  173 +```
  174 +
  175 +Parameters:
  176 +
  177 ++ `id` (required) - The ID or code name of a project
  178 ++ `merge_request_id` (required) - ID of MR
  179 ++ `note` (required) - Text of comment
  180 +
  181 +Will return created note with status `201 Created` on success, or `404 Not found` on fail.
  182 +
  183 +```json
  184 +{
  185 + "author":{
  186 + "id":1,
  187 + "email":"admin@local.host",
  188 + "name":"Administrator",
  189 + "blocked":false,
  190 + "created_at":"2012-04-29T08:46:00Z"
  191 + },
  192 + "note":"text1"
  193 +}
  194 +```
... ...
lib/api.rb
... ... @@ -18,5 +18,6 @@ module Gitlab
18 18 mount Issues
19 19 mount Milestones
20 20 mount Session
  21 + mount MergeRequests
21 22 end
22 23 end
... ...
lib/api/entities.rb
... ... @@ -63,5 +63,15 @@ module Gitlab
63 63 class SSHKey < Grape::Entity
64 64 expose :id, :title, :key
65 65 end
  66 +
  67 + class MergeRequest < Grape::Entity
  68 + expose :id, :target_branch, :source_branch, :project_id, :title, :closed, :merged
  69 + expose :author, :assignee, using: Entities::UserBasic
  70 + end
  71 +
  72 + class Note < Grape::Entity
  73 + expose :author, using: Entities::UserBasic
  74 + expose :note
  75 + end
66 76 end
67 77 end
... ...
lib/api/merge_requests.rb 0 → 100644
... ... @@ -0,0 +1,118 @@
  1 +module Gitlab
  2 + # MergeRequest API
  3 + class MergeRequests < Grape::API
  4 + before { authenticate! }
  5 +
  6 + resource :projects do
  7 +
  8 + # List merge requests
  9 + #
  10 + # Parameters:
  11 + # id (required) - The ID or code name of a project
  12 + #
  13 + # Example:
  14 + # GET /projects/:id/merge_requests
  15 + #
  16 + get ":id/merge_requests" do
  17 + authorize! :read_merge_request, user_project
  18 +
  19 + present paginate(user_project.merge_requests), with: Entities::MergeRequest
  20 + end
  21 +
  22 + # Show MR
  23 + #
  24 + # Parameters:
  25 + # id (required) - The ID or code name of a project
  26 + # merge_request_id (required) - The ID of MR
  27 + #
  28 + # Example:
  29 + # GET /projects/:id/merge_request/:merge_request_id
  30 + #
  31 + get ":id/merge_request/:merge_request_id" do
  32 + merge_request = user_project.merge_requests.find(params[:merge_request_id])
  33 +
  34 + authorize! :read_merge_request, merge_request
  35 +
  36 + present merge_request, with: Entities::MergeRequest
  37 + end
  38 +
  39 + # Create MR
  40 + #
  41 + # Parameters:
  42 + #
  43 + # id (required) - The ID or code name of a project
  44 + # source_branch (required) - The source branch
  45 + # target_branch (required) - The target branch
  46 + # assignee_id - Assignee user ID
  47 + # title (required) - Title of MR
  48 + #
  49 + # Example:
  50 + # POST /projects/:id/merge_requests
  51 + #
  52 + post ":id/merge_requests" do
  53 + authorize! :write_merge_request, user_project
  54 +
  55 + attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title]
  56 + merge_request = user_project.merge_requests.new(attrs)
  57 + merge_request.author = current_user
  58 +
  59 + if merge_request.save
  60 + merge_request.reload_code
  61 + present merge_request, with: Entities::MergeRequest
  62 + else
  63 + not_found!
  64 + end
  65 + end
  66 +
  67 + # Update MR
  68 + #
  69 + # Parameters:
  70 + # id (required) - The ID or code name of a project
  71 + # merge_request_id (required) - ID of MR
  72 + # source_branch - The source branch
  73 + # target_branch - The target branch
  74 + # assignee_id - Assignee user ID
  75 + # title - Title of MR
  76 + # closed - Status of MR. true - closed
  77 + # Example:
  78 + # PUT /projects/:id/merge_request/:merge_request_id
  79 + #
  80 + put ":id/merge_request/:merge_request_id" do
  81 + attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title, :closed]
  82 + merge_request = user_project.merge_requests.find(params[:merge_request_id])
  83 +
  84 + authorize! :modify_merge_request, merge_request
  85 +
  86 + if merge_request.update_attributes attrs
  87 + merge_request.reload_code
  88 + merge_request.mark_as_unchecked
  89 + present merge_request, with: Entities::MergeRequest
  90 + else
  91 + not_found!
  92 + end
  93 + end
  94 +
  95 + # Post comment to merge request
  96 + #
  97 + # Parameters:
  98 + # id (required) - The ID or code name of a project
  99 + # merge_request_id (required) - ID of MR
  100 + # note (required) - Text of comment
  101 + # Examples:
  102 + # POST /projects/:id/merge_request/:merge_request_id/comments
  103 + #
  104 + post ":id/merge_request/:merge_request_id/comments" do
  105 + merge_request = user_project.merge_requests.find(params[:merge_request_id])
  106 + note = merge_request.notes.new(note: params[:note], project_id: user_project.id)
  107 + note.author = current_user
  108 +
  109 + if note.save
  110 + present note, with: Entities::Note
  111 + else
  112 + not_found!
  113 + end
  114 + end
  115 +
  116 + end
  117 + end
  118 +end
... ...
spec/requests/api/merge_requests_spec.rb 0 → 100644
... ... @@ -0,0 +1,62 @@
  1 +require "spec_helper"
  2 +
  3 +describe Gitlab::API do
  4 + include ApiHelpers
  5 +
  6 + let(:user) { Factory :user }
  7 + let!(:project) { Factory :project, owner: user }
  8 + let!(:merge_request) { Factory :merge_request, author: user, assignee: user, project: project, title: "Test" }
  9 + before { project.add_access(user, :read) }
  10 +
  11 + describe "GET /projects/:id/merge_requests" do
  12 + context "when unauthenticated" do
  13 + it "should return authentication error" do
  14 + get api("/projects/#{project.code}/merge_requests")
  15 + response.status.should == 401
  16 + end
  17 + end
  18 +
  19 + context "when authenticated" do
  20 + it "should return an array of merge_requests" do
  21 + get api("/projects/#{project.code}/merge_requests", user)
  22 + response.status.should == 200
  23 + json_response.should be_an Array
  24 + json_response.first['title'].should == merge_request.title
  25 + end
  26 + end
  27 + end
  28 +
  29 + describe "GET /projects/:id/merge_request/:merge_request_id" do
  30 + it "should return merge_request" do
  31 + get api("/projects/#{project.code}/merge_request/#{merge_request.id}", user)
  32 + response.status.should == 200
  33 + json_response['title'].should == merge_request.title
  34 + end
  35 + end
  36 +
  37 + describe "POST /projects/:id/merge_requests" do
  38 + it "should return merge_request" do
  39 + post api("/projects/#{project.code}/merge_requests", user),
  40 + title: 'Test merge_request', source_branch: "stable", target_branch: "master", author: user
  41 + response.status.should == 201
  42 + json_response['title'].should == 'Test merge_request'
  43 + end
  44 + end
  45 +
  46 + describe "PUT /projects/:id/merge_request/:merge_request_id" do
  47 + it "should return merge_request" do
  48 + put api("/projects/#{project.code}/merge_request/#{merge_request.id}", user), title: "New title"
  49 + response.status.should == 200
  50 + json_response['title'].should == 'New title'
  51 + end
  52 + end
  53 +
  54 + describe "POST /projects/:id/merge_request/:merge_request_id/comments" do
  55 + it "should return comment" do
  56 + post api("/projects/#{project.code}/merge_request/#{merge_request.id}/comments", user), note: "My comment"
  57 + response.status.should == 201
  58 + json_response['note'].should == 'My comment'
  59 + end
  60 + end
  61 +
  62 +end
... ...