summaryrefslogtreecommitdiff
path: root/app/models/ci
diff options
context:
space:
mode:
Diffstat (limited to 'app/models/ci')
-rw-r--r--app/models/ci/build.rb26
-rw-r--r--app/models/ci/build_need.rb1
-rw-r--r--app/models/ci/build_report_result.rb4
-rw-r--r--app/models/ci/daily_build_group_report_result.rb14
-rw-r--r--app/models/ci/deleted_object.rb4
-rw-r--r--app/models/ci/group.rb2
-rw-r--r--app/models/ci/group_variable.rb4
-rw-r--r--app/models/ci/job_artifact.rb10
-rw-r--r--app/models/ci/legacy_stage.rb2
-rw-r--r--app/models/ci/pipeline.rb33
-rw-r--r--app/models/ci/processable.rb4
-rw-r--r--app/models/ci/ref.rb2
-rw-r--r--app/models/ci/runner.rb40
-rw-r--r--app/models/ci/runner_namespace.rb9
-rw-r--r--app/models/ci/stage.rb4
-rw-r--r--app/models/ci/variable.rb1
16 files changed, 92 insertions, 68 deletions
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index db151126caf..824e35a6480 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -486,6 +486,10 @@ module Ci
self.options.fetch(:environment, {}).fetch(:action, 'start') if self.options
end
+ def environment_deployment_tier
+ self.options.dig(:environment, :deployment_tier) if self.options
+ end
+
def outdated_deployment?
success? && !deployment.try(:last?)
end
@@ -510,7 +514,6 @@ module Ci
.concat(scoped_variables)
.concat(job_variables)
.concat(persisted_environment_variables)
- .to_runner_variables
end
end
@@ -523,6 +526,7 @@ module Ci
.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_BUILD_ID', value: id.to_s)
.append(key: 'CI_BUILD_TOKEN', value: token.to_s, public: false, masked: true)
.append(key: 'CI_REGISTRY_USER', value: ::Gitlab::Auth::CI_JOB_USER)
@@ -564,7 +568,10 @@ module Ci
end
def features
- { trace_sections: true }
+ {
+ trace_sections: true,
+ failure_reasons: self.class.failure_reasons.keys
+ }
end
def merge_request
@@ -691,7 +698,7 @@ module Ci
end
def any_runners_online?
- project.any_runners? { |runner| runner.active? && runner.online? && runner.can_pick?(self) }
+ project.any_active_runners? { |runner| runner.match_build_if_online?(self) }
end
def stuck?
@@ -810,14 +817,15 @@ module Ci
end
def cache
- cache = options[:cache]
+ cache = Array.wrap(options[:cache])
- if cache && project.jobs_cache_index
- cache = cache.merge(
- key: "#{cache[:key]}-#{project.jobs_cache_index}")
+ if project.jobs_cache_index
+ cache = cache.map do |single_cache|
+ single_cache.merge(key: "#{single_cache[:key]}-#{project.jobs_cache_index}")
+ end
end
- [cache]
+ cache
end
def credentials
@@ -983,7 +991,7 @@ module Ci
# TODO: Have `debug_mode?` check against data on sent back from runner
# to capture all the ways that variables can be set.
# See (https://gitlab.com/gitlab-org/gitlab/-/issues/290955)
- variables.any? { |variable| variable[:key] == 'CI_DEBUG_TRACE' && variable[:value].casecmp('true') == 0 }
+ variables['CI_DEBUG_TRACE']&.value&.casecmp('true') == 0
end
def drop_with_exit_code!(failure_reason, exit_code)
diff --git a/app/models/ci/build_need.rb b/app/models/ci/build_need.rb
index fac615f97b9..7bc70f9f1e1 100644
--- a/app/models/ci/build_need.rb
+++ b/app/models/ci/build_need.rb
@@ -10,6 +10,7 @@ module Ci
validates :build, presence: true
validates :name, presence: true, length: { maximum: 128 }
+ validates :optional, inclusion: { in: [true, false] }
scope :scoped_build, -> { where('ci_builds.id=ci_build_needs.build_id') }
scope :artifacts, -> { where(artifacts: true) }
diff --git a/app/models/ci/build_report_result.rb b/app/models/ci/build_report_result.rb
index 530233ad5c0..eb6a0700006 100644
--- a/app/models/ci/build_report_result.rb
+++ b/app/models/ci/build_report_result.rb
@@ -38,6 +38,10 @@ module Ci
tests.dig("skipped").to_i
end
+ def suite_error
+ tests.dig("suite_error")
+ end
+
def tests_total
[tests_success, tests_failed, tests_errored, tests_skipped].sum
end
diff --git a/app/models/ci/daily_build_group_report_result.rb b/app/models/ci/daily_build_group_report_result.rb
index 23c96e63724..5dcf575abd7 100644
--- a/app/models/ci/daily_build_group_report_result.rb
+++ b/app/models/ci/daily_build_group_report_result.rb
@@ -4,7 +4,6 @@ module Ci
class DailyBuildGroupReportResult < ApplicationRecord
extend Gitlab::Ci::Model
- REPORT_WINDOW = 90.days
PARAM_TYPES = %w[coverage].freeze
belongs_to :last_pipeline, class_name: 'Ci::Pipeline', foreign_key: :last_pipeline_id
@@ -13,13 +12,11 @@ module Ci
validates :data, json_schema: { filename: "daily_build_group_report_result_data" }
- scope :with_included_projects, -> { includes(:project) }
scope :by_ref_path, -> (ref_path) { where(ref_path: ref_path) }
scope :by_projects, -> (ids) { where(project_id: ids) }
scope :by_group, -> (group_id) { where(group_id: group_id) }
scope :with_coverage, -> { where("(data->'coverage') IS NOT NULL") }
scope :with_default_branch, -> { where(default_branch: true) }
- scope :by_date, -> (start_date) { where(date: report_window(start_date)..Date.current) }
scope :by_dates, -> (start_date, end_date) { where(date: start_date..end_date) }
scope :ordered_by_date_and_group_name, -> { order(date: :desc, group_name: :asc) }
@@ -29,17 +26,6 @@ module Ci
def upsert_reports(data)
upsert_all(data, unique_by: :index_daily_build_group_report_results_unique_columns) if data.any?
end
-
- def recent_results(attrs, limit: nil)
- where(attrs).order(date: :desc, group_name: :asc).limit(limit)
- end
-
- def report_window(start_date)
- default_date = REPORT_WINDOW.ago.to_date
- date = Date.parse(start_date) rescue default_date
-
- [date, default_date].max
- end
end
end
end
diff --git a/app/models/ci/deleted_object.rb b/app/models/ci/deleted_object.rb
index e74946eda16..2942a153e05 100644
--- a/app/models/ci/deleted_object.rb
+++ b/app/models/ci/deleted_object.rb
@@ -17,9 +17,9 @@ module Ci
.lock('FOR UPDATE SKIP LOCKED')
end
- def self.bulk_import(artifacts)
+ def self.bulk_import(artifacts, pick_up_at = nil)
attributes = artifacts.each.with_object([]) do |artifact, accumulator|
- record = artifact.to_deleted_object_attrs
+ record = artifact.to_deleted_object_attrs(pick_up_at)
accumulator << record if record[:store_dir] && record[:file]
end
diff --git a/app/models/ci/group.rb b/app/models/ci/group.rb
index c7c0ec61e62..4ba09fd8152 100644
--- a/app/models/ci/group.rb
+++ b/app/models/ci/group.rb
@@ -39,7 +39,7 @@ module Ci
def status_struct
strong_memoize(:status_struct) do
Gitlab::Ci::Status::Composite
- .new(@jobs)
+ .new(@jobs, project: project)
end
end
diff --git a/app/models/ci/group_variable.rb b/app/models/ci/group_variable.rb
index 1e1dd68ee6c..2928ce801ad 100644
--- a/app/models/ci/group_variable.rb
+++ b/app/models/ci/group_variable.rb
@@ -6,16 +6,18 @@ module Ci
include Ci::HasVariable
include Presentable
include Ci::Maskable
+ prepend HasEnvironmentScope
belongs_to :group, class_name: "::Group"
alias_attribute :secret_value, :value
validates :key, uniqueness: {
- scope: :group_id,
+ scope: [:group_id, :environment_scope],
message: "(%{value}) has already been taken"
}
scope :unprotected, -> { where(protected: false) }
+ scope :by_environment_scope, -> (environment_scope) { where(environment_scope: environment_scope) }
end
end
diff --git a/app/models/ci/job_artifact.rb b/app/models/ci/job_artifact.rb
index f927111758a..d5e88f2be5b 100644
--- a/app/models/ci/job_artifact.rb
+++ b/app/models/ci/job_artifact.rb
@@ -136,11 +136,7 @@ module Ci
scope :for_sha, ->(sha, project_id) { joins(job: :pipeline).where(ci_pipelines: { sha: sha, project_id: project_id }) }
scope :for_job_name, ->(name) { joins(:job).where(ci_builds: { name: name }) }
- scope :with_job, -> do
- if Feature.enabled?(:non_public_artifacts, type: :development)
- joins(:job).includes(:job)
- end
- end
+ scope :with_job, -> { joins(:job).includes(:job) }
scope :with_file_types, -> (file_types) do
types = self.file_types.select { |file_type| file_types.include?(file_type) }.values
@@ -311,12 +307,12 @@ module Ci
max_size&.megabytes.to_i
end
- def to_deleted_object_attrs
+ def to_deleted_object_attrs(pick_up_at = nil)
{
file_store: file_store,
store_dir: file.store_dir.to_s,
file: file_identifier,
- pick_up_at: expire_at || Time.current
+ pick_up_at: pick_up_at || expire_at || Time.current
}
end
diff --git a/app/models/ci/legacy_stage.rb b/app/models/ci/legacy_stage.rb
index df4368eccd5..ffd3d3fcd88 100644
--- a/app/models/ci/legacy_stage.rb
+++ b/app/models/ci/legacy_stage.rb
@@ -32,7 +32,7 @@ module Ci
end
def status
- @status ||= statuses.latest.composite_status
+ @status ||= statuses.latest.composite_status(project: project)
end
def detailed_status(current_user)
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index 3be107ea2e1..b63ec0c8a97 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -228,7 +228,7 @@ module Ci
pipeline.run_after_commit do
PipelineHooksWorker.perform_async(pipeline.id)
- ExpirePipelineCacheWorker.perform_async(pipeline.id) if pipeline.cacheable?
+ ExpirePipelineCacheWorker.perform_async(pipeline.id)
end
end
@@ -573,7 +573,7 @@ module Ci
end
def cancel_running(retries: nil)
- retry_optimistic_lock(cancelable_statuses, retries) do |cancelable|
+ retry_optimistic_lock(cancelable_statuses, retries, name: 'ci_pipeline_cancel_running') do |cancelable|
cancelable.find_each do |job|
yield(job) if block_given?
job.cancel
@@ -693,14 +693,6 @@ module Ci
.exists?
end
- # TODO: this logic is duplicate with Pipeline::Chain::Config::Content
- # we should persist this is `ci_pipelines.config_path`
- def config_path
- return unless repository_source? || unknown_source?
-
- project.ci_config_path_or_default
- end
-
def has_yaml_errors?
yaml_errors.present?
end
@@ -744,7 +736,7 @@ module Ci
end
def set_status(new_status)
- retry_optimistic_lock(self) do
+ retry_optimistic_lock(self, name: 'ci_pipeline_set_status') do
case new_status
when 'created' then nil
when 'waiting_for_resource' then request_resource
@@ -785,8 +777,7 @@ module Ci
Gitlab::Ci::Variables::Collection.new.tap do |variables|
variables.append(key: 'CI_PIPELINE_IID', value: iid.to_s)
variables.append(key: 'CI_PIPELINE_SOURCE', value: source.to_s)
-
- variables.append(key: 'CI_CONFIG_PATH', value: config_path)
+ variables.append(key: 'CI_PIPELINE_CREATED_AT', value: created_at&.iso8601)
variables.concat(predefined_commit_variables)
@@ -938,6 +929,12 @@ module Ci
.first
end
+ def self_with_ancestors_and_descendants(same_project: false)
+ ::Gitlab::Ci::PipelineObjectHierarchy
+ .new(self.class.unscoped.where(id: id), options: { same_project: same_project })
+ .all_objects
+ end
+
def bridge_triggered?
source_bridge.present?
end
@@ -1117,7 +1114,7 @@ module Ci
detached_merge_request_pipeline? && !merge_request_ref?
end
- def merge_request_pipeline?
+ def merged_result_pipeline?
merge_request? && target_sha.present?
end
@@ -1157,7 +1154,7 @@ module Ci
return unless merge_request?
strong_memoize(:merge_request_event_type) do
- if merge_request_pipeline?
+ if merged_result_pipeline?
:merged_result
elsif detached_merge_request_pipeline?
:detached
@@ -1169,10 +1166,6 @@ module Ci
@persistent_ref ||= PersistentRef.new(pipeline: self)
end
- def cacheable?
- !dangling?
- end
-
def dangling?
Enums::Ci::Pipeline.dangling_sources.key?(source.to_sym)
end
@@ -1247,7 +1240,7 @@ module Ci
def merge_request_diff_sha
return unless merge_request?
- if merge_request_pipeline?
+ if merged_result_pipeline?
source_sha
else
sha
diff --git a/app/models/ci/processable.rb b/app/models/ci/processable.rb
index fae65ed0632..0ad1ed2fce8 100644
--- a/app/models/ci/processable.rb
+++ b/app/models/ci/processable.rb
@@ -120,10 +120,6 @@ module Ci
raise NotImplementedError
end
- def scoped_variables_hash
- raise NotImplementedError
- end
-
override :all_met_to_become_pending?
def all_met_to_become_pending?
super && !with_resource_group?
diff --git a/app/models/ci/ref.rb b/app/models/ci/ref.rb
index 713a0bf9c45..3d71a5f2c96 100644
--- a/app/models/ci/ref.rb
+++ b/app/models/ci/ref.rb
@@ -62,7 +62,7 @@ module Ci
end
def update_status_by!(pipeline)
- retry_lock(self) do
+ retry_lock(self, name: 'ci_ref_update_status_by') do
next unless last_finished_pipeline_id == pipeline.id
case pipeline.status
diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb
index 44a00e36bcc..d1a20bc93c3 100644
--- a/app/models/ci/runner.rb
+++ b/app/models/ci/runner.rb
@@ -9,6 +9,7 @@ module Ci
include FromUnion
include TokenAuthenticatable
include IgnorableColumns
+ include FeatureGate
add_authentication_token_field :token, encrypted: -> { Feature.enabled?(:ci_runners_tokens_optional_encryption, default_enabled: true) ? :optional : :required }
@@ -251,10 +252,21 @@ module Ci
runner_projects.any?
end
+ # TODO: remove this method in favor of `matches_build?` once feature flag is removed
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/323317
def can_pick?(build)
- return false if self.ref_protected? && !build.protected?
+ if Feature.enabled?(:ci_runners_short_circuit_assignable_for, self, default_enabled: :yaml)
+ matches_build?(build)
+ else
+ # Run `matches_build?` checks before, since they are cheaper than
+ # `assignable_for?`.
+ #
+ matches_build?(build) && assignable_for?(build.project_id)
+ end
+ end
- assignable_for?(build.project_id) && accepting_tags?(build)
+ def match_build_if_online?(build)
+ active? && online? && can_pick?(build)
end
def only_for?(project)
@@ -265,6 +277,16 @@ module Ci
token[0...8] if token
end
+ def tag_list
+ return super unless Feature.enabled?(:ci_preload_runner_tags, default_enabled: :yaml)
+
+ if tags.loaded?
+ tags.map(&:name)
+ else
+ super
+ end
+ end
+
def has_tags?
tag_list.any?
end
@@ -304,8 +326,10 @@ module Ci
end
def pick_build!(build)
- if can_pick?(build)
- tick_runner_queue
+ if Feature.enabled?(:ci_reduce_queries_when_ticking_runner_queue, self, default_enabled: :yaml)
+ tick_runner_queue if matches_build?(build)
+ else
+ tick_runner_queue if can_pick?(build)
end
end
@@ -341,6 +365,8 @@ module Ci
end
end
+ # TODO: remove this method once feature flag ci_runners_short_circuit_assignable_for
+ # is removed. https://gitlab.com/gitlab-org/gitlab/-/issues/323317
def assignable_for?(project_id)
self.class.owned_or_instance_wide(project_id).where(id: self.id).any?
end
@@ -369,6 +395,12 @@ module Ci
end
end
+ def matches_build?(build)
+ return false if self.ref_protected? && !build.protected?
+
+ accepting_tags?(build)
+ end
+
def accepting_tags?(build)
(run_untagged? || build.has_tags?) && (build.tag_list - tag_list).empty?
end
diff --git a/app/models/ci/runner_namespace.rb b/app/models/ci/runner_namespace.rb
index 6903e8a21a1..e6c1899c89d 100644
--- a/app/models/ci/runner_namespace.rb
+++ b/app/models/ci/runner_namespace.rb
@@ -4,10 +4,17 @@ module Ci
class RunnerNamespace < ApplicationRecord
extend Gitlab::Ci::Model
- belongs_to :runner, inverse_of: :runner_namespaces, validate: true
+ belongs_to :runner, inverse_of: :runner_namespaces
belongs_to :namespace, inverse_of: :runner_namespaces, class_name: '::Namespace'
belongs_to :group, class_name: '::Group', foreign_key: :namespace_id
validates :runner_id, uniqueness: { scope: :namespace_id }
+ validate :group_runner_type
+
+ private
+
+ def group_runner_type
+ errors.add(:runner, 'is not a group runner') unless runner&.group_type?
+ end
end
end
diff --git a/app/models/ci/stage.rb b/app/models/ci/stage.rb
index ae80692d598..03a97355574 100644
--- a/app/models/ci/stage.rb
+++ b/app/models/ci/stage.rb
@@ -84,7 +84,7 @@ module Ci
end
def set_status(new_status)
- retry_optimistic_lock(self) do
+ retry_optimistic_lock(self, name: 'ci_stage_set_status') do
case new_status
when 'created' then nil
when 'waiting_for_resource' then request_resource
@@ -138,7 +138,7 @@ module Ci
end
def latest_stage_status
- statuses.latest.composite_status || 'skipped'
+ statuses.latest.composite_status(project: project) || 'skipped'
end
end
end
diff --git a/app/models/ci/variable.rb b/app/models/ci/variable.rb
index 13358b95a47..84505befc5c 100644
--- a/app/models/ci/variable.rb
+++ b/app/models/ci/variable.rb
@@ -18,7 +18,6 @@ module Ci
}
scope :unprotected, -> { where(protected: false) }
- scope :by_key, -> (key) { where(key: key) }
scope :by_environment_scope, -> (environment_scope) { where(environment_scope: environment_scope) }
end
end