diff options
Diffstat (limited to 'lib/gitlab/checks/changes_access.rb')
-rw-r--r-- | lib/gitlab/checks/changes_access.rb | 52 |
1 files changed, 51 insertions, 1 deletions
diff --git a/lib/gitlab/checks/changes_access.rb b/lib/gitlab/checks/changes_access.rb index 4e8b293a3e6..9ecc93f871b 100644 --- a/lib/gitlab/checks/changes_access.rb +++ b/lib/gitlab/checks/changes_access.rb @@ -29,11 +29,60 @@ module Gitlab true end + # All commits which have been newly introduced via any of the given + # changes. This set may also contain commits which are not referenced by + # any of the new revisions. + def commits + newrevs = @changes.map do |change| + newrev = change[:newrev] + newrev unless newrev.blank? || Gitlab::Git.blank_ref?(newrev) + end.compact + + return [] if newrevs.empty? + + @commits ||= project.repository.new_commits(newrevs, allow_quarantine: true) + end + + # All commits which have been newly introduced via the given revision. + def commits_for(newrev) + commits_by_id = commits.index_by(&:id) + + result = [] + pending = Set[newrev] + + # We go up the parent chain of our newrev and collect all commits which + # are new. In case a commit's ID cannot be found in the set of new + # commits, then it must already be a preexisting commit. + while pending.any? + rev = pending.first + pending.delete(rev) + + # Remove the revision from commit candidates such that we don't walk + # it multiple times. If the hash doesn't contain the revision, then + # we have either already walked the commit or it's not new. + commit = commits_by_id.delete(rev) + next if commit.nil? + + # Only add the parent ID to the pending set if we actually know its + # commit to guards us against readding an ID which we have already + # queued up before. + commit.parent_ids.each do |parent_id| + pending.add(parent_id) if commits_by_id.has_key?(parent_id) + end + + result << commit + end + + result + end + protected def single_access_checks! # Iterate over all changes to find if user allowed all of them to be applied changes.each do |change| + commits = Gitlab::Lazy.new { commits_for(change[:newrev]) } if Feature.enabled?(:changes_batch_commits) + # 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( @@ -41,7 +90,8 @@ module Gitlab user_access: user_access, project: project, protocol: protocol, - logger: logger + logger: logger, + commits: commits ).validate! end end |