Welcome to mirror list, hosted at ThFree Co, Russian Federation.

stage_type.rb « ci « types « graphql « app - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 56b4f248697e3e3c96e926253594a1866b5cc6f1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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
# frozen_string_literal: true

module Types
  module Ci
    # rubocop: disable Graphql/AuthorizeTypes
    class StageType < BaseObject
      graphql_name 'CiStage'

      field :name, GraphQL::STRING_TYPE, null: true,
        description: 'Name of the stage.'
      field :groups, Ci::GroupType.connection_type, null: true,
        extras: [:lookahead],
        description: 'Group of jobs for the stage.'
      field :detailed_status, Types::Ci::DetailedStatusType, null: true,
        description: 'Detailed status of the stage.'
      field :jobs, Ci::JobType.connection_type, null: true,
        description: 'Jobs for the stage.',
        method: 'latest_statuses'

      def detailed_status
        object.detailed_status(current_user)
      end

      # Issues one query per pipeline
      def groups(lookahead:)
        key = ::Gitlab::Graphql::BatchKey.new(object, lookahead, object_name: :stage)

        BatchLoader::GraphQL.for(key).batch(default_value: []) do |keys, loader|
          by_pipeline = keys.group_by(&:pipeline)
          include_needs = keys.any? { |k| k.requires?(%i[nodes jobs nodes needs]) }

          by_pipeline.each do |pl, key_group|
            project = pl.project
            indexed = key_group.index_by(&:id)

            jobs_for_pipeline(pl, indexed.keys, include_needs).each do |stage_id, statuses|
              key = indexed[stage_id]
              groups = ::Ci::Group.fabricate(project, key.stage, statuses)

              if Feature.enabled?(:ci_no_empty_groups, project)
                groups.each do |group|
                  rejected = group.jobs.reject { |job| Ability.allowed?(current_user, :read_commit_status, job) }
                  group.jobs.select! { |job| Ability.allowed?(current_user, :read_commit_status, job) }
                  next unless group.jobs.empty?

                  exc = StandardError.new('Empty Ci::Group')
                  traces = rejected.map do |job|
                    trace = []
                    policy = Ability.policy_for(current_user, job)
                    policy.debug(:read_commit_status, trace)
                    trace
                  end
                  extra = {
                    current_user_id: current_user&.id,
                    project_id: project.id,
                    pipeline_id: pl.id,
                    stage_id: stage_id,
                    group_name: group.name,
                    rejected_job_ids: rejected.map(&:id),
                    rejected_traces: traces
                  }
                  Gitlab::ErrorTracking.track_exception(exc, extra)
                end
                groups.reject! { |group| group.jobs.empty? }
              end

              loader.call(key, groups)
            end
          end
        end
      end

      private

      # rubocop: disable CodeReuse/ActiveRecord
      def jobs_for_pipeline(pipeline, stage_ids, include_needs)
        results = pipeline.latest_statuses.where(stage_id: stage_ids)
        results = results.preload(:needs) if include_needs

        results.group_by(&:stage_id)
      end
      # rubocop: enable CodeReuse/ActiveRecord
    end
  end
end