Class: Gitlab::Checks::ChangesAccess

Inherits:
Object
  • Object
show all
Includes:
Utils::StrongMemoize
Defined in:
lib/gitlab/checks/changes_access.rb

Constant Summary collapse

ATTRIBUTES =
%i[user_access project protocol changes logger].freeze

Instance Method Summary collapse

Constructor Details

#initialize(changes, user_access:, project:, protocol:, logger:) ⇒ ChangesAccess

Returns a new instance of ChangesAccess.



12
13
14
15
16
17
18
19
20
# File 'lib/gitlab/checks/changes_access.rb', line 12

def initialize(
  changes, user_access:, project:, protocol:, logger:
)
  @changes = changes
  @user_access = user_access
  @project = project
  @protocol = protocol
  @logger = logger
end

Instance Method Details

#commitsObject

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.



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/gitlab/checks/changes_access.rb', line 37

def commits
  strong_memoize(:commits) do
    newrevs = @changes.filter_map do |change|
      newrev = change[:newrev]

      next if blank_rev?(newrev)

      newrev
    end

    next [] if newrevs.empty?

    project.repository.new_commits(newrevs)
  end
end

#commits_for(oldrev, newrev) ⇒ Object

All commits which have been newly introduced via the given revision.



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/gitlab/checks/changes_access.rb', line 54

def commits_for(oldrev, 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. Furthermore, we stop walking as soon as we hit
    # `oldrev` such that we do not include any commits in our checks
    # which have been "over-pushed" by the client.
    commit.parent_ids.each do |parent_id|
      pending.add(parent_id) if commits_by_id.has_key?(parent_id) && parent_id != oldrev
    end

    result << commit
  end

  result
end

#single_change_accessesObject



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/gitlab/checks/changes_access.rb', line 88

def single_change_accesses
  @single_changes_accesses ||=
    changes.map do |change|
      commits =
        if !commitish_ref?(change[:ref]) || blank_rev?(change[:newrev])
          []
        else
          Gitlab::Lazy.new { commits_for(change[:oldrev], change[:newrev]) }
        end

      Checks::SingleChangeAccess.new(
        change,
        user_access: user_access,
        project: project,
        protocol: protocol,
        logger: logger,
        commits: commits
      )
    end
end

#validate!Object



22
23
24
25
26
27
28
29
30
31
32
# File 'lib/gitlab/checks/changes_access.rb', line 22

def validate!
  return if changes.empty?

  single_access_checks!

  logger.log_timed("Running checks for #{changes.length} changes") do
    bulk_access_checks!
  end

  true
end