Class: Ci::Processable

Inherits:
CommitStatus show all
Extended by:
Gitlab::Utils::Override
Includes:
Metadatable, FromUnion, Gitlab::Utils::StrongMemoize
Defined in:
app/models/ci/processable.rb

Overview

This class is a collection of common features between Ci::Build and Ci::Bridge. In gitlab.com/groups/gitlab-org/-/epics/9991, we aim to clarify class naming conventions.

Direct Known Subclasses

Bridge, Build

Constant Summary collapse

ACTIONABLE_WHEN =
%w[manual delayed].freeze

Constants included from TaggableQueries

TaggableQueries::MAX_TAGS_IDS, TaggableQueries::TooManyTagsError

Constants included from HasStatus

HasStatus::ACTIVE_STATUSES, HasStatus::ALIVE_STATUSES, HasStatus::AVAILABLE_STATUSES, HasStatus::BLOCKED_STATUS, HasStatus::CANCELABLE_STATUSES, HasStatus::COMPLETED_STATUSES, HasStatus::COMPLETED_WITH_MANUAL_STATUSES, HasStatus::DEFAULT_STATUS, HasStatus::EXECUTING_STATUSES, HasStatus::IGNORED_STATUSES, HasStatus::ORDERED_STATUSES, HasStatus::PASSED_WITH_WARNINGS_STATUSES, HasStatus::STARTED_STATUSES, HasStatus::STATUSES_ENUM, HasStatus::STOPPED_STATUSES, HasStatus::UnknownStatusError

Constants inherited from ApplicationRecord

ApplicationRecord::MAX_PLUCK

Constants included from HasCheckConstraints

HasCheckConstraints::NOT_NULL_CHECK_PATTERN

Constants included from ResetOnColumnErrors

ResetOnColumnErrors::MAX_RESET_PERIOD

Instance Attribute Summary

Attributes included from Importable

#importing, #user_contributions

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Gitlab::Utils::Override

extended, extensions, included, method_added, override, prepended, queue_verification, verify!

Methods included from Metadatable

#degenerate!, #degenerated?, #enqueue_immediately?, #ensure_metadata, #has_exposed_artifacts?, #id_tokens=, #id_tokens?, #interruptible, #interruptible=, #options, #options=, #set_enqueue_immediately!, #yaml_variables, #yaml_variables=

Methods inherited from CommitStatus

#archived?, #auto_canceled?, #cancelable?, #detailed_status, #duration, #exit_code=, #expire_etag_cache!, #force_cancelable?, #group_name, #has_trace?, #latest?, #locking_enabled?, locking_enabled?, names, #playable?, #queued_duration, #recoverable?, #resource_parent, #sortable_name, #stage_name, #stuck?, #supports_canceling?, #supports_force_cancel?, #to_ability_name, update_as_processed!, #update_older_statuses_retried!

Methods included from TaggableQueries

#tags_ids

Methods included from BulkInsertableAssociations

#bulk_insert_associations!, bulk_inserts_enabled?, with_bulk_insert

Methods included from Presentable

#present

Methods included from AfterCommitQueue

#run_after_commit, #run_after_commit_or_now

Methods included from HasStatus

#active?, #blocked?, #complete?, #complete_or_manual?, #incomplete?, #started?

Methods included from Partitionable

registered_models

Methods inherited from ApplicationRecord

model_name, table_name_prefix

Methods inherited from ApplicationRecord

===, cached_column_list, #create_or_load_association, declarative_enum, default_select_columns, id_in, id_not_in, iid_in, nullable_column?, pluck_primary_key, primary_key_in, #readable_by?, safe_ensure_unique, safe_find_or_create_by, safe_find_or_create_by!, #to_ability_name, underscore, where_exists, where_not_exists, with_fast_read_statement_timeout, without_order

Methods included from ResetOnColumnErrors

#reset_on_union_error, #reset_on_unknown_attribute_error

Methods included from Gitlab::SensitiveSerializableHash

#serializable_hash

Class Method Details

.populate_scheduling_type!Object

Old processables may have scheduling_type as nil, so we need to ensure the data exists before using it.



117
118
119
120
121
122
123
124
125
# File 'app/models/ci/processable.rb', line 117

def self.populate_scheduling_type!
  needs = Ci::BuildNeed.scoped_build.select(1)
  where(scheduling_type: nil).update_all(
    "scheduling_type = CASE WHEN (EXISTS (#{needs.to_sql}))
     THEN #{scheduling_types[:dag]}
     ELSE #{scheduling_types[:stage]}
     END"
  )
end

.select_with_aggregated_needs(project) ⇒ Object



103
104
105
106
107
108
109
110
111
112
113
# File 'app/models/ci/processable.rb', line 103

def self.select_with_aggregated_needs(project)
  aggregated_needs_names = Ci::BuildNeed
    .scoped_build
    .select("ARRAY_AGG(name)")
    .to_sql

  all.select(
    '*',
    "(#{aggregated_needs_names}) as aggregated_needs_names"
  )
end

Instance Method Details

#action?Boolean

Returns:

  • (Boolean)

Raises:

  • (NotImplementedError)


181
182
183
# File 'app/models/ci/processable.rb', line 181

def action?
  raise NotImplementedError
end

#aggregated_needs_namesObject



173
174
175
# File 'app/models/ci/processable.rb', line 173

def aggregated_needs_names
  read_attribute(:aggregated_needs_names)
end

#all_dependenciesObject



257
258
259
260
261
# File 'app/models/ci/processable.rb', line 257

def all_dependencies
  strong_memoize(:all_dependencies) do
    dependencies.all
  end
end

#all_met_to_become_pending?Boolean

Returns:

  • (Boolean)


206
207
208
# File 'app/models/ci/processable.rb', line 206

def all_met_to_become_pending?
  super && !with_resource_group?
end

#assign_resource_from_resource_group(processable) ⇒ Object



99
100
101
# File 'app/models/ci/processable.rb', line 99

def assign_resource_from_resource_group(processable)
  Ci::ResourceGroups::AssignResourceFromResourceGroupWorker.perform_async(processable.resource_group_id)
end

#can_auto_cancel_pipeline_on_job_failure?Boolean

Returns:

  • (Boolean)

Raises:

  • (NotImplementedError)


185
186
187
# File 'app/models/ci/processable.rb', line 185

def can_auto_cancel_pipeline_on_job_failure?
  raise NotImplementedError
end

#clone(current_user:, new_job_variables_attributes: []) ⇒ Object



138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'app/models/ci/processable.rb', line 138

def clone(current_user:, new_job_variables_attributes: [])
  new_attributes = self.class.clone_accessors.index_with do |attribute|
    public_send(attribute) # rubocop:disable GitlabSecurity/PublicSend
  end

  if persisted_environment.present?
    new_attributes[:metadata_attributes] ||= {}
    new_attributes[:metadata_attributes][:expanded_environment_name] = expanded_environment_name
  end

  new_attributes[:user] = current_user

  self.class.new(new_attributes)
end

#dependency_variablesObject



241
242
243
244
245
246
247
248
249
# File 'app/models/ci/processable.rb', line 241

def dependency_variables
  return [] if all_dependencies.empty?

  dependencies_with_accessible_artifacts = job_dependencies_with_accessible_artifacts(all_dependencies)

  Gitlab::Ci::Variables::Collection.new.concat(
    Ci::JobVariable.where(job: dependencies_with_accessible_artifacts).dotenv_source
  )
end

#ensure_scheduling_type!Object



233
234
235
236
237
238
239
# File 'app/models/ci/processable.rb', line 233

def ensure_scheduling_type!
  # If this has a scheduling_type, it means all processables in the pipeline already have.
  return if scheduling_type

  pipeline.ensure_scheduling_type!
  reset
end

#expanded_environment_nameObject

Raises:

  • (NotImplementedError)


197
198
199
# File 'app/models/ci/processable.rb', line 197

def expanded_environment_name
  raise NotImplementedError
end

#find_legacy_scheduling_typeObject

scheduling_type column of previous builds/bridges have not been populated, so we calculate this value on runtime when we need it.



221
222
223
224
225
# File 'app/models/ci/processable.rb', line 221

def find_legacy_scheduling_type
  strong_memoize(:find_legacy_scheduling_type) do
    needs.exists? ? :dag : :stage
  end
end

#job_dependencies_with_accessible_artifacts(all_dependencies) ⇒ Object



251
252
253
254
255
# File 'app/models/ci/processable.rb', line 251

def job_dependencies_with_accessible_artifacts(all_dependencies)
  build_ids = all_dependencies.collect(&:id)

  Ci::Build.id_in(build_ids).builds_with_accessible_artifacts(self.project_id)
end

#manual_confirmation_messageObject



267
268
269
# File 'app/models/ci/processable.rb', line 267

def manual_confirmation_message
  options[:manual_confirmation] if manual_job?
end

#manual_job?Boolean

Returns:

  • (Boolean)


263
264
265
# File 'app/models/ci/processable.rb', line 263

def manual_job?
  self.when == 'manual'
end

#needs_attributesObject



227
228
229
230
231
# File 'app/models/ci/processable.rb', line 227

def needs_attributes
  strong_memoize(:needs_attributes) do
    needs.map { |need| need.attributes.except('id', 'build_id') }
  end
end

#other_manual_actionsObject



189
190
191
# File 'app/models/ci/processable.rb', line 189

def other_manual_actions
  pipeline.manual_actions.reject { |action| action.name == name }
end

#persisted_environmentObject

Raises:

  • (NotImplementedError)


201
202
203
# File 'app/models/ci/processable.rb', line 201

def persisted_environment
  raise NotImplementedError
end

#retryable?Boolean

Returns:

  • (Boolean)


167
168
169
170
171
# File 'app/models/ci/processable.rb', line 167

def retryable?
  return false if retried? || archived? || deployment_rejected?

  success? || failed? || canceled? || canceling?
end

#schedulable?Boolean

Returns:

  • (Boolean)

Raises:

  • (NotImplementedError)


177
178
179
# File 'app/models/ci/processable.rb', line 177

def schedulable?
  raise NotImplementedError
end

#scheduling_type_dag?Boolean

Overriding scheduling_type enum’s method for nil ‘scheduling_type`s

Returns:

  • (Boolean)


215
216
217
# File 'app/models/ci/processable.rb', line 215

def scheduling_type_dag?
  scheduling_type.nil? ? find_legacy_scheduling_type == :dag : super
end

#scoped_userObject

Scoped user is present when the user creating the pipeline supports composite identity. For example: a service account like GitLab Duo. The scoped user is used to further restrict the permissions of the CI job token associated to the ‘job.user`.



156
157
158
159
160
161
162
163
164
# File 'app/models/ci/processable.rb', line 156

def scoped_user
  # If jobs are retried by human users (not composite identity) we want to
  # ignore the persisted `scoped_user_id`, because that is propagated
  # together with `options` to cloned jobs.
  # We also handle the case where `user` is `nil` (legacy behavior in specs).
  return unless user&.has_composite_identity?

  User.find_by_id(options[:scoped_user_id])
end

#whenObject



193
194
195
# File 'app/models/ci/processable.rb', line 193

def when
  read_attribute(:when) || 'on_success'
end

#with_resource_group?Boolean

Returns:

  • (Boolean)


210
211
212
# File 'app/models/ci/processable.rb', line 210

def with_resource_group?
  self.resource_group_id.present?
end