From ac072132b8f0e36badf297208a5964109dbed126 Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
Date: Fri, 12 Aug 2016 14:44:49 +0300
Subject: [PATCH] Add single merge request diff API endpoint

Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
---
 doc/api/merge_requests.md                     | 72 +++++++++++--------
 lib/api/entities.rb                           |  2 +
 lib/api/merge_request_diffs.rb                | 19 +++++
 spec/requests/api/merge_request_diffs_spec.rb | 17 +++++
 4 files changed, 81 insertions(+), 29 deletions(-)

diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index 0c06cfcd876..130488bf7c1 100644
--- a/doc/api/merge_requests.md
+++ b/doc/api/merge_requests.md
@@ -916,6 +916,48 @@ Example response:
 
 ```json
 [{
+  "id": 110,
+  "head_commit_sha": "33e2ee8579fda5bc36accc9c6fbd0b4fefda9e30",
+  "base_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd",
+  "start_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd",
+  "created_at": "2016-07-26T14:44:48.926Z",
+  "merge_request_id": 105,
+  "state": "collected",
+  "real_size": "1"
+}, {
+  "id": 108,
+  "head_commit_sha": "3eed087b29835c48015768f839d76e5ea8f07a24",
+  "base_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd",
+  "start_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd",
+  "created_at": "2016-07-25T14:21:33.028Z",
+  "merge_request_id": 105,
+  "state": "collected",
+  "real_size": "1"
+}]
+```
+
+## Get a single MR diff version
+
+Get a single merge request diff version.
+
+```
+GET /projects/:id/merge_requests/:merge_request_id/versions/:version_id
+```
+
+| Attribute | Type    | Required | Description           |
+| --------- | ------- | -------- | --------------------- |
+| `id`      | String  | yes      | The ID of the project |
+| `merge_request_id` | integer | yes | The ID of the merge request |
+| `version_id` | integer | yes | The ID of the merge request diff version |
+
+```bash
+curl -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/1/merge_requests/1/versions/1
+```
+
+Example response:
+
+```json
+{
   "id": 110,
   "head_commit_sha": "33e2ee8579fda5bc36accc9c6fbd0b4fefda9e30",
   "base_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd",
@@ -959,33 +1001,5 @@ Example response:
     "renamed_file": false,
     "deleted_file": false
   }]
-}, {
-  "id": 108,
-  "head_commit_sha": "3eed087b29835c48015768f839d76e5ea8f07a24",
-  "base_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd",
-  "start_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd",
-  "created_at": "2016-07-25T14:21:33.028Z",
-  "merge_request_id": 105,
-  "state": "collected",
-  "real_size": "1",
-  "commits": [{
-    "id": "3eed087b29835c48015768f839d76e5ea8f07a24",
-    "short_id": "3eed087b",
-    "title": "Add license",
-    "author_name": "Administrator",
-    "author_email": "admin@example.com",
-    "created_at": "2016-07-25T17:21:20.000+03:00",
-    "message": "Add license"
-  }],
-  "diffs": [{
-    "old_path": "LICENSE",
-    "new_path": "LICENSE",
-    "a_mode": "0",
-    "b_mode": "100644",
-    "diff": "--- /dev/null\n+++ b/LICENSE\n@@ -0,0 +1,21 @@\n+The MIT License (MIT)\n+\n+Copyright (c) 2016 Administrator\n+\n+Permission is hereby granted, free of charge, to any person obtaining a copy\n+of this software and associated documentation files (the \"Software\"), to deal\n+in the Software without restriction, including without limitation the rights\n+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n+copies of the Software, and to permit persons to whom the Software is\n+furnished to do so, subject to the following conditions:\n+\n+The above copyright notice and this permission notice shall be included in all\n+copies or substantial portions of the Software.\n+\n+THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n+SOFTWARE.\n",
-    "new_file": true,
-    "renamed_file": false,
-    "deleted_file": false
-  }]
-}]
+}
 ```
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index af069063f0c..f582b2ce250 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -231,7 +231,9 @@ module API
     class MergeRequestDiff < Grape::Entity
       expose :id, :head_commit_sha, :base_commit_sha, :start_commit_sha,
         :created_at, :merge_request_id, :state, :real_size
+    end
 
+    class MergeRequestDiffFull < MergeRequestDiff
       expose :commits, using: Entities::RepoCommit
 
       expose :diffs, using: Entities::RepoDiff do |compare, _|
diff --git a/lib/api/merge_request_diffs.rb b/lib/api/merge_request_diffs.rb
index a2f92f81107..07435d78468 100644
--- a/lib/api/merge_request_diffs.rb
+++ b/lib/api/merge_request_diffs.rb
@@ -21,6 +21,25 @@ module API
         authorize! :read_merge_request, merge_request
         present merge_request.merge_request_diffs, with: Entities::MergeRequestDiff
       end
+
+      desc 'Get a single merge request diff version' do
+        detail 'This feature was introduced in GitLab 8.12.'
+        success Entities::MergeRequestDiffFull
+      end
+
+      params do
+        requires :id, type: String, desc: 'The ID of a project'
+        requires :merge_request_id, type: Integer, desc: 'The ID of a merge request'
+        requires :version_id, type: Integer, desc: 'The ID of a merge request diff version'
+      end
+
+      get ":id/merge_requests/:merge_request_id/versions/:version_id" do
+        merge_request = user_project.merge_requests.
+          find(params[:merge_request_id])
+
+        authorize! :read_merge_request, merge_request
+        present merge_request.merge_request_diffs.find(params[:version_id]), with: Entities::MergeRequestDiffFull
+      end
     end
   end
 end
diff --git a/spec/requests/api/merge_request_diffs_spec.rb b/spec/requests/api/merge_request_diffs_spec.rb
index db076b4b9a5..8f1e5ac9891 100644
--- a/spec/requests/api/merge_request_diffs_spec.rb
+++ b/spec/requests/api/merge_request_diffs_spec.rb
@@ -29,4 +29,21 @@ describe API::API, 'MergeRequestDiffs', api: true  do
       expect(response).to have_http_status(404)
     end
   end
+
+  describe 'GET /projects/:id/merge_requests/:merge_request_id/versions/:version_id' do
+    context 'valid merge request' do
+      before { get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/versions/#{merge_request_diff.id}", user) }
+      let(:merge_request_diff) { merge_request.merge_request_diffs.first }
+
+      it { expect(response.status).to eq 200 }
+      it { expect(json_response['id']).to eq(merge_request_diff.id) }
+      it { expect(json_response['head_commit_sha']).to eq(merge_request_diff.head_commit_sha) }
+      it { expect(json_response['diffs'].size).to eq(merge_request_diff.diffs.size) }
+    end
+
+    it 'returns a 404 when merge_request_id not found' do
+      get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/versions/999", user)
+      expect(response).to have_http_status(404)
+    end
+  end
 end
-- 
2.30.9