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 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

#artifacts_exposed_as, #artifacts_exposed_paths, #debug_trace_enabled?, #degenerate!, #degenerated?, #downstream_errors, #enable_debug_trace!, #exit_code, #exit_code=, #has_exposed_artifacts?, #id_tokens, #id_tokens=, #id_tokens?, #interruptible, #interruptible=, #options, #options=, #scoped_user_id, #secrets=, #timeout_human_readable_value, #timeout_source_value, #timeout_value, #update_timeout_state, #yaml_variables, #yaml_variables=

Methods inherited from CommitStatus

#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?, #test_suite_name, #to_ability_name, update_as_processed!, #update_older_statuses_retried!

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, current_transaction, declarative_enum, default_select_columns, delete_all_returning, #deleted_from_database?, id_in, id_not_in, iid_in, nullable_column?, 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 Organizations::Sharding

#sharding_organization

Methods included from ResetOnColumnErrors

#reset_on_union_error, #reset_on_unknown_attribute_error

Methods included from Gitlab::SensitiveSerializableHash

#serializable_hash

Class Method Details

.fabricate(attrs) ⇒ Object



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'app/models/ci/processable.rb', line 159

def self.fabricate(attrs)
  attrs = attrs.dup
  definition_attrs = attrs.extract!(*Ci::JobDefinition::CONFIG_ATTRIBUTES)
  attrs[:tag_list] = definition_attrs[:tag_list] if definition_attrs.key?(:tag_list)

  new(attrs).tap do |job|
    job_definition = ::Ci::JobDefinition.fabricate(
      config: definition_attrs,
      project_id: job.project_id,
      partition_id: job.partition_id
    )

    job.temp_job_definition = job_definition
  end
end

.populate_scheduling_type!Object

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



189
190
191
192
193
194
195
196
197
# File 'app/models/ci/processable.rb', line 189

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



175
176
177
178
179
180
181
182
183
184
185
# File 'app/models/ci/processable.rb', line 175

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)


246
247
248
# File 'app/models/ci/processable.rb', line 246

def action?
  raise NotImplementedError
end

#aggregated_needs_namesObject



238
239
240
# File 'app/models/ci/processable.rb', line 238

def aggregated_needs_names
  read_attribute(:aggregated_needs_names)
end

#all_dependenciesObject



322
323
324
325
326
# File 'app/models/ci/processable.rb', line 322

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

#all_met_to_become_pending?Boolean

Returns:

  • (Boolean)


271
272
273
# File 'app/models/ci/processable.rb', line 271

def all_met_to_become_pending?
  super && !with_resource_group?
end

#archived?Boolean

Returns:

  • (Boolean)


234
235
236
# File 'app/models/ci/processable.rb', line 234

def archived?(...)
  degenerated? || super
end

#assign_resource_from_resource_group(processable) ⇒ Object



199
200
201
# File 'app/models/ci/processable.rb', line 199

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)


250
251
252
# File 'app/models/ci/processable.rb', line 250

def can_auto_cancel_pipeline_on_job_failure?
  raise NotImplementedError
end

#dependency_variablesObject



306
307
308
309
310
311
312
313
314
# File 'app/models/ci/processable.rb', line 306

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

#enqueue_immediately?Boolean

Returns:

  • (Boolean)


342
343
344
# File 'app/models/ci/processable.rb', line 342

def enqueue_immediately?
  redis_state.enqueue_immediately?
end

#ensure_scheduling_type!Object



298
299
300
301
302
303
304
# File 'app/models/ci/processable.rb', line 298

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)


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

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.



286
287
288
289
290
# File 'app/models/ci/processable.rb', line 286

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



316
317
318
319
320
# File 'app/models/ci/processable.rb', line 316

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



332
333
334
# File 'app/models/ci/processable.rb', line 332

def manual_confirmation_message
  options[:manual_confirmation] if manual_job? && playable?
end

#manual_job?Boolean

Returns:

  • (Boolean)


328
329
330
# File 'app/models/ci/processable.rb', line 328

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

#needs_attributesObject



292
293
294
295
296
# File 'app/models/ci/processable.rb', line 292

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

#other_manual_actionsObject



254
255
256
# File 'app/models/ci/processable.rb', line 254

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

#persisted_environmentObject

Raises:

  • (NotImplementedError)


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

def persisted_environment
  raise NotImplementedError
end

#redis_stateObject



336
337
338
339
340
# File 'app/models/ci/processable.rb', line 336

def redis_state
  strong_memoize(:redis_state) do
    Ci::JobRedisState.find_or_initialize_by(job: self)
  end
end

#retryable?Boolean

Returns:

  • (Boolean)


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

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

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

#schedulable?Boolean

Returns:

  • (Boolean)

Raises:

  • (NotImplementedError)


242
243
244
# File 'app/models/ci/processable.rb', line 242

def schedulable?
  raise NotImplementedError
end

#scheduling_type_dag?Boolean

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

Returns:

  • (Boolean)


280
281
282
# File 'app/models/ci/processable.rb', line 280

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.



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

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&.composite_identity_enforced?

  User.find_by_id(scoped_user_id)
end

#set_enqueue_immediately!Object



346
347
348
# File 'app/models/ci/processable.rb', line 346

def set_enqueue_immediately!
  redis_state.enqueue_immediately = true
end

#sourceObject



350
351
352
# File 'app/models/ci/processable.rb', line 350

def source
  job_source&.source || pipeline.source
end

#whenObject



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

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

#with_resource_group?Boolean

Returns:

  • (Boolean)


275
276
277
# File 'app/models/ci/processable.rb', line 275

def with_resource_group?
  self.resource_group_id.present?
end