Commit c3d09683 authored by Max Woolf's avatar Max Woolf

Merge branch '332587-constraint-status-check-branches' into 'master'

Constraint external status checks to protected branches

See merge request gitlab-org/gitlab!63422
parents ee0695bc d808ea96
...@@ -8,6 +8,11 @@ module MergeRequests ...@@ -8,6 +8,11 @@ module MergeRequests
ignore_column :external_approval_rule_id, remove_with: '14.3', remove_after: '2021-09-22' ignore_column :external_approval_rule_id, remove_with: '14.3', remove_after: '2021-09-22'
scope :with_api_entity_associations, -> { preload(:protected_branches) } scope :with_api_entity_associations, -> { preload(:protected_branches) }
scope :applicable_to_branch, ->(branch) do
includes(:protected_branches)
.references(:protected_branches)
.where('protected_branches.id IS NULL OR protected_branches.name = ?', branch)
end
belongs_to :project belongs_to :project
has_and_belongs_to_many :protected_branches has_and_belongs_to_many :protected_branches
...@@ -16,6 +21,8 @@ module MergeRequests ...@@ -16,6 +21,8 @@ module MergeRequests
validates :name, uniqueness: { scope: :project_id }, presence: true validates :name, uniqueness: { scope: :project_id }, presence: true
def async_execute(data) def async_execute(data)
return unless protected_branches.none? || protected_branches.by_name(data[:object_attributes][:target_branch]).any?
ApprovalRules::ExternalApprovalRulePayloadWorker.perform_async(self.id, payload_data(data)) ApprovalRules::ExternalApprovalRulePayloadWorker.perform_async(self.id, payload_data(data))
end end
......
...@@ -135,7 +135,7 @@ module API ...@@ -135,7 +135,7 @@ module API
merge_request = find_merge_request_with_access(params[:merge_request_iid], :approve_merge_request) merge_request = find_merge_request_with_access(params[:merge_request_iid], :approve_merge_request)
present(paginate(merge_request.project.external_status_checks.all), with: Entities::MergeRequests::StatusCheck, merge_request: merge_request, sha: merge_request.source_branch_sha) present(paginate(user_project.external_status_checks.applicable_to_branch(merge_request.target_branch)), with: Entities::MergeRequests::StatusCheck, merge_request: merge_request, sha: merge_request.source_branch_sha)
end end
end end
end end
......
...@@ -22,6 +22,62 @@ RSpec.describe MergeRequests::ExternalStatusCheck, type: :model do ...@@ -22,6 +22,62 @@ RSpec.describe MergeRequests::ExternalStatusCheck, type: :model do
end end
end end
describe 'applicable_to_branch' do
let_it_be(:merge_request) { create(:merge_request) }
let_it_be(:check_belonging_to_different_project) { create(:external_status_check) }
let_it_be(:check_with_no_protected_branches) { create(:external_status_check, project: merge_request.project, protected_branches: []) }
let_it_be(:check_with_applicable_protected_branches) { create(:external_status_check, project: merge_request.project, protected_branches: [create(:protected_branch, name: merge_request.target_branch)]) }
let_it_be(:check_with_non_applicable_protected_branches) { create(:external_status_check, project: merge_request.project, protected_branches: [create(:protected_branch, name: 'testbranch')]) }
it 'returns the correct collection of checks' do
expect(merge_request.project.external_status_checks.applicable_to_branch(merge_request.target_branch)).to contain_exactly(check_with_no_protected_branches, check_with_applicable_protected_branches)
end
end
describe 'async_execute' do
let_it_be(:merge_request) { create(:merge_request) }
let(:data) do
{
object_attributes: {
target_branch: 'test'
}
}
end
subject { check.async_execute(data) }
context 'when list of protected branches is empty' do
let_it_be(:check) { create(:external_status_check, project: merge_request.project) }
it 'enqueues the status check' do
expect(ApprovalRules::ExternalApprovalRulePayloadWorker).to receive(:perform_async).once
subject
end
end
context 'when data target branch matches a protected branch' do
let_it_be(:check) { create(:external_status_check, project: merge_request.project, protected_branches: [create(:protected_branch, name: 'test')]) }
it 'enqueues the status check' do
expect(ApprovalRules::ExternalApprovalRulePayloadWorker).to receive(:perform_async).once
subject
end
end
context 'when data target branch does not match a protected branch' do
let_it_be(:check) { create(:external_status_check, project: merge_request.project, protected_branches: [create(:protected_branch, name: 'new-branch')]) }
it 'does not enqueue the status check' do
expect(ApprovalRules::ExternalApprovalRulePayloadWorker).to receive(:perform_async).never
subject
end
end
end
describe 'approved?' do describe 'approved?' do
let_it_be(:rule) { create(:external_status_check) } let_it_be(:rule) { create(:external_status_check) }
let_it_be(:merge_request) { create(:merge_request) } let_it_be(:merge_request) { create(:merge_request) }
......
...@@ -51,6 +51,8 @@ RSpec.describe API::StatusChecks do ...@@ -51,6 +51,8 @@ RSpec.describe API::StatusChecks do
end end
context 'when merge request has received status check responses' do context 'when merge request has received status check responses' do
let!(:non_applicable_check) { create(:external_status_check, project: project, protected_branches: [create(:protected_branch, name: 'different-branch')]) }
let!(:branch_specific_check) { create(:external_status_check, project: project, protected_branches: [create(:protected_branch, name: merge_request.target_branch)]) }
let!(:status_check_response) { create(:status_check_response, external_status_check: rule, merge_request: merge_request, sha: sha) } let!(:status_check_response) { create(:status_check_response, external_status_check: rule, merge_request: merge_request, sha: sha) }
it 'returns a 200' do it 'returns a 200' do
...@@ -62,7 +64,7 @@ RSpec.describe API::StatusChecks do ...@@ -62,7 +64,7 @@ RSpec.describe API::StatusChecks do
it 'returns the total number of status checks for the MRs project' do it 'returns the total number of status checks for the MRs project' do
subject subject
expect(json_response.size).to eq(2) expect(json_response.size).to eq(3)
end end
it 'has the correct status values' do it 'has the correct status values' do
...@@ -70,6 +72,7 @@ RSpec.describe API::StatusChecks do ...@@ -70,6 +72,7 @@ RSpec.describe API::StatusChecks do
expect(json_response[0]["status"]).to eq('approved') expect(json_response[0]["status"]).to eq('approved')
expect(json_response[1]["status"]).to eq('pending') expect(json_response[1]["status"]).to eq('pending')
expect(json_response[2]["status"]).to eq('pending')
end end
end end
end end
......
...@@ -19,7 +19,6 @@ RSpec.describe MergeRequests::BaseService do ...@@ -19,7 +19,6 @@ RSpec.describe MergeRequests::BaseService do
subject { MergeRequests::CreateService.new(project: project, current_user: project.owner, params: params) } subject { MergeRequests::CreateService.new(project: project, current_user: project.owner, params: params) }
context 'project has external status checks' do
let_it_be(:status_checks) { create_list(:external_status_check, 3, project: project) } let_it_be(:status_checks) { create_list(:external_status_check, 3, project: project) }
it 'fires the correct number of compliance hooks' do it 'fires the correct number of compliance hooks' do
...@@ -27,7 +26,6 @@ RSpec.describe MergeRequests::BaseService do ...@@ -27,7 +26,6 @@ RSpec.describe MergeRequests::BaseService do
subject.execute subject.execute
end end
end
describe '#filter_params' do describe '#filter_params' do
let(:params_filtering_service) { double(:params_filtering_service) } let(:params_filtering_service) { double(:params_filtering_service) }
......
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