diff options
Diffstat (limited to 'lib/gitlab/checks')
-rw-r--r-- | lib/gitlab/checks/branch_check.rb | 2 | ||||
-rw-r--r-- | lib/gitlab/checks/changes_access.rb | 52 | ||||
-rw-r--r-- | lib/gitlab/checks/single_change_access.rb | 3 |
3 files changed, 54 insertions, 3 deletions
diff --git a/lib/gitlab/checks/branch_check.rb b/lib/gitlab/checks/branch_check.rb index a2d74d36b58..cfff6e919dc 100644 --- a/lib/gitlab/checks/branch_check.rb +++ b/lib/gitlab/checks/branch_check.rb @@ -122,7 +122,7 @@ module Gitlab def empty_project_push_message <<~MESSAGE - A default branch (e.g. master) does not yet exist for #{project.full_path} + A default branch (e.g. main) does not yet exist for #{project.full_path} Ask a project Owner or Maintainer to create a default branch: #{project_members_url} 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 diff --git a/lib/gitlab/checks/single_change_access.rb b/lib/gitlab/checks/single_change_access.rb index 280b2dd25e2..2fd48dfbfe2 100644 --- a/lib/gitlab/checks/single_change_access.rb +++ b/lib/gitlab/checks/single_change_access.rb @@ -11,7 +11,7 @@ module Gitlab def initialize( change, user_access:, project:, - protocol:, logger: + protocol:, logger:, commits: nil ) @oldrev, @newrev, @ref = change.values_at(:oldrev, :newrev, :ref) @branch_name = Gitlab::Git.branch_name(@ref) @@ -19,6 +19,7 @@ module Gitlab @user_access = user_access @project = project @protocol = protocol + @commits = commits @logger = logger @logger.append_message("Running checks for ref: #{@branch_name || @tag_name}") |