Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-08-20 21:42:06 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-08-20 21:42:06 +0300
commit6e4e1050d9dba2b7b2523fdd1768823ab85feef4 (patch)
tree78be5963ec075d80116a932011d695dd33910b4e /app/models/ci
parent1ce776de4ae122aba3f349c02c17cebeaa8ecf07 (diff)
Add latest changes from gitlab-org/gitlab@13-3-stable-ee
Diffstat (limited to 'app/models/ci')
-rw-r--r--app/models/ci/build.rb68
-rw-r--r--app/models/ci/build_trace_chunk.rb39
-rw-r--r--app/models/ci/build_trace_chunks/database.rb18
-rw-r--r--app/models/ci/build_trace_chunks/fog.rb20
-rw-r--r--app/models/ci/build_trace_chunks/redis.rb38
-rw-r--r--app/models/ci/group.rb12
-rw-r--r--app/models/ci/instance_variable.rb10
-rw-r--r--app/models/ci/job_artifact.rb41
-rw-r--r--app/models/ci/legacy_stage.rb2
-rw-r--r--app/models/ci/pipeline.rb86
-rw-r--r--app/models/ci/pipeline_artifact.rb37
-rw-r--r--app/models/ci/pipeline_enums.rb4
-rw-r--r--app/models/ci/ref.rb12
-rw-r--r--app/models/ci/runner.rb2
-rw-r--r--app/models/ci/stage.rb4
15 files changed, 208 insertions, 185 deletions
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index 6c90645e997..af4e6bb0494 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -73,8 +73,7 @@ module Ci
return unless has_environment?
strong_memoize(:persisted_environment) do
- deployment&.environment ||
- Environment.find_by(name: expanded_environment_name, project: project)
+ Environment.find_by(name: expanded_environment_name, project: project)
end
end
@@ -351,7 +350,7 @@ module Ci
after_transition any => [:failed] do |build|
next unless build.project
- if build.retry_failure?
+ if build.auto_retry_allowed?
begin
Ci::Build.retry(build, build.user)
rescue Gitlab::Access::AccessDeniedError => ex
@@ -373,6 +372,10 @@ module Ci
end
end
+ def auto_retry_allowed?
+ auto_retry.allowed?
+ end
+
def detailed_status(current_user)
Gitlab::Ci::Status::Build::Factory
.new(self, current_user)
@@ -439,27 +442,6 @@ module Ci
pipeline.builds.retried.where(name: self.name).count
end
- def retry_failure?
- max_allowed_retries = nil
- max_allowed_retries ||= options_retry_max if retry_on_reason_or_always?
- max_allowed_retries ||= DEFAULT_RETRIES.fetch(failure_reason.to_sym, 0)
-
- max_allowed_retries > 0 && retries_count < max_allowed_retries
- end
-
- def options_retry_max
- options_retry[:max]
- end
-
- def options_retry_when
- options_retry.fetch(:when, ['always'])
- end
-
- def retry_on_reason_or_always?
- options_retry_when.include?(failure_reason.to_s) ||
- options_retry_when.include?('always')
- end
-
def any_unmet_prerequisites?
prerequisites.present?
end
@@ -474,8 +456,7 @@ module Ci
strong_memoize(:expanded_environment_name) do
# We're using a persisted expanded environment name in order to avoid
# variable expansion per request.
- if Feature.enabled?(:ci_persisted_expanded_environment_name, project, default_enabled: true) &&
- metadata&.expanded_environment_name.present?
+ if metadata&.expanded_environment_name.present?
metadata.expanded_environment_name
else
ExpandVariables.expand(environment, -> { simple_variables })
@@ -543,8 +524,6 @@ module Ci
end
end
- CI_REGISTRY_USER = 'gitlab-ci-token'
-
def persisted_variables
Gitlab::Ci::Variables::Collection.new.tap do |variables|
break variables unless persisted?
@@ -556,7 +535,7 @@ module Ci
.append(key: 'CI_JOB_TOKEN', value: token.to_s, public: false, masked: true)
.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: CI_REGISTRY_USER)
+ .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)
@@ -615,7 +594,7 @@ module Ci
def repo_url
return unless token
- auth = "gitlab-ci-token:#{token}@"
+ auth = "#{::Gitlab::Auth::CI_JOB_USER}:#{token}@"
project.http_url_to_repo.sub(%r{^https?://}) do |prefix|
prefix + auth
end
@@ -668,6 +647,13 @@ module Ci
!artifacts_expired? && artifacts_file&.exists?
end
+ # 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.
+ def available_artifacts?
+ (!artifacts_expired? || pipeline.artifacts_locked?) && job_artifacts_archive&.exists?
+ end
+
def artifacts_metadata?
artifacts? && artifacts_metadata&.exists?
end
@@ -878,8 +864,7 @@ module Ci
end
def multi_build_steps?
- options.dig(:release)&.any? &&
- Gitlab::Ci::Features.release_generation_enabled?
+ options.dig(:release)&.any?
end
def hide_secrets(trace)
@@ -962,6 +947,12 @@ module Ci
private
+ def auto_retry
+ strong_memoize(:auto_retry) do
+ Gitlab::Ci::Build::AutoRetry.new(self)
+ end
+ end
+
def dependencies
strong_memoize(:dependencies) do
Ci::BuildDependencies.new(self)
@@ -1017,19 +1008,6 @@ module Ci
end
end
- # The format of the retry option changed in GitLab 11.5: Before it was
- # integer only, after it is a hash. New builds are created with the new
- # format, but builds created before GitLab 11.5 and saved in database still
- # have the old integer only format. This method returns the retry option
- # normalized as a hash in 11.5+ format.
- def options_retry
- strong_memoize(:options_retry) do
- value = options&.dig(:retry)
- value = value.is_a?(Integer) ? { max: value } : value.to_h
- value.with_indifferent_access
- end
- end
-
def has_expiring_artifacts?
artifacts_expire_at.present? && artifacts_expire_at > Time.current
end
diff --git a/app/models/ci/build_trace_chunk.rb b/app/models/ci/build_trace_chunk.rb
index 0a7a0e0772b..407802baf09 100644
--- a/app/models/ci/build_trace_chunk.rb
+++ b/app/models/ci/build_trace_chunk.rb
@@ -75,18 +75,16 @@ module Ci
def append(new_data, offset)
raise ArgumentError, 'New data is missing' unless new_data
- raise ArgumentError, 'Offset is out of range' if offset > size || offset < 0
+ raise ArgumentError, 'Offset is out of range' if offset < 0 || offset > size
raise ArgumentError, 'Chunk size overflow' if CHUNK_SIZE < (offset + new_data.bytesize)
- in_lock(*lock_params) do # Write operation is atomic
- unsafe_set_data!(data.byteslice(0, offset) + new_data)
- end
+ in_lock(*lock_params) { unsafe_append_data!(new_data, offset) }
schedule_to_persist if full?
end
def size
- data&.bytesize.to_i
+ @size ||= current_store.size(self) || data&.bytesize
end
def start_offset
@@ -118,7 +116,7 @@ module Ci
raise FailedToPersistDataError, 'Data is not fulfilled in a bucket'
end
- old_store_class = self.class.get_store_class(data_store)
+ old_store_class = current_store
self.raw_data = nil
self.data_store = new_store
@@ -128,16 +126,33 @@ module Ci
end
def get_data
- self.class.get_store_class(data_store).data(self)&.force_encoding(Encoding::BINARY) # Redis/Database return UTF-8 string as default
- rescue Excon::Error::NotFound
- # If the data store is :fog and the file does not exist in the object storage, this method returns nil.
+ current_store.data(self)&.force_encoding(Encoding::BINARY) # Redis/Database return UTF-8 string as default
end
def unsafe_set_data!(value)
raise ArgumentError, 'New data size exceeds chunk size' if value.bytesize > CHUNK_SIZE
- self.class.get_store_class(data_store).set_data(self, value)
+ current_store.set_data(self, value)
+
@data = value
+ @size = value.bytesize
+
+ save! if changed?
+ end
+
+ def unsafe_append_data!(value, offset)
+ new_size = value.bytesize + offset
+
+ if new_size > CHUNK_SIZE
+ raise ArgumentError, 'New data size exceeds chunk size'
+ end
+
+ current_store.append_data(self, value, offset).then do |stored|
+ raise ArgumentError, 'Trace appended incorrectly' if stored != new_size
+ end
+
+ @data = nil
+ @size = new_size
save! if changed?
end
@@ -156,6 +171,10 @@ module Ci
size == CHUNK_SIZE
end
+ def current_store
+ self.class.get_store_class(data_store)
+ end
+
def lock_params
["trace_write:#{build_id}:chunks:#{chunk_index}",
{ ttl: WRITE_LOCK_TTL,
diff --git a/app/models/ci/build_trace_chunks/database.rb b/app/models/ci/build_trace_chunks/database.rb
index 73cb8abf381..3b8e23510d9 100644
--- a/app/models/ci/build_trace_chunks/database.rb
+++ b/app/models/ci/build_trace_chunks/database.rb
@@ -19,8 +19,22 @@ module Ci
model.raw_data
end
- def set_data(model, data)
- model.raw_data = data
+ def set_data(model, new_data)
+ model.raw_data = new_data
+ end
+
+ def append_data(model, new_data, offset)
+ if offset > 0
+ truncated_data = data(model).to_s.byteslice(0, offset)
+ new_data = truncated_data + new_data
+ end
+
+ model.raw_data = new_data
+ model.raw_data.to_s.bytesize
+ end
+
+ def size(model)
+ data(model).to_s.bytesize
end
def delete_data(model)
diff --git a/app/models/ci/build_trace_chunks/fog.rb b/app/models/ci/build_trace_chunks/fog.rb
index a849bd08427..b1e9fd1faeb 100644
--- a/app/models/ci/build_trace_chunks/fog.rb
+++ b/app/models/ci/build_trace_chunks/fog.rb
@@ -9,10 +9,26 @@ module Ci
def data(model)
connection.get_object(bucket_name, key(model))[:body]
+ rescue Excon::Error::NotFound
+ # If the object does not exist in the object storage, this method returns nil.
end
- def set_data(model, data)
- connection.put_object(bucket_name, key(model), data)
+ def set_data(model, new_data)
+ connection.put_object(bucket_name, key(model), new_data)
+ end
+
+ def append_data(model, new_data, offset)
+ if offset > 0
+ truncated_data = data(model).to_s.byteslice(0, offset)
+ new_data = truncated_data + new_data
+ end
+
+ set_data(model, new_data)
+ new_data.bytesize
+ end
+
+ def size(model)
+ data(model).to_s.bytesize
end
def delete_data(model)
diff --git a/app/models/ci/build_trace_chunks/redis.rb b/app/models/ci/build_trace_chunks/redis.rb
index c3864f78b01..0ae563f6ce8 100644
--- a/app/models/ci/build_trace_chunks/redis.rb
+++ b/app/models/ci/build_trace_chunks/redis.rb
@@ -4,6 +4,32 @@ module Ci
module BuildTraceChunks
class Redis
CHUNK_REDIS_TTL = 1.week
+ LUA_APPEND_CHUNK = <<~EOS.freeze
+ local key, new_data, offset = KEYS[1], ARGV[1], ARGV[2]
+ local length = new_data:len()
+ local expire = #{CHUNK_REDIS_TTL.seconds}
+ local current_size = redis.call("strlen", key)
+ offset = tonumber(offset)
+
+ if offset == 0 then
+ -- overwrite everything
+ redis.call("set", key, new_data, "ex", expire)
+ return redis.call("strlen", key)
+ elseif offset > current_size then
+ -- offset range violation
+ return -1
+ elseif offset + length >= current_size then
+ -- efficiently append or overwrite and append
+ redis.call("expire", key, expire)
+ return redis.call("setrange", key, offset, new_data)
+ else
+ -- append and truncate
+ local current_data = redis.call("get", key)
+ new_data = current_data:sub(1, offset) .. new_data
+ redis.call("set", key, new_data, "ex", expire)
+ return redis.call("strlen", key)
+ end
+ EOS
def available?
true
@@ -21,6 +47,18 @@ module Ci
end
end
+ def append_data(model, new_data, offset)
+ Gitlab::Redis::SharedState.with do |redis|
+ redis.eval(LUA_APPEND_CHUNK, keys: [key(model)], argv: [new_data, offset])
+ end
+ end
+
+ def size(model)
+ Gitlab::Redis::SharedState.with do |redis|
+ redis.strlen(key(model))
+ end
+ end
+
def delete_data(model)
delete_keys([[model.build_id, model.chunk_index]])
end
diff --git a/app/models/ci/group.rb b/app/models/ci/group.rb
index 779c6c0396f..f0c035635b9 100644
--- a/app/models/ci/group.rb
+++ b/app/models/ci/group.rb
@@ -24,15 +24,9 @@ module Ci
def status
strong_memoize(:status) do
- if ::Gitlab::Ci::Features.composite_status?(project)
- Gitlab::Ci::Status::Composite
- .new(@jobs)
- .status
- else
- CommitStatus
- .where(id: @jobs)
- .legacy_status
- end
+ Gitlab::Ci::Status::Composite
+ .new(@jobs)
+ .status
end
end
diff --git a/app/models/ci/instance_variable.rb b/app/models/ci/instance_variable.rb
index 628749b32cb..e083caa8751 100644
--- a/app/models/ci/instance_variable.rb
+++ b/app/models/ci/instance_variable.rb
@@ -14,12 +14,14 @@ module Ci
alias_attribute :secret_value, :value
validates :key, uniqueness: {
- message: "(%{value}) has already been taken"
+ message: -> (object, data) { _("(%{value}) has already been taken") }
}
- validates :encrypted_value, length: {
- maximum: 1024,
- too_long: 'The encrypted value of the provided variable exceeds %{count} bytes. Variables over 700 characters risk exceeding the limit.'
+ validates :value, length: {
+ maximum: 10_000,
+ too_long: -> (object, data) do
+ _('The value of the provided variable exceeds the %{count} character limit')
+ end
}
scope :unprotected, -> { where(protected: false) }
diff --git a/app/models/ci/job_artifact.rb b/app/models/ci/job_artifact.rb
index dbeba1ece31..75c3ce98c95 100644
--- a/app/models/ci/job_artifact.rb
+++ b/app/models/ci/job_artifact.rb
@@ -8,6 +8,8 @@ module Ci
include UsageStatistics
include Sortable
include IgnorableColumns
+ include Artifactable
+ include FileStoreMounter
extend Gitlab::Ci::Model
NotSupportedAdapterError = Class.new(StandardError)
@@ -114,7 +116,7 @@ module Ci
belongs_to :project
belongs_to :job, class_name: "Ci::Build", foreign_key: :job_id
- mount_uploader :file, JobArtifactUploader
+ mount_file_store_uploader JobArtifactUploader
validates :file_format, presence: true, unless: :trace?, on: :create
validate :validate_supported_file_format!, on: :create
@@ -123,8 +125,6 @@ module Ci
update_project_statistics project_statistics_name: :build_artifacts_size
- after_save :update_file_store, if: :saved_change_to_file?
-
scope :not_expired, -> { where('expire_at IS NULL OR expire_at > ?', Time.current) }
scope :with_files_stored_locally, -> { where(file_store: ::JobArtifactUploader::Store::LOCAL) }
scope :with_files_stored_remotely, -> { where(file_store: ::JobArtifactUploader::Store::REMOTE) }
@@ -200,12 +200,6 @@ module Ci
load_performance: 25 ## EE-specific
}
- enum file_format: {
- raw: 1,
- zip: 2,
- gzip: 3
- }, _suffix: true
-
# `file_location` indicates where actual files are stored.
# Ideally, actual files should be stored in the same directory, and use the same
# convention to generate its path. However, sometimes we can't do so due to backward-compatibility.
@@ -220,11 +214,6 @@ module Ci
hashed_path: 2
}
- FILE_FORMAT_ADAPTERS = {
- gzip: Gitlab::Ci::Build::Artifacts::Adapters::GzipStream,
- raw: Gitlab::Ci::Build::Artifacts::Adapters::RawStream
- }.freeze
-
def validate_supported_file_format!
return if Feature.disabled?(:drop_license_management_artifact, project, default_enabled: true)
@@ -239,12 +228,6 @@ module Ci
end
end
- def update_file_store
- # The file.object_store is set during `uploader.store!`
- # which happens after object is inserted/updated
- self.update_column(:file_store, file.object_store)
- end
-
def self.associated_file_types_for(file_type)
return unless file_types.include?(file_type)
@@ -284,7 +267,7 @@ module Ci
def expire_in=(value)
self.expire_at =
if value
- ChronicDuration.parse(value)&.seconds&.from_now
+ ::Gitlab::Ci::Build::Artifacts::ExpireInParser.new(value).seconds_from_now
end
end
@@ -303,16 +286,12 @@ module Ci
end
def self.max_artifact_size(type:, project:)
- max_size = if Feature.enabled?(:ci_max_artifact_size_per_type, project, default_enabled: false)
- limit_name = "#{PLAN_LIMIT_PREFIX}#{type}"
-
- project.actual_limits.limit_for(
- limit_name,
- alternate_limit: -> { project.closest_setting(:max_artifacts_size) }
- )
- else
- project.closest_setting(:max_artifacts_size)
- end
+ limit_name = "#{PLAN_LIMIT_PREFIX}#{type}"
+
+ max_size = project.actual_limits.limit_for(
+ limit_name,
+ alternate_limit: -> { project.closest_setting(:max_artifacts_size) }
+ )
max_size&.megabytes.to_i
end
diff --git a/app/models/ci/legacy_stage.rb b/app/models/ci/legacy_stage.rb
index 250306e2be4..df4368eccd5 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.slow_composite_status(project: project)
+ @status ||= statuses.latest.composite_status
end
def detailed_status(current_user)
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index d4b439d648f..7762328d274 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -57,12 +57,12 @@ module Ci
# the merge request's latest commit.
has_many :merge_requests_as_head_pipeline, foreign_key: "head_pipeline_id", class_name: 'MergeRequest'
- has_many :pending_builds, -> { pending }, foreign_key: :commit_id, class_name: 'Ci::Build'
+ has_many :pending_builds, -> { pending }, foreign_key: :commit_id, class_name: 'Ci::Build', inverse_of: :pipeline
has_many :failed_builds, -> { latest.failed }, foreign_key: :commit_id, class_name: 'Ci::Build', inverse_of: :pipeline
- has_many :retryable_builds, -> { latest.failed_or_canceled.includes(:project) }, foreign_key: :commit_id, class_name: 'Ci::Build'
+ has_many :retryable_builds, -> { latest.failed_or_canceled.includes(:project) }, foreign_key: :commit_id, class_name: 'Ci::Build', inverse_of: :pipeline
has_many :cancelable_statuses, -> { cancelable }, foreign_key: :commit_id, class_name: 'CommitStatus'
- has_many :manual_actions, -> { latest.manual_actions.includes(:project) }, foreign_key: :commit_id, class_name: 'Ci::Build'
- has_many :scheduled_actions, -> { latest.scheduled_actions.includes(:project) }, foreign_key: :commit_id, class_name: 'Ci::Build'
+ has_many :manual_actions, -> { latest.manual_actions.includes(:project) }, foreign_key: :commit_id, class_name: 'Ci::Build', inverse_of: :pipeline
+ has_many :scheduled_actions, -> { latest.scheduled_actions.includes(:project) }, foreign_key: :commit_id, class_name: 'Ci::Build', inverse_of: :pipeline
has_many :auto_canceled_pipelines, class_name: 'Ci::Pipeline', foreign_key: 'auto_canceled_by_id'
has_many :auto_canceled_jobs, class_name: 'CommitStatus', foreign_key: 'auto_canceled_by_id'
@@ -83,6 +83,7 @@ module Ci
has_many :daily_build_group_report_results, class_name: 'Ci::DailyBuildGroupReportResult', foreign_key: :last_pipeline_id
has_many :latest_builds_report_results, through: :latest_builds, source: :report_results
+ has_many :pipeline_artifacts, class_name: 'Ci::PipelineArtifact', inverse_of: :pipeline, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
accepts_nested_attributes_for :variables, reject_if: :persisted?
@@ -249,14 +250,6 @@ module Ci
pipeline.run_after_commit { AutoDevops::DisableWorker.perform_async(pipeline.id) }
end
-
- after_transition any => [:success] do |pipeline|
- next unless Gitlab::Ci::Features.keep_latest_artifacts_for_ref_enabled?(pipeline.project)
-
- pipeline.run_after_commit do
- Ci::PipelineSuccessUnlockArtifactsWorker.perform_async(pipeline.id)
- end
- end
end
scope :internal, -> { where(source: internal_sources) }
@@ -416,7 +409,7 @@ module Ci
def legacy_stage(name)
stage = Ci::LegacyStage.new(self, name: name)
- stage unless stage.statuses_count.zero?
+ stage unless stage.statuses_count == 0
end
def ref_exists?
@@ -425,40 +418,6 @@ module Ci
false
end
- def ordered_stages
- if ::Gitlab::Ci::Features.atomic_processing?(project)
- # The `Ci::Stage` contains all up-to date data
- # as atomic processing updates all data in-bulk
- stages
- elsif complete?
- # The `Ci::Stage` contains up-to date data only for `completed` pipelines
- # this is due to asynchronous processing of pipeline, and stages possibly
- # not updated inline with processing of pipeline
- stages
- else
- # In other cases, we need to calculate stages dynamically
- legacy_stages
- end
- end
-
- def legacy_stages_using_sql
- # TODO, this needs refactoring, see gitlab-foss#26481.
- stages_query = statuses
- .group('stage').select(:stage).order('max(stage_idx)')
-
- status_sql = statuses.latest.where('stage=sg.stage').legacy_status_sql
-
- warnings_sql = statuses.latest.select('COUNT(*)')
- .where('stage=sg.stage').failed_but_allowed.to_sql
-
- stages_with_statuses = CommitStatus.from(stages_query, :sg)
- .pluck('sg.stage', Arel.sql(status_sql), Arel.sql("(#{warnings_sql})"))
-
- stages_with_statuses.map do |stage|
- Ci::LegacyStage.new(self, Hash[%i[name status warnings].zip(stage)])
- end
- end
-
def legacy_stages_using_composite_status
stages = latest_statuses_ordered_by_stage.group_by(&:stage)
@@ -477,12 +436,9 @@ module Ci
triggered_pipelines.preload(:source_job)
end
+ # TODO: Remove usage of this method in templates
def legacy_stages
- if ::Gitlab::Ci::Features.composite_status?(project)
- legacy_stages_using_composite_status
- else
- legacy_stages_using_sql
- end
+ legacy_stages_using_composite_status
end
def valid_commit_sha
@@ -665,7 +621,7 @@ module Ci
end
def has_warnings?
- number_of_warnings.positive?
+ number_of_warnings > 0
end
def number_of_warnings
@@ -755,10 +711,6 @@ module Ci
end
end
- def update_legacy_status
- set_status(latest_builds_status.to_s)
- end
-
def protected_ref?
strong_memoize(:protected_ref) { project.protected_for?(git_ref) }
end
@@ -828,7 +780,7 @@ module Ci
return unless started_at
seconds = (started_at - created_at).to_i
- seconds unless seconds.zero?
+ seconds unless seconds == 0
end
def update_duration
@@ -922,12 +874,6 @@ module Ci
end
end
- def test_reports_count
- Rails.cache.fetch(['project', project.id, 'pipeline', id, 'test_reports_count'], force: false) do
- test_reports.total_count
- end
- end
-
def accessibility_reports
Gitlab::Ci::Reports::AccessibilityReports.new.tap do |accessibility_reports|
builds.latest.with_reports(Ci::JobArtifact.accessibility_reports).each do |build|
@@ -1061,10 +1007,6 @@ module Ci
@persistent_ref ||= PersistentRef.new(pipeline: self)
end
- def find_successful_build_ids_by_names(names)
- statuses.latest.success.where(name: names).pluck(:id)
- end
-
def cacheable?
Ci::PipelineEnums.ci_config_sources.key?(config_source.to_sym)
end
@@ -1084,8 +1026,6 @@ module Ci
end
def ensure_ci_ref!
- return unless Gitlab::Ci::Features.pipeline_fixed_notifications?
-
self.ci_ref = Ci::Ref.ensure_for(self)
end
@@ -1123,12 +1063,6 @@ module Ci
end
end
- def latest_builds_status
- return 'failed' unless yaml_errors.blank?
-
- statuses.latest.slow_composite_status(project: project) || 'skipped'
- end
-
def keep_around_commits
return unless project
diff --git a/app/models/ci/pipeline_artifact.rb b/app/models/ci/pipeline_artifact.rb
new file mode 100644
index 00000000000..e7f51977ccd
--- /dev/null
+++ b/app/models/ci/pipeline_artifact.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+# This class is being used to persist additional artifacts after a pipeline completes, which is a great place to cache a computed result in object storage
+
+module Ci
+ class PipelineArtifact < ApplicationRecord
+ extend Gitlab::Ci::Model
+ include Artifactable
+ include FileStoreMounter
+
+ FILE_STORE_SUPPORTED = [
+ ObjectStorage::Store::LOCAL,
+ ObjectStorage::Store::REMOTE
+ ].freeze
+
+ FILE_SIZE_LIMIT = 10.megabytes.freeze
+
+ belongs_to :project, class_name: "Project", inverse_of: :pipeline_artifacts
+ belongs_to :pipeline, class_name: "Ci::Pipeline", inverse_of: :pipeline_artifacts
+
+ validates :pipeline, :project, :file_format, :file, presence: true
+ validates :file_store, presence: true, inclusion: { in: FILE_STORE_SUPPORTED }
+ validates :size, presence: true, numericality: { less_than_or_equal_to: FILE_SIZE_LIMIT }
+ validates :file_type, presence: true
+
+ mount_file_store_uploader Ci::PipelineArtifactUploader
+ before_save :set_size, if: :file_changed?
+
+ enum file_type: {
+ code_coverage: 1
+ }
+
+ def set_size
+ self.size = file.size
+ end
+ end
+end
diff --git a/app/models/ci/pipeline_enums.rb b/app/models/ci/pipeline_enums.rb
index 352dc56aac7..9d108ff0fa4 100644
--- a/app/models/ci/pipeline_enums.rb
+++ b/app/models/ci/pipeline_enums.rb
@@ -63,6 +63,10 @@ module Ci
def self.ci_config_sources_values
ci_config_sources.values
end
+
+ def self.non_ci_config_source_values
+ config_sources.values - ci_config_sources.values
+ end
end
end
diff --git a/app/models/ci/ref.rb b/app/models/ci/ref.rb
index 29b44575d65..3d8823728e7 100644
--- a/app/models/ci/ref.rb
+++ b/app/models/ci/ref.rb
@@ -3,6 +3,7 @@
module Ci
class Ref < ApplicationRecord
extend Gitlab::Ci::Model
+ include AfterCommitQueue
include Gitlab::OptimisticLocking
FAILING_STATUSES = %w[failed broken still_failing].freeze
@@ -15,6 +16,7 @@ module Ci
transition unknown: :success
transition fixed: :success
transition %i[failed broken still_failing] => :fixed
+ transition success: same
end
event :do_fail do
@@ -29,6 +31,14 @@ module Ci
state :fixed, value: 3
state :broken, value: 4
state :still_failing, value: 5
+
+ after_transition any => [:fixed, :success] do |ci_ref|
+ next unless ::Gitlab::Ci::Features.keep_latest_artifacts_for_ref_enabled?(ci_ref.project)
+
+ ci_ref.run_after_commit do
+ Ci::PipelineSuccessUnlockArtifactsWorker.perform_async(ci_ref.last_finished_pipeline_id)
+ end
+ end
end
class << self
@@ -47,8 +57,6 @@ module Ci
end
def update_status_by!(pipeline)
- return unless Gitlab::Ci::Features.pipeline_fixed_notifications?
-
retry_lock(self) do
next unless last_finished_pipeline_id == pipeline.id
diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb
index 1cd6c64841b..00ee45740bd 100644
--- a/app/models/ci/runner.rb
+++ b/app/models/ci/runner.rb
@@ -10,7 +10,7 @@ module Ci
include TokenAuthenticatable
include IgnorableColumns
- add_authentication_token_field :token, encrypted: -> { Feature.enabled?(:ci_runners_tokens_optional_encryption, default_enabled: true) ? :optional : :required }
+ add_authentication_token_field :token, encrypted: -> { Feature.enabled?(:ci_runners_tokens_optional_encryption) ? :optional : :required }
enum access_level: {
not_protected: 0,
diff --git a/app/models/ci/stage.rb b/app/models/ci/stage.rb
index 41215601704..cc6bd1870b9 100644
--- a/app/models/ci/stage.rb
+++ b/app/models/ci/stage.rb
@@ -113,7 +113,7 @@ module Ci
end
def has_warnings?
- number_of_warnings.positive?
+ number_of_warnings > 0
end
def number_of_warnings
@@ -138,7 +138,7 @@ module Ci
end
def latest_stage_status
- statuses.latest.slow_composite_status(project: project) || 'skipped'
+ statuses.latest.composite_status || 'skipped'
end
end
end