Commit 1f3f6579 authored by Patrick Steinhardt's avatar Patrick Steinhardt

checks: Add function to convert ChangesAccess to SingleChangeAccesses

There is only a single callsite right now which extracts changes from a
ChangesAccess and converts them into SingleChangeAccesses, which is
inside the ChangesAccess class itself. We're about to convert push rules
such that they can both drive single and bulk push rules, and there
we'll need the same functionality.

Extract the code into a standalone `#single_change_accesses()` function
which can be used to do the conversion.
parent 245ced26
...@@ -76,15 +76,16 @@ module Gitlab ...@@ -76,15 +76,16 @@ module Gitlab
result result
end end
protected def single_change_accesses
@single_changes_accesses ||=
def single_access_checks! changes.map do |change|
# Iterate over all changes to find if user allowed all of them to be applied commits =
changes.each do |change| if change[:newrev].blank? || Gitlab::Git.blank_ref?(change[:newrev])
commits = Gitlab::Lazy.new { commits_for(change[:newrev]) } []
else
Gitlab::Lazy.new { commits_for(change[:newrev]) }
end
# If user does not have access to make at least one change, cancel all
# push by allowing the exception to bubble up
Checks::SingleChangeAccess.new( Checks::SingleChangeAccess.new(
change, change,
user_access: user_access, user_access: user_access,
...@@ -92,7 +93,16 @@ module Gitlab ...@@ -92,7 +93,16 @@ module Gitlab
protocol: protocol, protocol: protocol,
logger: logger, logger: logger,
commits: commits commits: commits
).validate! )
end
end
protected
def single_access_checks!
# Iterate over all changes to find if user allowed all of them to be applied
single_change_accesses.each do |single_change_access|
single_change_access.validate!
end end
end end
......
...@@ -174,6 +174,101 @@ RSpec.describe Gitlab::Checks::ChangesAccess do ...@@ -174,6 +174,101 @@ RSpec.describe Gitlab::Checks::ChangesAccess do
end end
end end
describe '#single_change_accesses' do
let(:commits_for) { {} }
let(:expected_accesses) { [] }
shared_examples '#single_change_access' do
before do
commits_for.each do |id, commits|
expect(subject)
.to receive(:commits_for)
.with(id)
.and_return(commits)
end
end
it 'returns an array of SingleChangeAccess' do
# Commits are wrapped in a Gitlab::Lazy and thus need to be resolved
# first such that we can directly compare types.
actual_accesses = subject.single_change_accesses
.each { |access| access.instance_variable_set(:@commits, access.commits.to_a) }
expect(actual_accesses).to match_array(expected_accesses)
end
end
context 'with no changes' do
let(:changes) { [] }
it_behaves_like '#single_change_access'
end
context 'with a single change and no new commits' do
let(:commits_for) { { 'new' => [] } }
let(:changes) do
[
{ oldrev: 'old', newrev: 'new', ref: 'refs/heads/branch' }
]
end
let(:expected_accesses) do
[
have_attributes(oldrev: 'old', newrev: 'new', ref: 'refs/heads/branch', commits: [])
]
end
it_behaves_like '#single_change_access'
end
context 'with a single change and new commits' do
let(:commits_for) { { 'new' => [create_commit('new', [])] } }
let(:changes) do
[
{ oldrev: 'old', newrev: 'new', ref: 'refs/heads/branch' }
]
end
let(:expected_accesses) do
[
have_attributes(oldrev: 'old', newrev: 'new', ref: 'refs/heads/branch', commits: [create_commit('new', [])])
]
end
it_behaves_like '#single_change_access'
end
context 'with multiple changes' do
let(:commits_for) do
{
'a' => [create_commit('a', [])],
'c' => [create_commit('c', [])],
'd' => []
}
end
let(:changes) do
[
{ newrev: 'a', ref: 'refs/heads/a' },
{ oldrev: 'b', ref: 'refs/heads/b' },
{ oldrev: 'a', newrev: 'c', ref: 'refs/heads/c' },
{ newrev: 'd', ref: 'refs/heads/d' }
]
end
let(:expected_accesses) do
[
have_attributes(newrev: 'a', ref: 'refs/heads/a', commits: [create_commit('a', [])]),
have_attributes(oldrev: 'b', ref: 'refs/heads/b', commits: []),
have_attributes(oldrev: 'a', newrev: 'c', ref: 'refs/heads/c', commits: [create_commit('c', [])]),
have_attributes(newrev: 'd', ref: 'refs/heads/d', commits: [])
]
end
it_behaves_like '#single_change_access'
end
end
def create_commit(id, parent_ids) def create_commit(id, parent_ids)
Gitlab::Git::Commit.new(project.repository, { Gitlab::Git::Commit.new(project.repository, {
id: id, id: id,
......
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