From c2b622b2a40bdf01f3f71a8adf9aff31d535149f Mon Sep 17 00:00:00 2001
From: Chantal Rollison <crollison@gitlab.com>
Date: Tue, 26 Jun 2018 12:30:29 -0700
Subject: [PATCH] Add locked state to merge request API

---
 app/finders/issuable_finder.rb                 |  4 +++-
 app/finders/merge_requests_finder.rb           |  2 +-
 .../unreleased/cr-add-locked-state-to-MR.yml   |  5 +++++
 doc/api/merge_requests.md                      | 12 ++++++------
 lib/api/merge_requests.rb                      |  4 ++--
 spec/finders/merge_requests_finder_spec.rb     | 14 +++++++++++---
 spec/requests/api/merge_requests_spec.rb       | 15 ++++++++++++---
 .../requests/api/merge_requests_list.rb        | 18 +++++++++---------
 8 files changed, 49 insertions(+), 25 deletions(-)
 create mode 100644 changelogs/unreleased/cr-add-locked-state-to-MR.yml

diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb
index 5d5f72c4d86..6fdfd964fca 100644
--- a/app/finders/issuable_finder.rb
+++ b/app/finders/issuable_finder.rb
@@ -7,7 +7,7 @@
 #   current_user - which user use
 #   params:
 #     scope: 'created_by_me' or 'assigned_to_me' or 'all'
-#     state: 'opened' or 'closed' or 'all'
+#     state: 'opened' or 'closed' or 'locked' or 'all'
 #     group_id: integer
 #     project_id: integer
 #     milestone_title: string
@@ -311,6 +311,8 @@ class IssuableFinder
       items.respond_to?(:merged) ? items.merged : items.closed
     when 'opened'
       items.opened
+    when 'locked'
+      items.where(state: 'locked')
     else
       items
     end
diff --git a/app/finders/merge_requests_finder.rb b/app/finders/merge_requests_finder.rb
index 8d84ed4bdfb..40089c082c1 100644
--- a/app/finders/merge_requests_finder.rb
+++ b/app/finders/merge_requests_finder.rb
@@ -6,7 +6,7 @@
 #   current_user - which user use
 #   params:
 #     scope: 'created_by_me' or 'assigned_to_me' or 'all'
-#     state: 'open', 'closed', 'merged', or 'all'
+#     state: 'open', 'closed', 'merged', 'locked', or 'all'
 #     group_id: integer
 #     project_id: integer
 #     milestone_title: string
diff --git a/changelogs/unreleased/cr-add-locked-state-to-MR.yml b/changelogs/unreleased/cr-add-locked-state-to-MR.yml
new file mode 100644
index 00000000000..f290ddc0b87
--- /dev/null
+++ b/changelogs/unreleased/cr-add-locked-state-to-MR.yml
@@ -0,0 +1,5 @@
+---
+title: Adds the `locked` state to the merge request API so that it can be used as a search filter.
+merge_request: 20186
+author:
+type: fixed
diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index da74045b702..2057ed3588a 100644
--- a/doc/api/merge_requests.md
+++ b/doc/api/merge_requests.md
@@ -11,7 +11,7 @@ default it returns only merge requests created by the current user. To
 get all merge requests, use parameter `scope=all`.
 
 The `state` parameter can be used to get only merge requests with a
-given state (`opened`, `closed`, or `merged`) or all of them (`all`).
+given state (`opened`, `closed`, `locked`, or `merged`) or all of them (`all`). It should be noted that when searching by `locked` it will mostly return no results as it is a short-lived, transitional state.
 The pagination parameters `page` and `per_page` can be used to
 restrict the list of merge requests.
 
@@ -35,7 +35,7 @@ Parameters:
 
 | Attribute           | Type     | Required | Description                                                                                                            |
 | ------------------- | -------- | -------- | ---------------------------------------------------------------------------------------------------------------------- |
-| `state`             | string   | no       | Return all merge requests or just those that are `opened`, `closed`, or `merged`                                       |
+| `state`             | string   | no       | Return all merge requests or just those that are `opened`, `closed`, `locked`, or `merged`                                       |
 | `order_by`          | string   | no       | Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at`                                |
 | `sort`              | string   | no       | Return requests sorted in `asc` or `desc` order. Default is `desc`                                                     |
 | `milestone`         | string   | no       | Return merge requests for a specific milestone                                                                         |
@@ -122,7 +122,7 @@ Parameters:
 ## List project merge requests
 
 Get all merge requests for this project.
-The `state` parameter can be used to get only merge requests with a given state (`opened`, `closed`, or `merged`) or all of them (`all`).
+The `state` parameter can be used to get only merge requests with a given state (`opened`, `closed`, `locked`, or `merged`) or all of them (`all`).
 The pagination parameters `page` and `per_page` can be used to restrict the list of merge requests.
 
 ```
@@ -155,7 +155,7 @@ Parameters:
 | ------------------- | -------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------ |
 | `id`                | integer        | yes      | The ID of a project                                                                                                            |
 | `iids[]`            | Array[integer] | no       | Return the request having the given `iid`                                                                                      |
-| `state`             | string         | no       | Return all merge requests or just those that are `opened`, `closed`, or `merged`                                               |
+| `state`             | string         | no       | Return all merge requests or just those that are `opened`, `closed`, `locked`, or `merged`                                               |
 | `order_by`          | string         | no       | Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at`                                        |
 | `sort`              | string         | no       | Return requests sorted in `asc` or `desc` order. Default is `desc`                                                             |
 | `milestone`         | string         | no       | Return merge requests for a specific milestone                                                                                 |
@@ -243,7 +243,7 @@ Parameters:
 ## List group merge requests
 
 Get all merge requests for this group and its subgroups.
-The `state` parameter can be used to get only merge requests with a given state (`opened`, `closed`, or `merged`) or all of them (`all`).
+The `state` parameter can be used to get only merge requests with a given state (`opened`, `closed`, `locked`, or `merged`) or all of them (`all`).
 The pagination parameters `page` and `per_page` can be used to restrict the list of merge requests.
 
 ```
@@ -262,7 +262,7 @@ Parameters:
 | Attribute           | Type           | Required | Description                                                                                                                    |
 | ------------------- | -------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------ |
 | `id`                | integer        | yes      | The ID of a group                                                                                                           |
-| `state`             | string         | no       | Return all merge requests or just those that are `opened`, `closed`, or `merged`                                               |
+| `state`             | string         | no       | Return all merge requests or just those that are `opened`, `closed`, `locked`, or `merged`                                               |
 | `order_by`          | string         | no       | Return merge requests ordered by `created_at` or `updated_at` fields. Default is `created_at`                                        |
 | `sort`              | string         | no       | Return merge requests sorted in `asc` or `desc` order. Default is `desc`                                                             |
 | `milestone`         | string         | no       | Return merge requests for a specific milestone                                                                                 |
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index af7d2471b34..0f46bc4c98e 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -72,8 +72,8 @@ module API
       end
 
       params :merge_requests_params do
-        optional :state, type: String, values: %w[opened closed merged all], default: 'all',
-                         desc: 'Return opened, closed, merged, or all merge requests'
+        optional :state, type: String, values: %w[opened closed locked merged all], default: 'all',
+                         desc: 'Return opened, closed, locked, merged, or all merge requests'
         optional :order_by, type: String, values: %w[created_at updated_at], default: 'created_at',
                             desc: 'Return merge requests ordered by `created_at` or `updated_at` fields.'
         optional :sort, type: String, values: %w[asc desc], default: 'desc',
diff --git a/spec/finders/merge_requests_finder_spec.rb b/spec/finders/merge_requests_finder_spec.rb
index c8a43ddf410..669ec602f11 100644
--- a/spec/finders/merge_requests_finder_spec.rb
+++ b/spec/finders/merge_requests_finder_spec.rb
@@ -19,7 +19,7 @@ describe MergeRequestsFinder do
 
   let!(:merge_request1) { create(:merge_request, :simple, author: user, source_project: project2, target_project: project1) }
   let!(:merge_request2) { create(:merge_request, :conflict, author: user, source_project: project2, target_project: project1, state: 'closed') }
-  let!(:merge_request3) { create(:merge_request, :simple, author: user, source_project: project2, target_project: project2) }
+  let!(:merge_request3) { create(:merge_request, :simple, author: user, source_project: project2, target_project: project2, state: 'locked') }
   let!(:merge_request4) { create(:merge_request, :simple, author: user, source_project: project3, target_project: project3) }
   let!(:merge_request5) { create(:merge_request, :simple, author: user, source_project: project4, target_project: project4) }
 
@@ -35,7 +35,7 @@ describe MergeRequestsFinder do
     it 'filters by scope' do
       params = { scope: 'authored', state: 'opened' }
       merge_requests = described_class.new(user, params).execute
-      expect(merge_requests.size).to eq(4)
+      expect(merge_requests.size).to eq(3)
     end
 
     it 'filters by project' do
@@ -90,6 +90,14 @@ describe MergeRequestsFinder do
       expect(merge_requests).to contain_exactly(merge_request2)
     end
 
+    it 'filters by state' do
+      params = { state: 'locked' }
+
+      merge_requests = described_class.new(user, params).execute
+
+      expect(merge_requests).to contain_exactly(merge_request3)
+    end
+
     context 'filtering by group milestone' do
       let!(:group) { create(:group, :public) }
       let(:group_milestone) { create(:milestone, group: group) }
@@ -199,7 +207,7 @@ describe MergeRequestsFinder do
     it 'returns the number of rows for the default state' do
       finder = described_class.new(user)
 
-      expect(finder.row_count).to eq(4)
+      expect(finder.row_count).to eq(3)
     end
 
     it 'returns the number of rows for a given state' do
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index d4ebfc3f782..eba39bb6ccc 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -14,6 +14,7 @@ describe API::MergeRequests do
   let!(:merge_request) { create(:merge_request, :simple, milestone: milestone1, author: user, assignee: user, source_project: project, target_project: project, title: "Test", created_at: base_time) }
   let!(:merge_request_closed) { create(:merge_request, state: "closed", milestone: milestone1, author: user, assignee: user, source_project: project, target_project: project, title: "Closed test", created_at: base_time + 1.second) }
   let!(:merge_request_merged) { create(:merge_request, state: "merged", author: user, assignee: user, source_project: project, target_project: project, title: "Merged test", created_at: base_time + 2.seconds, merge_commit_sha: '9999999999999999999999999999999999999999') }
+  let!(:merge_request_locked) { create(:merge_request, state: "locked", milestone: milestone1, author: user, assignee: user, source_project: project, target_project: project, title: "Locked test", created_at: base_time + 1.second) }
   let!(:note)       { create(:note_on_merge_request, author: user, project: project, noteable: merge_request, note: "a comment on a MR") }
   let!(:note2)      { create(:note_on_merge_request, author: user, project: project, noteable: merge_request, note: "another comment on a MR") }
   let!(:label) do
@@ -85,7 +86,7 @@ describe API::MergeRequests do
 
         get api('/merge_requests', user), scope: :all
 
-        expect_response_contain_exactly(merge_request2, merge_request_merged, merge_request_closed, merge_request)
+        expect_response_contain_exactly(merge_request2, merge_request_merged, merge_request_closed, merge_request, merge_request_locked)
         expect(json_response.map { |mr| mr['id'] }).not_to include(merge_request3.id)
       end
 
@@ -158,7 +159,7 @@ describe API::MergeRequests do
         it 'returns merge requests with the given source branch' do
           get api('/merge_requests', user), source_branch: merge_request_closed.source_branch, state: 'all'
 
-          expect_response_contain_exactly(merge_request_closed, merge_request_merged)
+          expect_response_contain_exactly(merge_request_closed, merge_request_merged, merge_request_locked)
         end
       end
 
@@ -166,7 +167,7 @@ describe API::MergeRequests do
         it 'returns merge requests with the given target branch' do
           get api('/merge_requests', user), target_branch: merge_request_closed.target_branch, state: 'all'
 
-          expect_response_contain_exactly(merge_request_closed, merge_request_merged)
+          expect_response_contain_exactly(merge_request_closed, merge_request_merged, merge_request_locked)
         end
       end
 
@@ -219,6 +220,14 @@ describe API::MergeRequests do
           expect_response_ordered_exactly(merge_request)
         end
       end
+
+      context 'state param' do
+        it 'returns merge requests with the given state' do
+          get api('/merge_requests', user), state: 'locked'
+
+          expect_response_contain_exactly(merge_request_locked)
+        end
+      end
     end
   end
 
diff --git a/spec/support/shared_examples/requests/api/merge_requests_list.rb b/spec/support/shared_examples/requests/api/merge_requests_list.rb
index d5e22b8cb56..a401f7541f0 100644
--- a/spec/support/shared_examples/requests/api/merge_requests_list.rb
+++ b/spec/support/shared_examples/requests/api/merge_requests_list.rb
@@ -29,7 +29,7 @@ shared_examples 'merge requests list' do
       expect(response).to have_gitlab_http_status(200)
       expect(response).to include_pagination_headers
       expect(json_response).to be_an Array
-      expect(json_response.length).to eq(3)
+      expect(json_response.length).to eq(4)
       expect(json_response.last['title']).to eq(merge_request.title)
       expect(json_response.last).to have_key('web_url')
       expect(json_response.last['sha']).to eq(merge_request.diff_head_sha)
@@ -53,7 +53,7 @@ shared_examples 'merge requests list' do
       expect(response).to include_pagination_headers
       expect(json_response.last.keys).to match_array(%w(id iid title web_url created_at description project_id state updated_at))
       expect(json_response).to be_an Array
-      expect(json_response.length).to eq(3)
+      expect(json_response.length).to eq(4)
       expect(json_response.last['iid']).to eq(merge_request.iid)
       expect(json_response.last['title']).to eq(merge_request.title)
       expect(json_response.last).to have_key('web_url')
@@ -70,7 +70,7 @@ shared_examples 'merge requests list' do
       expect(response).to have_gitlab_http_status(200)
       expect(response).to include_pagination_headers
       expect(json_response).to be_an Array
-      expect(json_response.length).to eq(3)
+      expect(json_response.length).to eq(4)
       expect(json_response.last['title']).to eq(merge_request.title)
     end
 
@@ -216,7 +216,7 @@ shared_examples 'merge requests list' do
         expect(response).to have_gitlab_http_status(200)
         expect(response).to include_pagination_headers
         expect(json_response).to be_an Array
-        expect(json_response.length).to eq(3)
+        expect(json_response.length).to eq(4)
         response_dates = json_response.map { |merge_request| merge_request['created_at'] }
         expect(response_dates).to eq(response_dates.sort)
       end
@@ -229,7 +229,7 @@ shared_examples 'merge requests list' do
         expect(response).to have_gitlab_http_status(200)
         expect(response).to include_pagination_headers
         expect(json_response).to be_an Array
-        expect(json_response.length).to eq(3)
+        expect(json_response.length).to eq(4)
         response_dates = json_response.map { |merge_request| merge_request['created_at'] }
         expect(response_dates).to eq(response_dates.sort.reverse)
       end
@@ -242,7 +242,7 @@ shared_examples 'merge requests list' do
         expect(response).to have_gitlab_http_status(200)
         expect(response).to include_pagination_headers
         expect(json_response).to be_an Array
-        expect(json_response.length).to eq(3)
+        expect(json_response.length).to eq(4)
         response_dates = json_response.map { |merge_request| merge_request['updated_at'] }
         expect(response_dates).to eq(response_dates.sort.reverse)
       end
@@ -255,7 +255,7 @@ shared_examples 'merge requests list' do
         expect(response).to have_gitlab_http_status(200)
         expect(response).to include_pagination_headers
         expect(json_response).to be_an Array
-        expect(json_response.length).to eq(3)
+        expect(json_response.length).to eq(4)
         response_dates = json_response.map { |merge_request| merge_request['created_at'] }
         expect(response_dates).to eq(response_dates.sort)
       end
@@ -265,7 +265,7 @@ shared_examples 'merge requests list' do
       it 'returns merge requests with the given source branch' do
         get api(endpoint_path, user), source_branch: merge_request_closed.source_branch, state: 'all'
 
-        expect_response_contain_exactly(merge_request_closed, merge_request_merged)
+        expect_response_contain_exactly(merge_request_closed, merge_request_merged, merge_request_locked)
       end
     end
 
@@ -273,7 +273,7 @@ shared_examples 'merge requests list' do
       it 'returns merge requests with the given target branch' do
         get api(endpoint_path, user), target_branch: merge_request_closed.target_branch, state: 'all'
 
-        expect_response_contain_exactly(merge_request_closed, merge_request_merged)
+        expect_response_contain_exactly(merge_request_closed, merge_request_merged, merge_request_locked)
       end
     end
   end
-- 
2.30.9