summaryrefslogtreecommitdiff
path: root/app/models/ci
diff options
context:
space:
mode:
Diffstat (limited to 'app/models/ci')
-rw-r--r--app/models/ci/bridge.rb20
-rw-r--r--app/models/ci/build.rb36
-rw-r--r--app/models/ci/job_artifact.rb5
-rw-r--r--app/models/ci/namespace_mirror.rb20
-rw-r--r--app/models/ci/pipeline.rb14
-rw-r--r--app/models/ci/processable.rb6
-rw-r--r--app/models/ci/secure_file.rb8
7 files changed, 86 insertions, 23 deletions
diff --git a/app/models/ci/bridge.rb b/app/models/ci/bridge.rb
index 2ff777bfc89..ff444ddefa3 100644
--- a/app/models/ci/bridge.rb
+++ b/app/models/ci/bridge.rb
@@ -57,10 +57,6 @@ module Ci
end
end
- def self.retry(bridge, current_user)
- raise NotImplementedError
- end
-
def self.with_preloads
preload(
:metadata,
@@ -69,6 +65,10 @@ module Ci
)
end
+ def retryable?
+ false
+ end
+
def inherit_status_from_downstream!(pipeline)
case pipeline.status
when 'success'
@@ -274,7 +274,8 @@ module Ci
# The order of this list refers to the priority of the variables
downstream_yaml_variables(expand_variables) +
- downstream_pipeline_variables(expand_variables)
+ downstream_pipeline_variables(expand_variables) +
+ downstream_pipeline_schedule_variables(expand_variables)
end
def downstream_yaml_variables(expand_variables)
@@ -293,6 +294,15 @@ module Ci
end
end
+ def downstream_pipeline_schedule_variables(expand_variables)
+ return [] unless forward_pipeline_variables?
+ return [] unless pipeline.pipeline_schedule
+
+ pipeline.pipeline_schedule.variables.to_a.map do |variable|
+ { key: variable.key, value: ::ExpandVariables.expand(variable.value, expand_variables) }
+ end
+ end
+
def forward_yaml_variables?
strong_memoize(:forward_yaml_variables) do
result = options&.dig(:trigger, :forward, :yaml_variables)
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index 68ec196a9ee..16c9aa212d0 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -218,17 +218,21 @@ module Ci
pending.unstarted.order('created_at ASC').first
end
- def retry(build, current_user)
- # rubocop: disable CodeReuse/ServiceClass
- Ci::RetryBuildService
- .new(build.project, current_user)
- .execute(build)
- # rubocop: enable CodeReuse/ServiceClass
- end
-
def with_preloads
preload(:job_artifacts_archive, :job_artifacts, :tags, project: [:namespace])
end
+
+ def extra_accessors
+ []
+ end
+
+ def clone_accessors
+ %i[pipeline project ref tag options name
+ allow_failure stage stage_id stage_idx trigger_request
+ yaml_variables when environment coverage_regex
+ description tag_list protected needs_attributes
+ job_variables_attributes resource_group scheduling_type].freeze
+ end
end
state_machine :status do
@@ -351,7 +355,9 @@ module Ci
if build.auto_retry_allowed?
begin
- Ci::Build.retry(build, build.user)
+ # rubocop: disable CodeReuse/ServiceClass
+ Ci::RetryJobService.new(build.project, build.user).execute(build)
+ # rubocop: enable CodeReuse/ServiceClass
rescue Gitlab::Access::AccessDeniedError => ex
Gitlab::AppLogger.error "Unable to auto-retry job #{build.id}: #{ex}"
end
@@ -472,12 +478,6 @@ module Ci
active? || created?
end
- def retryable?
- return false if retried? || archived? || deployment_rejected?
-
- success? || failed? || canceled?
- end
-
def retries_count
pipeline.builds.retried.where(name: self.name).count
end
@@ -504,7 +504,11 @@ module Ci
if metadata&.expanded_environment_name.present?
metadata.expanded_environment_name
else
- ExpandVariables.expand(environment, -> { simple_variables })
+ if ::Feature.enabled?(:ci_expand_environment_name_and_url, project, default_enabled: :yaml)
+ ExpandVariables.expand(environment, -> { simple_variables.sort_and_expand_all })
+ else
+ ExpandVariables.expand(environment, -> { simple_variables })
+ end
end
end
end
diff --git a/app/models/ci/job_artifact.rb b/app/models/ci/job_artifact.rb
index 3426c4d5248..dff8bb89021 100644
--- a/app/models/ci/job_artifact.rb
+++ b/app/models/ci/job_artifact.rb
@@ -186,6 +186,7 @@ module Ci
scope :downloadable, -> { where(file_type: DOWNLOADABLE_TYPES) }
scope :unlocked, -> { joins(job: :pipeline).merge(::Ci::Pipeline.unlocked) }
+ scope :order_expired_asc, -> { order(expire_at: :asc) }
scope :order_expired_desc, -> { order(expire_at: :desc) }
scope :with_destroy_preloads, -> { includes(project: [:route, :statistics]) }
@@ -273,6 +274,10 @@ module Ci
self.where(project: project).sum(:size)
end
+ def self.pluck_job_id
+ pluck(:job_id)
+ end
+
##
# FastDestroyAll concerns
# rubocop: disable CodeReuse/ServiceClass
diff --git a/app/models/ci/namespace_mirror.rb b/app/models/ci/namespace_mirror.rb
index d5cbbb96134..e8f08db597f 100644
--- a/app/models/ci/namespace_mirror.rb
+++ b/app/models/ci/namespace_mirror.rb
@@ -4,6 +4,8 @@ module Ci
# This model represents a record in a shadow table of the main database's namespaces table.
# It allows us to navigate the namespace hierarchy on the ci database without resorting to a JOIN.
class NamespaceMirror < ApplicationRecord
+ include FromUnion
+
belongs_to :namespace
scope :by_group_and_descendants, -> (id) do
@@ -14,6 +16,24 @@ module Ci
where('traversal_ids && ARRAY[?]::int[]', ids)
end
+ scope :contains_traversal_ids, -> (traversal_ids) do
+ mirrors = []
+
+ traversal_ids.group_by(&:count).each do |columns_count, traversal_ids_group|
+ columns = Array.new(columns_count) { |i| "(traversal_ids[#{i + 1}])" }
+ pairs = traversal_ids_group.map do |ids|
+ ids = ids.map { |id| Arel::Nodes.build_quoted(id).to_sql }
+ "(#{ids.join(",")})"
+ end
+
+ # Create condition in format:
+ # ((traversal_ids[1]),(traversal_ids[2])) IN ((1,2),(2,3))
+ mirrors << Ci::NamespaceMirror.where("(#{columns.join(",")}) IN (#{pairs.join(",")})") # rubocop:disable GitlabSecurity/SqlInjection
+ end
+
+ self.from_union(mirrors)
+ end
+
scope :by_namespace_id, -> (namespace_id) { where(namespace_id: namespace_id) }
class << self
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index ae3ea7aa03f..2d0479e02a3 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -824,6 +824,8 @@ module Ci
variables.append(key: 'CI_OPEN_MERGE_REQUESTS', value: open_merge_requests_refs.join(','))
end
+ variables.append(key: 'CI_GITLAB_FIPS_MODE', value: 'true') if Gitlab::FIPS.enabled?
+
variables.append(key: 'CI_KUBERNETES_ACTIVE', value: 'true') if has_kubernetes_active?
variables.append(key: 'CI_DEPLOY_FREEZE', value: 'true') if freeze_period?
@@ -836,6 +838,8 @@ module Ci
def predefined_commit_variables
strong_memoize(:predefined_commit_variables) do
Gitlab::Ci::Variables::Collection.new.tap do |variables|
+ next variables unless sha.present?
+
variables.append(key: 'CI_COMMIT_SHA', value: sha)
variables.append(key: 'CI_COMMIT_SHORT_SHA', value: short_sha)
variables.append(key: 'CI_COMMIT_BEFORE_SHA', value: before_sha)
@@ -955,7 +959,7 @@ module Ci
Ci::Build.latest.where(pipeline: self_and_descendants)
end
- def environments_in_self_and_descendants
+ def environments_in_self_and_descendants(deployment_status: nil)
# We limit to 100 unique environments for application safety.
# See: https://gitlab.com/gitlab-org/gitlab/-/issues/340781#note_699114700
expanded_environment_names =
@@ -965,7 +969,7 @@ module Ci
.limit(100)
.pluck(:expanded_environment_name)
- Environment.where(project: project, name: expanded_environment_names).with_deployment(sha)
+ Environment.where(project: project, name: expanded_environment_names).with_deployment(sha, status: deployment_status)
end
# With multi-project and parent-child pipelines
@@ -1285,6 +1289,12 @@ module Ci
end
end
+ def has_expired_test_reports?
+ strong_memoize(:artifacts_expired) do
+ !has_reports?(::Ci::JobArtifact.test_reports.not_expired)
+ end
+ end
+
private
def add_message(severity, content)
diff --git a/app/models/ci/processable.rb b/app/models/ci/processable.rb
index 4d119706a43..d79ff74753a 100644
--- a/app/models/ci/processable.rb
+++ b/app/models/ci/processable.rb
@@ -101,6 +101,12 @@ module Ci
:merge_train_pipeline?,
to: :pipeline
+ def retryable?
+ return false if retried? || archived? || deployment_rejected?
+
+ success? || failed? || canceled?
+ end
+
def aggregated_needs_names
read_attribute(:aggregated_needs_names)
end
diff --git a/app/models/ci/secure_file.rb b/app/models/ci/secure_file.rb
index 18f0093ea41..6a26a5341aa 100644
--- a/app/models/ci/secure_file.rb
+++ b/app/models/ci/secure_file.rb
@@ -15,7 +15,9 @@ module Ci
validates :file, presence: true, file_size: { maximum: FILE_SIZE_LIMIT }
validates :checksum, :file_store, :name, :permissions, :project_id, presence: true
+ validates :name, uniqueness: { scope: :project }
+ after_initialize :generate_key_data
before_validation :assign_checksum
enum permissions: { read_only: 0, read_write: 1, execute: 2 }
@@ -33,5 +35,11 @@ module Ci
def assign_checksum
self.checksum = file.checksum if file.present? && file_changed?
end
+
+ def generate_key_data
+ return if key_data.present?
+
+ self.key_data = SecureRandom.hex(64)
+ end
end
end