Commit aea85351 authored by Timo Furrer's avatar Timo Furrer

Implement API to get single MR rule

This change implements the `GET` API to retrieve a single
Merge Request level rule.

Changelog: added
MR: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/82767
EE: true
parent 0c0c7626
......@@ -776,6 +776,82 @@ GET /projects/:id/merge_requests/:merge_request_iid/approval_rules
]
```
### Get a single merge request level rule
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/82767) in GitLab 14.10.
You can request information about a single merge request approval rule using the following endpoint:
```plaintext
GET /projects/:id/merge_requests/:merge_request_iid/approval_rules/:approval_rule_id
```
**Parameters:**
| Attribute | Type | Required | Description |
|---------------------|---------|----------|------------------------------------------------------------------------------|
| `id` | integer or string | yes | The ID or [URL-encoded path of a project](index.md#namespaced-path-encoding) |
| `merge_request_iid` | integer | yes | The IID of MR |
| `approval_rule_id` | integer | yes | The ID of a approval rule |
```json
{
"id": 1,
"name": "security",
"rule_type": "regular",
"eligible_approvers": [
{
"id": 5,
"name": "John Doe",
"username": "jdoe",
"state": "active",
"avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
"web_url": "http://localhost/jdoe"
},
{
"id": 50,
"name": "Group Member 1",
"username": "group_member_1",
"state": "active",
"avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
"web_url": "http://localhost/group_member_1"
}
],
"approvals_required": 3,
"source_rule": null,
"users": [
{
"id": 5,
"name": "John Doe",
"username": "jdoe",
"state": "active",
"avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
"web_url": "http://localhost/jdoe"
}
],
"groups": [
{
"id": 5,
"name": "group1",
"path": "group1",
"description": "",
"visibility": "public",
"lfs_enabled": false,
"avatar_url": null,
"web_url": "http://localhost/groups/group1",
"request_access_enabled": false,
"full_name": "group1",
"full_path": "group1",
"parent_id": null,
"ldap_cn": null,
"ldap_access": null
}
],
"contains_hidden_groups": false,
"overridden": false
}
```
### Create merge request level rule
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/11877) in GitLab 12.3.
......
......@@ -49,11 +49,24 @@ module API
end
segment ':approval_rule_id' do
desc 'Get merge request approval rule' do
success EE::API::Entities::MergeRequestApprovalRule
end
params do
requires :approval_rule_id, type: Integer, desc: 'The ID of a merge request approval rule'
end
get do
merge_request = find_merge_request_with_access(params[:merge_request_iid])
approval_rule = find_merge_request_approval_rule(merge_request, params[:approval_rule_id])
present approval_rule, with: EE::API::Entities::MergeRequestApprovalRule, current_user: current_user
end
desc 'Update merge request approval rule' do
success EE::API::Entities::MergeRequestApprovalRule
end
params do
requires :approval_rule_id, type: Integer, desc: 'The ID of an approval rule'
requires :approval_rule_id, type: Integer, desc: 'The ID of a merge request approval rule'
optional :name, type: String, desc: 'The name of the approval rule'
optional :approvals_required, type: Integer, desc: 'The number of required approvals for this rule'
optional :user_ids, type: Array[Integer], coerce_with: ::API::Validations::Types::CommaSeparatedToIntegerArray.coerce, desc: 'The user ids for this rule'
......@@ -75,7 +88,7 @@ module API
desc 'Destroy merge request approval rule'
params do
requires :approval_rule_id, type: Integer, desc: 'The ID of an approval_rule'
requires :approval_rule_id, type: Integer, desc: 'The ID of a merge request approval rule'
end
delete do
merge_request = find_merge_request_with_access(params[:merge_request_iid], :update_approvers)
......
......@@ -5,8 +5,8 @@ require 'spec_helper'
RSpec.describe API::MergeRequestApprovalRules do
let_it_be(:user) { create(:user) }
let_it_be(:other_user) { create(:user) }
let_it_be(:project) { create(:project, :public, :repository, creator: user, namespace: user.namespace) }
let(:project) { create(:project, :public, :repository, creator: user, namespace: user.namespace) }
let(:merge_request) { create(:merge_request, author: user, source_project: project, target_project: project) }
shared_examples_for 'a protected API endpoint for merge request approval rule action' do
......@@ -141,6 +141,92 @@ RSpec.describe API::MergeRequestApprovalRules do
end
end
describe 'GET /projects/:id/merge_requests/:merge_request_iid/approval_rules/:approval_rule_id' do
let(:current_user) { other_user }
let(:approver) { create(:user) }
let(:group) { create(:group) }
let(:source_rule) { nil }
let(:users) { [approver] }
let(:groups) { [group] }
let(:approval_rule) do
create(
:approval_merge_request_rule,
merge_request: merge_request,
approval_project_rule: source_rule,
approvals_required: 2,
users: users,
groups: groups
)
end
let(:url) { "/projects/#{project.id}/merge_requests/#{merge_request.iid}/approval_rules/#{approval_rule.id}" }
context 'user cannot read merge request' do
before do
project.project_feature.update!(merge_requests_access_level: ProjectFeature::PRIVATE)
get api(url, other_user)
end
it 'responds with 403' do
expect(response).to have_gitlab_http_status(:forbidden)
end
end
context 'user can read merge request' do
before do
group.add_developer(approver)
merge_request.approvals.create!(user: approver)
get api(url, current_user)
end
it 'matches the response schema' do
expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('public_api/v4/merge_request_approval_rule', dir: 'ee')
expect(json_response['name']).to eq(approval_rule.name)
expect(json_response['approvals_required']).to eq(approval_rule.approvals_required)
expect(json_response['rule_type']).to eq(approval_rule.rule_type)
expect(json_response['section']).to be_nil
expect(json_response['contains_hidden_groups']).to eq(false)
expect(json_response['source_rule']).to be_nil
expect(json_response['eligible_approvers']).to match_array([hash_including('id' => approver.id)])
expect(json_response['users']).to match_array([hash_including('id' => approver.id)])
expect(json_response['groups']).to match_array([hash_including('id' => group.id)])
end
context 'groups contain private groups' do
let(:group) { create(:group, :private) }
context 'current_user cannot see private group' do
it 'hides private group' do
expect(json_response['contains_hidden_groups']).to eq(true)
expect(json_response['groups']).to be_empty
end
end
context 'current_user can see private group' do
let(:current_user) { approver }
it 'shows private group' do
expect(json_response['contains_hidden_groups']).to eq(false)
expect(json_response['groups']).to match_array([hash_including('id' => group.id)])
end
end
end
context 'has existing merge request rule that overrides a project-level rule' do
let(:source_rule) { create(:approval_project_rule, project: project) }
it 'includes source_rule' do
expect(json_response['source_rule']['approvals_required']).to eq(source_rule.approvals_required)
end
end
end
end
describe 'POST /projects/:id/merge_requests/:merge_request_iid/approval_rules' do
let(:current_user) { user }
let(:url) { "/projects/#{project.id}/merge_requests/#{merge_request.iid}/approval_rules" }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment