Class: Ci::Build
- Inherits:
-
Processable
show all
- Extended by:
- Gitlab::Utils::Override
- Includes:
- AfterCommitQueue, BulkInsertableTags, Contextable, Deployable, HasRef, Taggable, TrackEnvironmentUsage, EachBatch, Importable, Presentable, TokenAuthenticatable
- Defined in:
- app/models/ci/build.rb
Constant Summary
collapse
- RUNNER_FEATURES =
{
upload_multiple_artifacts: ->(build) { build.publishes_artifacts_reports? },
refspecs: ->(build) { build.merge_request_ref? },
artifacts_exclude: ->(build) { build.supports_artifacts_exclude? },
multi_build_steps: ->(build) { build.multi_build_steps? },
return_exit_code: ->(build) { build.exit_codes_defined? },
fallback_cache_keys: ->(build) { build.fallback_cache_keys_defined? }
}.freeze
- DEGRADATION_THRESHOLD_VARIABLE_NAME =
'DEGRADATION_THRESHOLD'
- RUNNERS_STATUS_CACHE_EXPIRATION =
1.minute
- DEPLOYMENT_NAMES =
%w[deploy release rollout].freeze
- TOKEN_PREFIX =
'glcbt-'
Ci::BulkInsertableTags::BULK_INSERT_TAG_THREAD_KEY
Constants inherited
from Processable
Processable::ACTIONABLE_WHEN
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
ApplicationRecord::MAX_PLUCK
HasCheckConstraints::NOT_NULL_CHECK_PATTERN
ResetOnColumnErrors::MAX_RESET_PERIOD
Instance Attribute Summary
Attributes included from Importable
#importing, #user_contributions
Class Method Summary
collapse
Instance Method Summary
collapse
extended, extensions, included, method_added, override, prepended, queue_verification, verify!
Methods included from Taggable
#reload, #tag_list=
#count_user_deployment?, #deployment_name?, #track_deployment_usage, #track_verify_environment_usage, #verifies_environment?
Methods included from HasRef
#branch?, #git_ref, #ref_slug
#present
#run_after_commit, #run_after_commit_or_now
Methods included from Deployable
#accesses_environment?, #actual_persisted_environment, #deployment_job?, #deployment_status, #environment_action, #environment_slug, #environment_status, #environment_tier, #environment_tier_from_options, #environment_url, #expanded_auto_stop_in, #expanded_environment_name, #expanded_kubernetes_namespace, #has_environment_keyword?, #has_outdated_deployment?, #on_stop, #persisted_environment, #persisted_environment=, #prepares_environment?, #stop_action_successful?, #stops_environment?, #successful_deployment_status, #verifies_environment?
#scoped_variables, #simple_variables, #simple_variables_without_dependencies, #track_duration, #unprotected_scoped_variables
with_bulk_insert_tags
Methods inherited from Processable
#aggregated_needs_names, #all_dependencies, #assign_resource_from_resource_group, #dependency_variables, #ensure_scheduling_type!, #expanded_environment_name, #find_legacy_scheduling_type, #job_dependencies_with_accessible_artifacts, #manual_confirmation_message, #manual_job?, #needs_attributes, #other_manual_actions, #persisted_environment, populate_scheduling_type!, #retryable?, #scheduling_type_dag?, #scoped_user, select_with_aggregated_needs, #when, #with_resource_group?
#cancel_gracefully?, #enqueue_immediately?, #ensure_metadata, #has_exposed_artifacts?, #id_tokens=, #id_tokens?, #interruptible, #interruptible=, #options, #options=, #set_enqueue_immediately!, #yaml_variables, #yaml_variables=
#auto_canceled?, #duration, #expire_etag_cache!, #group_name, #latest?, #locking_enabled?, locking_enabled?, names, #queued_duration, #recoverable?, #resource_parent, #retryable?, #sortable_name, #stage_name, #to_ability_name, update_as_processed!, #update_older_statuses_retried!
#tags_ids
#bulk_insert_associations!, bulk_inserts_enabled?, with_bulk_insert
Methods included from HasStatus
#active?, #blocked?, #complete?, #complete_or_manual?, #incomplete?, #started?
registered_models
table_name_prefix
===, 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
#reset_on_union_error, #reset_on_unknown_attribute_error
Class Method Details
.arel_tag_names_array ⇒ Object
428
429
430
431
432
433
434
|
# File 'app/models/ci/build.rb', line 428
def self.arel_tag_names_array
::Ci::BuildTag
.joins(:tag)
.where(::Ci::BuildTag.arel_table[:build_id].eq(arel_table[:id]))
.where(::Ci::BuildTag.arel_table[:partition_id].eq(arel_table[:partition_id]))
.select('COALESCE(array_agg(tags.name ORDER BY name), ARRAY[]::text[])')
end
|
.build_matchers(project) ⇒ Object
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
|
# File 'app/models/ci/build.rb', line 408
def self.build_matchers(project)
unique_params = [
:protected,
Arel.sql("(#{arel_tag_names_array.to_sql})")
]
group(*unique_params).pluck('array_agg(id)', *unique_params).map do |values|
Gitlab::Ci::Matching::BuildMatcher.new({
build_ids: values[0],
protected: values[1],
tag_list: values[2],
project: project
})
end
end
|
.clone_accessors ⇒ Object
264
265
266
267
268
269
270
271
|
# File 'app/models/ci/build.rb', line 264
def clone_accessors
%i[pipeline project ref tag options name
allow_failure stage stage_idx trigger_request
yaml_variables when environment coverage_regex
description tag_list protected needs_attributes
job_variables_attributes resource_group scheduling_type
ci_stage partition_id id_tokens interruptible execution_config_id].freeze
end
|
.ids_in_merge_request(merge_request_id) ⇒ Object
424
425
426
|
# File 'app/models/ci/build.rb', line 424
def self.ids_in_merge_request(merge_request_id)
in_merge_request(merge_request_id).pluck(:id)
end
|
.keep_artifacts! ⇒ Object
901
902
903
904
|
# File 'app/models/ci/build.rb', line 901
def self.keep_artifacts!
update_all(artifacts_expire_at: nil)
Ci::JobArtifact.where(job: self.select(:id)).update_all(expire_at: nil)
end
|
.model_name ⇒ Object
This is needed for url_for to work, as the controller is JobsController
256
257
258
|
# File 'app/models/ci/build.rb', line 256
def model_name
ActiveModel::Name.new(self, nil, 'job')
end
|
.supported_keyset_orderings ⇒ Object
273
274
275
|
# File 'app/models/ci/build.rb', line 273
def supported_keyset_orderings
{ id: [:desc] }
end
|
.with_preloads ⇒ Object
260
261
262
|
# File 'app/models/ci/build.rb', line 260
def with_preloads
preload(:job_artifacts_archive, :job_artifacts, :tags, project: [:namespace])
end
|
Instance Method Details
#action? ⇒ Boolean
529
530
531
|
# File 'app/models/ci/build.rb', line 529
def action?
ACTIONABLE_WHEN.include?(self.when)
end
|
#all_met_to_become_pending? ⇒ Boolean
555
556
557
|
# File 'app/models/ci/build.rb', line 555
def all_met_to_become_pending?
super && !any_unmet_prerequisites?
end
|
#all_queuing_entries ⇒ Object
We can have only one queuing entry or running build tracking entry, because there is a unique index on ‘build_id` in each table, but we need a relation to remove these entries more efficiently in a single statement without actually loading data.
1142
1143
1144
|
# File 'app/models/ci/build.rb', line 1142
def all_queuing_entries
::Ci::PendingBuild.where(build_id: id)
end
|
1146
1147
1148
|
# File 'app/models/ci/build.rb', line 1146
def all_runtime_metadata
::Ci::RunningBuild.where(build_id: id)
end
|
#allow_git_fetch ⇒ Object
697
698
699
|
# File 'app/models/ci/build.rb', line 697
def allow_git_fetch
project.build_allow_git_fetch
end
|
#allowed_to_fail_with_code?(exit_code) ⇒ Boolean
1164
1165
1166
1167
1168
1169
|
# File 'app/models/ci/build.rb', line 1164
def allowed_to_fail_with_code?(exit_code)
options
.dig(:allow_failure_criteria, :exit_codes)
.to_a
.include?(exit_code)
end
|
#any_runners_available? ⇒ Boolean
808
809
810
811
812
|
# File 'app/models/ci/build.rb', line 808
def any_runners_available?
cache_for_available_runners do
project.active_runners.exists?
end
end
|
#any_runners_online? ⇒ Boolean
802
803
804
805
806
|
# File 'app/models/ci/build.rb', line 802
def any_runners_online?
cache_for_online_runners do
project.any_online_runners? { |runner| runner.match_build_if_online?(self) }
end
end
|
#any_unmet_prerequisites? ⇒ Boolean
559
560
561
|
# File 'app/models/ci/build.rb', line 559
def any_unmet_prerequisites?
prerequisites.present?
end
|
#apple_app_store_variables ⇒ Object
645
646
647
648
649
|
# File 'app/models/ci/build.rb', line 645
def apple_app_store_variables
return [] unless apple_app_store_integration.try(:activated?)
Gitlab::Ci::Variables::Collection.new(apple_app_store_integration.ci_variables(protected_ref: pipeline.protected_ref?))
end
|
#archived? ⇒ Boolean
510
511
512
513
514
515
|
# File 'app/models/ci/build.rb', line 510
def archived?
return true if degenerated?
archive_builds_older_than = Gitlab::CurrentSettings.current_application_settings.archive_builds_older_than
archive_builds_older_than.present? && created_at < archive_builds_older_than
end
|
#artifact_access_setting_in_config ⇒ Object
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
|
# File 'app/models/ci/build.rb', line 844
def artifact_access_setting_in_config
artifacts_public = options.dig(:artifacts, :public)
artifacts_access = options.dig(:artifacts, :access)
if !artifacts_public.nil? && !artifacts_access.nil?
raise ArgumentError, 'artifacts:public and artifacts:access are mutually exclusive'
end
return :public if artifacts_public == true || artifacts_access == 'all'
return :private if artifacts_public == false || artifacts_access == 'developer'
return :none if artifacts_access == 'none'
:public
end
|
#artifact_for_type(type) ⇒ Object
911
912
913
914
915
|
# File 'app/models/ci/build.rb', line 911
def artifact_for_type(type)
file_types = Ci::JobArtifact.associated_file_types_for(type)
file_types_ids = file_types&.map { |file_type| Ci::JobArtifact.file_types[file_type] }
job_artifacts.find_by(file_type: file_types_ids)
end
|
#artifacts? ⇒ Boolean
734
735
736
|
# File 'app/models/ci/build.rb', line 734
def artifacts?
!artifacts_expired? && artifacts_file&.exists?
end
|
#artifacts_expire_in ⇒ Object
883
884
885
|
# File 'app/models/ci/build.rb', line 883
def artifacts_expire_in
artifacts_expire_at - Time.current if artifacts_expire_at
end
|
#artifacts_expire_in=(value) ⇒ Object
887
888
889
890
|
# File 'app/models/ci/build.rb', line 887
def artifacts_expire_in=(value)
self.artifacts_expire_at =
(ChronicDuration.parse(value)&.seconds&.from_now if value)
end
|
#artifacts_expired? ⇒ Boolean
879
880
881
|
# File 'app/models/ci/build.rb', line 879
def artifacts_expired?
artifacts_expire_at&.past?
end
|
#artifacts_expose_as ⇒ Object
765
766
767
|
# File 'app/models/ci/build.rb', line 765
def artifacts_expose_as
options.dig(:artifacts, :expose_as)
end
|
#artifacts_file ⇒ Object
722
723
724
|
# File 'app/models/ci/build.rb', line 722
def artifacts_file
job_artifacts_archive&.file
end
|
730
731
732
|
# File 'app/models/ci/build.rb', line 730
def artifacts_metadata
job_artifacts_metadata&.file
end
|
749
750
751
|
# File 'app/models/ci/build.rb', line 749
def artifacts_metadata?
artifacts? && artifacts_metadata&.exists?
end
|
#artifacts_metadata_entry(path, **options) ⇒ Object
860
861
862
863
864
865
866
867
868
869
|
# File 'app/models/ci/build.rb', line 860
def artifacts_metadata_entry(path, **options)
artifacts_metadata.open do |metadata_stream|
metadata = Gitlab::Ci::Build::Artifacts::Metadata.new(
metadata_stream,
path,
**options)
metadata.to_entry
end
end
|
#artifacts_no_access? ⇒ Boolean
838
839
840
841
842
|
# File 'app/models/ci/build.rb', line 838
def artifacts_no_access?
return false if job_artifacts_archive.nil?
job_artifacts_archive.none_access?
end
|
#artifacts_paths ⇒ Object
769
770
771
|
# File 'app/models/ci/build.rb', line 769
def artifacts_paths
options.dig(:artifacts, :paths)
end
|
#artifacts_public? ⇒ Boolean
832
833
834
835
836
|
# File 'app/models/ci/build.rb', line 832
def artifacts_public?
return true if job_artifacts_archive.nil?
job_artifacts_archive.public_access?
end
|
#artifacts_size ⇒ Object
726
727
728
|
# File 'app/models/ci/build.rb', line 726
def artifacts_size
job_artifacts_archive&.size
end
|
#auto_retry_allowed? ⇒ Boolean
457
458
459
|
# File 'app/models/ci/build.rb', line 457
def auto_retry_allowed?
auto_retry.allowed?
end
|
#auto_retry_expected? ⇒ Boolean
467
468
469
|
# File 'app/models/ci/build.rb', line 467
def auto_retry_expected?
failed? && auto_retry_allowed?
end
|
#available_artifacts? ⇒ Boolean
This method is similar to #artifacts? but it includes the artifacts locking mechanics. A new method was created to prevent breaking existing behavior and avoid introducing N+1s.
745
746
747
|
# File 'app/models/ci/build.rb', line 745
def available_artifacts?
(!artifacts_expired? || pipeline.artifacts_locked?) && job_artifacts_archive&.exists?
end
|
#browsable_artifacts? ⇒ Boolean
828
829
830
|
# File 'app/models/ci/build.rb', line 828
def browsable_artifacts?
artifacts_metadata?
end
|
#build_matcher ⇒ Object
446
447
448
449
450
451
452
453
454
455
|
# File 'app/models/ci/build.rb', line 446
def build_matcher
strong_memoize(:build_matcher) do
Gitlab::Ci::Matching::BuildMatcher.new({
protected: protected?,
tag_list: tag_list,
build_ids: [id],
project: project
})
end
end
|
#cache ⇒ Object
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
|
# File 'app/models/ci/build.rb', line 935
def cache
cache = Array.wrap(options[:cache])
cache.each do |single_cache|
single_cache[:fallback_keys] = [] unless single_cache.key?(:fallback_keys)
end
if project.jobs_cache_index
cache = cache.map do |single_cache|
cache = single_cache.merge(key: "#{single_cache[:key]}-#{project.jobs_cache_index}")
fallback = cache.slice(:fallback_keys).transform_values { |keys| keys.map { |key| "#{key}-#{project.jobs_cache_index}" } }
cache.merge(fallback.compact)
end
end
return cache unless project.ci_separated_caches
cache.map do |entry|
type_suffix = !entry[:unprotect] && pipeline.protected_ref? ? 'protected' : 'non_protected'
cache = entry.merge(key: "#{entry[:key]}-#{type_suffix}")
fallback = cache.slice(:fallback_keys).transform_values { |keys| keys.map { |key| "#{key}-#{type_suffix}" } }
cache.merge(fallback.compact)
end
end
|
#can_auto_cancel_pipeline_on_job_failure? ⇒ Boolean
533
534
535
536
|
# File 'app/models/ci/build.rb', line 533
def can_auto_cancel_pipeline_on_job_failure?
!auto_retry_expected?
end
|
#cancelable? ⇒ Boolean
rubocop: enable CodeReuse/ServiceClass
546
547
548
|
# File 'app/models/ci/build.rb', line 546
def cancelable?
(active? || created?) && !canceling?
end
|
#clone(current_user:, new_job_variables_attributes: []) ⇒ Object
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
|
# File 'app/models/ci/build.rb', line 1181
def clone(current_user:, new_job_variables_attributes: [])
new_build = super
if action? && new_job_variables_attributes.any?
new_build.job_variables = []
new_build.job_variables_attributes = new_job_variables_attributes
end
new_build
end
|
#collect_accessibility_reports!(accessibility_report) ⇒ Object
1037
1038
1039
1040
1041
1042
1043
|
# File 'app/models/ci/build.rb', line 1037
def collect_accessibility_reports!(accessibility_report)
each_report(Ci::JobArtifact.file_types_for_report(:accessibility)) do |file_type, blob|
Gitlab::Ci::Parsers.fabricate!(file_type).parse!(blob, accessibility_report)
end
accessibility_report
end
|
#collect_codequality_reports!(codequality_report) ⇒ Object
1045
1046
1047
1048
1049
1050
1051
|
# File 'app/models/ci/build.rb', line 1045
def collect_codequality_reports!(codequality_report)
each_report(Ci::JobArtifact.file_types_for_report(:codequality)) do |file_type, blob|
Gitlab::Ci::Parsers.fabricate!(file_type).parse!(blob, codequality_report, { project: project, commit_sha: pipeline.sha })
end
codequality_report
end
|
1053
1054
1055
1056
1057
1058
1059
|
# File 'app/models/ci/build.rb', line 1053
def collect_terraform_reports!(terraform_reports)
each_report(::Ci::JobArtifact.file_types_for_report(:terraform)) do |file_type, blob, report_artifact|
::Gitlab::Ci::Parsers.fabricate!(file_type).parse!(blob, terraform_reports, artifact: report_artifact)
end
terraform_reports
end
|
#collect_test_reports!(test_reports) ⇒ Object
1029
1030
1031
1032
1033
1034
1035
|
# File 'app/models/ci/build.rb', line 1029
def collect_test_reports!(test_reports)
each_report(Ci::JobArtifact.file_types_for_report(:test)) do |file_type, blob|
Gitlab::Ci::Parsers.fabricate!(file_type).parse!(blob, test_reports, job: self)
end
test_reports
end
|
#create_queuing_entry! ⇒ Object
#debug_mode? ⇒ Boolean
1114
1115
1116
1117
1118
1119
|
# File 'app/models/ci/build.rb', line 1114
def debug_mode?
metadata&.debug_trace_enabled? ||
Gitlab::Utils.to_boolean(variables['CI_DEBUG_SERVICES']&.value, default: false) ||
Gitlab::Utils.to_boolean(variables['CI_DEBUG_TRACE']&.value, default: false)
end
|
#degenerate! ⇒ Object
504
505
506
507
508
|
# File 'app/models/ci/build.rb', line 504
def degenerate!
super do
execution_config&.destroy
end
end
|
#degenerated? ⇒ Boolean
500
501
502
|
# File 'app/models/ci/build.rb', line 500
def degenerated?
super && execution_config_id.nil?
end
|
#degradation_threshold ⇒ Object
1095
1096
1097
1098
|
# File 'app/models/ci/build.rb', line 1095
def degradation_threshold
var = yaml_variables.find { |v| v[:key] == DEGRADATION_THRESHOLD_VARIABLE_NAME }
var[:value]&.to_i if var
end
|
#dependency_proxy_variables ⇒ Object
630
631
632
633
634
635
636
637
|
# File 'app/models/ci/build.rb', line 630
def dependency_proxy_variables
Gitlab::Ci::Variables::Collection.new.tap do |variables|
break variables unless Gitlab.config.dependency_proxy.enabled
variables.append(key: 'CI_DEPENDENCY_PROXY_USER', value: ::Gitlab::Auth::CI_JOB_USER)
variables.append(key: 'CI_DEPENDENCY_PROXY_PASSWORD', value: token.to_s, public: false, masked: true)
end
end
|
#deploy_token_variables ⇒ Object
621
622
623
624
625
626
627
628
|
# File 'app/models/ci/build.rb', line 621
def deploy_token_variables
Gitlab::Ci::Variables::Collection.new.tap do |variables|
break variables unless gitlab_deploy_token
variables.append(key: 'CI_DEPLOY_USER', value: gitlab_deploy_token.username)
variables.append(key: 'CI_DEPLOY_PASSWORD', value: gitlab_deploy_token.token, public: false, masked: true)
end
end
|
#detailed_status(current_user) ⇒ Object
471
472
473
474
475
|
# File 'app/models/ci/build.rb', line 471
def detailed_status(current_user)
Gitlab::Ci::Status::Build::Factory
.new(present, current_user)
.fabricate!
end
|
#diffblue_cover_variables ⇒ Object
657
658
659
660
661
|
# File 'app/models/ci/build.rb', line 657
def diffblue_cover_variables
return [] unless diffblue_cover_integration.try(:activated?)
Gitlab::Ci::Variables::Collection.new(diffblue_cover_integration.ci_variables)
end
|
#doom! ⇒ Object
Consider this object to have an unknown job problem
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
|
# File 'app/models/ci/build.rb', line 1066
def doom!
transaction do
now = Time.current
attributes = {
status: :failed,
failure_reason: :data_integrity_failure,
updated_at: now
}
attributes[:finished_at] = now unless finished_at.present?
update_columns(attributes)
all_queuing_entries.delete_all
all_runtime_metadata.delete_all
end
deployment&.sync_status_with(self)
::Gitlab::Ci::Pipeline::Metrics
.job_failure_reason_counter
.increment(reason: :data_integrity_failure)
Gitlab::AppLogger.info(
message: 'Build doomed',
class: self.class.name,
build_id: id,
pipeline_id: pipeline_id,
project_id: project_id)
end
|
#drop_with_exit_code!(failure_reason, exit_code) ⇒ Object
1121
1122
1123
1124
1125
1126
|
# File 'app/models/ci/build.rb', line 1121
def drop_with_exit_code!(failure_reason, exit_code)
failure_reason ||= :unknown_failure
result = drop!(::Gitlab::Ci::Build::Status::Reason.new(self, failure_reason, exit_code))
::Ci::TrackFailedBuildWorker.perform_async(id, exit_code, failure_reason)
result
end
|
#each_report(report_types) ⇒ Object
1171
1172
1173
1174
1175
1176
1177
1178
1179
|
# File 'app/models/ci/build.rb', line 1171
def each_report(report_types)
job_artifacts_for_types(report_types).each do |report_artifact|
next if report_artifact&.artifact_report&.faulty?
report_artifact.each_blob do |blob|
yield report_artifact.file_type, blob, report_artifact
end
end
end
|
#erasable? ⇒ Boolean
871
872
873
|
# File 'app/models/ci/build.rb', line 871
def erasable?
complete? && (artifacts? || has_job_artifacts? || has_trace?)
end
|
#erased? ⇒ Boolean
875
876
877
|
# File 'app/models/ci/build.rb', line 875
def erased?
!erased_at.nil?
end
|
#execute_hooks ⇒ Object
818
819
820
821
822
823
824
825
826
|
# File 'app/models/ci/build.rb', line 818
def execute_hooks
return unless project
return if user&.blocked?
ActiveRecord::Associations::Preloader.new(records: [self], associations: { runner: :tags }).call
project.execute_hooks(build_data.dup, :job_hooks) if project.has_active_hooks?(:job_hooks)
project.execute_integrations(build_data.dup, :job_hooks) if project.has_active_integrations?(:job_hooks)
end
|
#exit_code=(value) ⇒ Object
461
462
463
464
465
|
# File 'app/models/ci/build.rb', line 461
def exit_code=(value)
return unless value
ensure_metadata.exit_code = value.to_i.clamp(0, Gitlab::Database::MAX_SMALLINT_VALUE)
end
|
#exit_codes_defined? ⇒ Boolean
1128
1129
1130
|
# File 'app/models/ci/build.rb', line 1128
def exit_codes_defined?
options.dig(:allow_failure_criteria, :exit_codes).present? || options.dig(:retry, :exit_codes).present?
end
|
#fallback_cache_keys_defined? ⇒ Boolean
961
962
963
|
# File 'app/models/ci/build.rb', line 961
def fallback_cache_keys_defined?
Array.wrap(options[:cache]).any? { |cache| cache[:fallback_keys].present? }
end
|
#features ⇒ Object
675
676
677
678
679
680
|
# File 'app/models/ci/build.rb', line 675
def features
{
trace_sections: true,
failure_reasons: self.class.failure_reasons.keys
}
end
|
#google_play_variables ⇒ Object
651
652
653
654
655
|
# File 'app/models/ci/build.rb', line 651
def google_play_variables
return [] unless google_play_integration.try(:activated?)
Gitlab::Ci::Variables::Collection.new(google_play_integration.ci_variables(protected_ref: pipeline.protected_ref?))
end
|
#harbor_variables ⇒ Object
639
640
641
642
643
|
# File 'app/models/ci/build.rb', line 639
def harbor_variables
return [] unless harbor_integration.try(:activated?)
Gitlab::Ci::Variables::Collection.new(harbor_integration.ci_variables)
end
|
#has_archived_trace? ⇒ Boolean
718
719
720
|
# File 'app/models/ci/build.rb', line 718
def has_archived_trace?
trace.archived?
end
|
#has_expired_locked_archive_artifacts? ⇒ Boolean
892
893
894
895
|
# File 'app/models/ci/build.rb', line 892
def has_expired_locked_archive_artifacts?
locked_artifacts? &&
artifacts_expire_at&.past?
end
|
#has_expiring_archive_artifacts? ⇒ Boolean
897
898
899
|
# File 'app/models/ci/build.rb', line 897
def has_expiring_archive_artifacts?
has_expiring_artifacts? && job_artifacts_archive.present?
end
|
#has_job_artifacts? ⇒ Boolean
753
754
755
|
# File 'app/models/ci/build.rb', line 753
def has_job_artifacts?
job_artifacts.any?
end
|
#has_live_trace? ⇒ Boolean
714
715
716
|
# File 'app/models/ci/build.rb', line 714
def has_live_trace?
trace.live?
end
|
798
799
800
|
# File 'app/models/ci/build.rb', line 798
def has_tags?
tag_list.any?
end
|
#has_terminal? ⇒ Boolean
1025
1026
1027
|
# File 'app/models/ci/build.rb', line 1025
def has_terminal?
running? && runner_session_url.present?
end
|
#has_test_reports? ⇒ Boolean
757
758
759
|
# File 'app/models/ci/build.rb', line 757
def has_test_reports?
job_artifacts.of_report_type(:test).exists?
end
|
#has_trace? ⇒ Boolean
710
711
712
|
# File 'app/models/ci/build.rb', line 710
def has_trace?
trace.exist?
end
|
#has_valid_build_dependencies? ⇒ Boolean
969
970
971
|
# File 'app/models/ci/build.rb', line 969
def has_valid_build_dependencies?
dependencies.valid?
end
|
#hide_secrets(data, metrics = ::Gitlab::Ci::Trace::Metrics.new) ⇒ Object
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
|
# File 'app/models/ci/build.rb', line 1010
def hide_secrets(data, metrics = ::Gitlab::Ci::Trace::Metrics.new)
return unless trace
data.dup.tap do |trace|
Gitlab::Ci::MaskSecret.mask!(trace, project.runners_token) if project
Gitlab::Ci::MaskSecret.mask!(trace, token) if token
metrics.increment_trace_operation(operation: :mutated) if trace != data
end
end
|
#invalid_dependencies ⇒ Object
973
974
975
|
# File 'app/models/ci/build.rb', line 973
def invalid_dependencies
dependencies.invalid_local
end
|
#job_artifact_types ⇒ Object
1192
1193
1194
|
# File 'app/models/ci/build.rb', line 1192
def job_artifact_types
job_artifacts.map(&:file_type)
end
|
#job_variables_attributes ⇒ Object
1154
1155
1156
1157
1158
1159
1160
1161
1162
|
# File 'app/models/ci/build.rb', line 1154
def job_variables_attributes
strong_memoize(:job_variables_attributes) do
job_variables.internal_source.map do |variable|
variable.attributes.except('id', 'job_id', 'encrypted_value', 'encrypted_value_iv').tap do |attrs|
attrs[:value] = variable.value
end
end
end
end
|
#keep_artifacts! ⇒ Object
906
907
908
909
|
# File 'app/models/ci/build.rb', line 906
def keep_artifacts!
update(artifacts_expire_at: nil)
job_artifacts.update_all(expire_at: nil)
end
|
#locked_artifacts? ⇒ Boolean
738
739
740
|
# File 'app/models/ci/build.rb', line 738
def locked_artifacts?
pipeline.artifacts_locked? && artifacts_file&.exists?
end
|
#max_test_cases_per_report ⇒ Object
1108
1109
1110
1111
1112
|
# File 'app/models/ci/build.rb', line 1108
def max_test_cases_per_report
::Gitlab.com? ? 500_000 : 0
end
|
#merge_request ⇒ Object
682
683
684
685
686
|
# File 'app/models/ci/build.rb', line 682
def merge_request
strong_memoize(:merge_request) do
pipeline.all_merge_requests.order(iid: :asc).first
end
end
|
#multi_build_steps? ⇒ Boolean
1006
1007
1008
|
# File 'app/models/ci/build.rb', line 1006
def multi_build_steps?
options[:release]&.any?
end
|
#needs_touch? ⇒ Boolean
773
774
775
|
# File 'app/models/ci/build.rb', line 773
def needs_touch?
Time.current - updated_at > 15.minutes.to_i
end
|
#options_scheduled_at ⇒ Object
525
526
527
|
# File 'app/models/ci/build.rb', line 525
def options_scheduled_at
ChronicDuration.parse(options[:start_in])&.seconds&.from_now
end
|
#other_scheduled_actions ⇒ Object
477
478
479
|
# File 'app/models/ci/build.rb', line 477
def other_scheduled_actions
pipeline.scheduled_actions.reject { |action| action.name == name }
end
|
#pages ⇒ Object
Overriden on EE rubocop:disable Gitlab/NoCodeCoverageComment – Fully tested in EE and tested in Foss through feature specs in spec/models/ci/build_spec.rb :nocov:
491
492
493
|
# File 'app/models/ci/build.rb', line 491
def pages
{}
end
|
#pages_generator? ⇒ Boolean
481
482
483
484
485
486
|
# File 'app/models/ci/build.rb', line 481
def pages_generator?
return false unless Gitlab.config.pages.enabled
return true if options[:pages].is_a?(Hash) || options[:pages] == true
options[:pages] != false && name == 'pages' end
|
#pages_variables ⇒ Object
663
664
665
666
667
668
669
670
671
672
673
|
# File 'app/models/ci/build.rb', line 663
def pages_variables
::Gitlab::Ci::Variables::Collection.new.tap do |variables|
next variables unless pages_generator? && Feature.enabled?(:fix_pages_ci_variables, project)
pages_url_builder = ::Gitlab::Pages::UrlBuilder.new(project, pages)
variables
.append(key: 'CI_PAGES_HOSTNAME', value: pages_url_builder.hostname)
.append(key: 'CI_PAGES_URL', value: pages_url_builder.pages_url)
end
end
|
#persisted_environment_variables ⇒ Object
608
609
610
611
612
613
614
615
616
617
618
619
|
# File 'app/models/ci/build.rb', line 608
def persisted_environment_variables
Gitlab::Ci::Variables::Collection.new.tap do |variables|
break variables unless persisted? && persisted_environment.present?
variables.append(key: 'CI_ENVIRONMENT_SLUG', value: environment_slug)
variables.append(key: 'CI_ENVIRONMENT_URL', value: environment_url) if environment_url
end
end
|
#persisted_variables ⇒ Object
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
|
# File 'app/models/ci/build.rb', line 587
def persisted_variables
Gitlab::Ci::Variables::Collection.new.tap do |variables|
break variables unless persisted?
variables
.concat(pipeline.persisted_variables)
.append(key: 'CI_JOB_ID', value: id.to_s)
.append(key: 'CI_JOB_URL', value: Gitlab::Routing.url_helpers.project_job_url(project, self))
.append(key: 'CI_JOB_TOKEN', value: token.to_s, public: false, masked: true)
.append(key: 'CI_JOB_STARTED_AT', value: started_at&.iso8601)
.append(key: 'CI_REGISTRY_USER', value: ::Gitlab::Auth::CI_JOB_USER)
.append(key: 'CI_REGISTRY_PASSWORD', value: token.to_s, public: false, masked: true)
.append(key: 'CI_REPOSITORY_URL', value: repo_url.to_s, public: false)
.concat(deploy_token_variables)
.concat(harbor_variables)
.concat(apple_app_store_variables)
.concat(google_play_variables)
.concat(diffblue_cover_variables)
end
end
|
#play(current_user, job_variables_attributes = nil) ⇒ Object
rubocop: disable CodeReuse/ServiceClass
539
540
541
542
543
|
# File 'app/models/ci/build.rb', line 539
def play(current_user, job_variables_attributes = nil)
Ci::PlayBuildService
.new(project, current_user)
.execute(self, job_variables_attributes)
end
|
#playable? ⇒ Boolean
517
518
519
|
# File 'app/models/ci/build.rb', line 517
def playable?
action? && !archived? && (manual? || scheduled? || retryable?)
end
|
#publishes_artifacts_reports? ⇒ Boolean
998
999
1000
|
# File 'app/models/ci/build.rb', line 998
def publishes_artifacts_reports?
options&.dig(:artifacts, :reports)&.any?
end
|
#remove_pending_state! ⇒ Object
1100
1101
1102
|
# File 'app/models/ci/build.rb', line 1100
def remove_pending_state!
pending_state.try(:delete)
end
|
#remove_token! ⇒ Object
786
787
788
|
# File 'app/models/ci/build.rb', line 786
def remove_token!
update!(token_encrypted: nil)
end
|
#repo_url ⇒ Object
688
689
690
691
692
693
694
695
|
# File 'app/models/ci/build.rb', line 688
def repo_url
return unless token
auth = "#{::Gitlab::Auth::CI_JOB_USER}:#{token}@"
project.http_url_to_repo.sub(%r{^https?://}) do |prefix|
prefix + auth
end
end
|
#report_artifacts ⇒ Object
1061
1062
1063
|
# File 'app/models/ci/build.rb', line 1061
def report_artifacts
job_artifacts.all_reports
end
|
#retries_count ⇒ Object
550
551
552
|
# File 'app/models/ci/build.rb', line 550
def retries_count
pipeline.builds.retried.where(name: name).count
end
|
#run_on_status_commit(&block) ⇒ Object
1104
1105
1106
|
# File 'app/models/ci/build.rb', line 1104
def run_on_status_commit(&block)
status_commit_hooks.push(block)
end
|
#runnable? ⇒ Boolean
rubocop:enable Gitlab/NoCodeCoverageComment
496
497
498
|
# File 'app/models/ci/build.rb', line 496
def runnable?
true
end
|
#runner_required_feature_names ⇒ Object
984
985
986
987
988
989
990
|
# File 'app/models/ci/build.rb', line 984
def runner_required_feature_names
strong_memoize(:runner_required_feature_names) do
RUNNER_FEATURES.select do |feature, method|
method.call(self)
end.keys
end
end
|
#schedulable? ⇒ Boolean
521
522
523
|
# File 'app/models/ci/build.rb', line 521
def schedulable?
self.when == 'delayed' && options[:start_in].present?
end
|
#serializable_hash(options = {}) ⇒ Object
1021
1022
1023
|
# File 'app/models/ci/build.rb', line 1021
def serializable_hash(options = {})
super(options).merge(when: read_attribute(:when))
end
|
#shared_runner_build? ⇒ Boolean
1150
1151
1152
|
# File 'app/models/ci/build.rb', line 1150
def shared_runner_build?
runner&.instance_type?
end
|
#source ⇒ Object
1211
1212
1213
|
# File 'app/models/ci/build.rb', line 1211
def source
build_source&.source || pipeline.source
end
|
#stuck? ⇒ Boolean
814
815
816
|
# File 'app/models/ci/build.rb', line 814
def stuck?
pending? && !any_runners_online?
end
|
#supported_runner?(features) ⇒ Boolean
992
993
994
995
996
|
# File 'app/models/ci/build.rb', line 992
def supported_runner?(features)
runner_required_feature_names.all? do |feature_name|
features&.dig(feature_name)
end
end
|
#supports_artifacts_exclude? ⇒ Boolean
1002
1003
1004
|
# File 'app/models/ci/build.rb', line 1002
def supports_artifacts_exclude?
options&.dig(:artifacts, :exclude)&.any?
end
|
#supports_canceling? ⇒ Boolean
A Ci::Bridge may transition to ‘canceling` as a result of strategy: :depend but only a Ci::Build will transition to `canceling“ via `.cancel`
442
443
444
|
# File 'app/models/ci/build.rb', line 442
def supports_canceling?
cancel_gracefully?
end
|
#tag_list ⇒ Object
790
791
792
793
794
795
796
|
# File 'app/models/ci/build.rb', line 790
def tag_list
if tags.loaded?
tags.map(&:name)
else
super
end
end
|
436
437
438
|
# File 'app/models/ci/build.rb', line 436
def tags_ids_relation
simple_tags
end
|
#test_suite_name ⇒ Object
1196
1197
1198
1199
1200
1201
1202
|
# File 'app/models/ci/build.rb', line 1196
def test_suite_name
if matrix_build?
name
else
group_name
end
end
|
#time_in_queue_seconds ⇒ Object
1204
1205
1206
1207
1208
|
# File 'app/models/ci/build.rb', line 1204
def time_in_queue_seconds
return if queued_at.nil?
(::Time.current - queued_at).seconds.to_i
end
|
#to_partial_path ⇒ Object
Can be removed in Rails 7.1. Related to: Gitlab.next_rails?
1217
1218
1219
|
# File 'app/models/ci/build.rb', line 1217
def to_partial_path
'jobs/job'
end
|
#token ⇒ Object
1221
1222
1223
1224
1225
|
# File 'app/models/ci/build.rb', line 1221
def token
return encoded_jwt if user&.has_composite_identity? || Feature.enabled?(:ci_job_token_jwt, user)
super
end
|
#trace ⇒ Object
706
707
708
|
# File 'app/models/ci/build.rb', line 706
def trace
Gitlab::Ci::Trace.new(self)
end
|
#triggered_by?(current_user) ⇒ Boolean
567
568
569
|
# File 'app/models/ci/build.rb', line 567
def triggered_by?(current_user)
user == current_user
end
|
#update_coverage ⇒ Object
701
702
703
704
|
# File 'app/models/ci/build.rb', line 701
def update_coverage
coverage = trace.(coverage_regex)
update(coverage: coverage) if coverage.present?
end
|
#valid_dependency? ⇒ Boolean
977
978
979
980
981
982
|
# File 'app/models/ci/build.rb', line 977
def valid_dependency?
return false if artifacts_expired? && !pipeline.artifacts_locked?
return false if erased?
true
end
|
#valid_token?(token) ⇒ Boolean
777
778
779
780
781
782
783
784
|
# File 'app/models/ci/build.rb', line 777
def valid_token?(token)
jwt = ::Ci::JobToken::Jwt.decode(token)
if jwt
jwt.job == self
else
self.token && token.present? && ActiveSupport::SecurityUtils.secure_compare(token, self.token)
end
end
|
#variables ⇒ Object
All variables, including persisted environment variables.
574
575
576
577
578
579
580
581
582
583
584
585
|
# File 'app/models/ci/build.rb', line 574
def variables
strong_memoize(:variables) do
Gitlab::Ci::Variables::Collection.new
.concat(persisted_variables)
.concat(dependency_proxy_variables)
.concat(job_jwt_variables)
.concat(scoped_variables)
.concat(pages_variables)
.concat(job_variables)
.concat(persisted_environment_variables)
end
end
|