Commit 56c07c5e authored by Phil Hughes's avatar Phil Hughes

Merge branch '1593-limited-approvers' into 'master'

restrict individual approvers to project members

Closes #1593

See merge request !1691
parents 6116d1f3 8c30dac3
...@@ -23,28 +23,29 @@ export default class ApproversSelect { ...@@ -23,28 +23,29 @@ export default class ApproversSelect {
$(document).on('click', '.js-approver-remove', e => ApproversSelect.removeApprover(e)); $(document).on('click', '.js-approver-remove', e => ApproversSelect.removeApprover(e));
} }
static getApprovers(fieldName, selector, key) { static getApprovers(fieldName, approverList) {
const input = $(`[name="${fieldName}"]`); const input = $(`[name="${fieldName}"]`);
const existingApprovers = $(approverList).map((i, el) =>
const existingApprovers = $(selector).map((i, el) =>
parseInt($(el).data('id'), 10), parseInt($(el).data('id'), 10),
); );
const selectedApprovers = input.val() const selectedApprovers = input.val()
.split(',') .split(',')
.filter(val => val !== ''); .filter(val => val !== '');
const approvers = { return [...existingApprovers, ...selectedApprovers];
[key]: [...existingApprovers, ...selectedApprovers],
};
return approvers;
} }
fetchGroups(term) { fetchGroups(term) {
const options = ApproversSelect.getApprovers(this.fieldNames[1], '.js-approver-group', 'skip_groups'); const options = {
skip_groups: ApproversSelect.getApprovers(this.fieldNames[1], '.js-approver-group'),
};
return Api.groups(term, options); return Api.groups(term, options);
} }
fetchUsers(term) { fetchUsers(term) {
const options = ApproversSelect.getApprovers(this.fieldNames[0], '.js-approver', 'skip_users'); const options = {
skip_users: ApproversSelect.getApprovers(this.fieldNames[0], '.js-approver'),
project_id: $('#project_id').val(),
};
return Api.users(term, options); return Api.users(term, options);
} }
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
.col-sm-10 .col-sm-10
- author = issuable.author || current_user - author = issuable.author || current_user
- skip_users = issuable.all_approvers_including_groups + [author] - skip_users = issuable.all_approvers_including_groups + [author]
= users_select_tag("merge_request[approver_ids]", multiple: true, class: 'input-large', scope: :all, email_user: true, skip_users: skip_users) = users_select_tag("merge_request[approver_ids]", multiple: true, class: 'input-large', email_user: true, skip_users: skip_users)
.help-block .help-block
This merge request must be approved by these users. This merge request must be approved by these users.
You can override the project settings by setting your own list of approvers. You can override the project settings by setting your own list of approvers.
......
...@@ -11,7 +11,7 @@ merge request in a project. ...@@ -11,7 +11,7 @@ merge request in a project.
## Configuring Approvals ## Configuring Approvals
You can configure the approvals in the project settings, under merge requests. You can configure the approvals in the project settings, under merge requests.
To enable it, set **Approvals required** to 1 or higher and search for the To enable it, turn on **Activate merge request approvals** and search for the
users you want to be approvers. users you want to be approvers.
![Merge Request Approvals in Project Settings](img/approvals_settings.png) ![Merge Request Approvals in Project Settings](img/approvals_settings.png)
...@@ -19,8 +19,6 @@ users you want to be approvers. ...@@ -19,8 +19,6 @@ users you want to be approvers.
### Approvals Required ### Approvals Required
This sets the amount of approvals required before being able to merge a merge request. This sets the amount of approvals required before being able to merge a merge request.
At 0, this disables the feature. Any value above 0 requires that amount of different
users to approve the merge request.
The number of approvers can be higher than the required approvals. The number of approvers can be higher than the required approvals.
......
...@@ -31,6 +31,7 @@ feature 'Merge request approvals', js: true, feature: true do ...@@ -31,6 +31,7 @@ feature 'Merge request approvals', js: true, feature: true do
context 'when creating an MR' do context 'when creating an MR' do
let(:other_user) { create(:user) } let(:other_user) { create(:user) }
let(:non_member) { create(:user) }
before do before do
project.team << [user, :developer] project.team << [user, :developer]
...@@ -49,6 +50,10 @@ feature 'Merge request approvals', js: true, feature: true do ...@@ -49,6 +50,10 @@ feature 'Merge request approvals', js: true, feature: true do
it 'does not allow setting the current user as an approver' do it 'does not allow setting the current user as an approver' do
expect(find('.select2-results')).not_to have_content(user.name) expect(find('.select2-results')).not_to have_content(user.name)
end end
it 'filters non members from approvers list' do
expect(find('.select2-results')).not_to have_content(non_member.name)
end
end end
context "Group approvers" do context "Group approvers" do
......
...@@ -7,13 +7,14 @@ describe 'Project settings > [EE] Merge Requests', feature: true, js: true do ...@@ -7,13 +7,14 @@ describe 'Project settings > [EE] Merge Requests', feature: true, js: true do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:empty_project, approvals_before_merge: 1) } let(:project) { create(:empty_project, approvals_before_merge: 1) }
let(:group) { create(:group) } let(:group) { create(:group) }
let(:approver) { create(:user) } let(:group_member) { create(:user) }
let(:non_member) { create(:user) }
before do before do
login_as(user) login_as(user)
project.team << [user, :master] project.team << [user, :master]
group.add_developer(approver)
group.add_developer(user) group.add_developer(user)
group.add_developer(group_member)
end end
scenario 'adds approver' do scenario 'adds approver' do
...@@ -28,6 +29,18 @@ describe 'Project settings > [EE] Merge Requests', feature: true, js: true do ...@@ -28,6 +29,18 @@ describe 'Project settings > [EE] Merge Requests', feature: true, js: true do
click_button 'Add' click_button 'Add'
expect(find('.js-current-approvers')).to have_content(user.name) expect(find('.js-current-approvers')).to have_content(user.name)
find('.js-select-user-and-group').click
expect(find('.select2-results')).not_to have_content(user.name)
end
scenario 'filter approvers' do
visit edit_project_path(project)
find('.js-select-user-and-group').click
expect(find('.select2-results')).to have_content(user.name)
expect(find('.select2-results')).not_to have_content(non_member.name)
end end
scenario 'adds approver group' do scenario 'adds approver group' do
......
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