summaryrefslogtreecommitdiff
path: root/lib/gitlab/ci/pipeline/chain/command.rb
blob: d2dc712e366a6b985680ed836a9aa974eb0fad8e (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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# rubocop:disable Naming/FileName
# frozen_string_literal: true

module Gitlab
  module Ci
    module Pipeline
      module Chain
        Command = Struct.new(
          :source, :project, :current_user,
          :origin_ref, :checkout_sha, :after_sha, :before_sha, :source_sha, :target_sha,
          :trigger_request, :schedule, :merge_request, :external_pull_request,
          :ignore_skip_ci, :save_incompleted,
          :seeds_block, :variables_attributes, :push_options,
          :chat_data, :allow_mirror_update, :bridge, :content, :dry_run, :logger,
          # These attributes are set by Chains during processing:
          :config_content, :yaml_processor_result, :workflow_rules_result, :pipeline_seed
        ) do
          include Gitlab::Utils::StrongMemoize

          def initialize(params = {})
            params.each do |key, value|
              self[key] = value
            end
          end

          alias_method :dry_run?, :dry_run

          def branch_exists?
            strong_memoize(:is_branch) do
              branch_ref? && project.repository.branch_exists?(ref)
            end
          end

          def tag_exists?
            strong_memoize(:is_tag) do
              tag_ref? && project.repository.tag_exists?(ref)
            end
          end

          def merge_request_ref_exists?
            strong_memoize(:merge_request_ref_exists) do
              MergeRequest.merge_request_ref?(origin_ref) &&
                project.repository.ref_exists?(origin_ref)
            end
          end

          def ref
            strong_memoize(:ref) do
              Gitlab::Git.ref_name(origin_ref)
            end
          end

          def sha
            strong_memoize(:sha) do
              project.commit(origin_sha || origin_ref).try(:id)
            end
          end

          def origin_sha
            checkout_sha || after_sha
          end

          def before_sha
            self[:before_sha] || checkout_sha || Gitlab::Git::BLANK_SHA
          end

          def protected_ref?
            strong_memoize(:protected_ref) do
              project.protected_for?(origin_ref)
            end
          end

          def ambiguous_ref?
            strong_memoize(:ambiguous_ref) do
              project.repository.ambiguous_ref?(origin_ref)
            end
          end

          def parent_pipeline
            bridge&.parent_pipeline
          end

          def parent_pipeline_partition_id
            parent_pipeline.partition_id if creates_child_pipeline?
          end

          def creates_child_pipeline?
            bridge&.triggers_child_pipeline?
          end

          def metrics
            @metrics ||= ::Gitlab::Ci::Pipeline::Metrics
          end

          def logger
            self[:logger] ||= ::Gitlab::Ci::Pipeline::Logger.new(project: project)
          end

          def observe_step_duration(step_class, duration)
            step = step_class.name.underscore.parameterize(separator: '_')
            logger.observe("pipeline_step_#{step}_duration_s", duration, once: true)

            if Feature.enabled?(:ci_pipeline_creation_step_duration_tracking, type: :ops)
              metrics.pipeline_creation_step_duration_histogram
                .observe({ step: step_class.name }, duration.seconds)
            end
          end

          def observe_creation_duration(duration)
            logger.observe(:pipeline_creation_duration_s, duration, once: true)

            metrics.pipeline_creation_duration_histogram
              .observe({ gitlab: gitlab_org_project?.to_s }, duration.seconds)
          end

          def observe_pipeline_size(pipeline)
            logger.observe(:pipeline_size_count, pipeline.total_size, once: true)

            metrics.pipeline_size_histogram
              .observe({ source: pipeline.source.to_s, plan: project.actual_plan_name }, pipeline.total_size)
          end

          def observe_jobs_count_in_alive_pipelines
            jobs_count = project.all_pipelines.jobs_count_in_alive_pipelines

            metrics.active_jobs_histogram
              .observe({ plan: project.actual_plan_name }, jobs_count)
          end

          def observe_pipeline_includes_count(pipeline)
            logger.observe(:pipeline_includes_count, pipeline.config_metadata&.[](:includes)&.count, once: true)
          end

          def increment_pipeline_failure_reason_counter(reason)
            metrics.pipeline_failure_reason_counter
              .increment(reason: (reason || :unknown_failure).to_s)
          end

          private

          # Verifies that origin_ref is a fully qualified tag reference (refs/tags/<tag-name>)
          #
          # Fallbacks to `true` for backward compatibility reasons
          # if origin_ref is a short ref
          def tag_ref?
            return true if full_git_ref_name_unavailable?

            Gitlab::Git.tag_ref?(origin_ref).present?
          end

          # Verifies that origin_ref is a fully qualified branch reference (refs/heads/<branch-name>)
          #
          # Fallbacks to `true` for backward compatibility reasons
          # if origin_ref is a short ref
          def branch_ref?
            return true if full_git_ref_name_unavailable?

            Gitlab::Git.branch_ref?(origin_ref).present?
          end

          def full_git_ref_name_unavailable?
            ref == origin_ref
          end

          def gitlab_org_project?
            project.full_path == 'gitlab-org/gitlab'
          end
        end
      end
    end
  end
end

# rubocop:enable Naming/FileName