diff options
Diffstat (limited to 'app/models/ci')
-rw-r--r-- | app/models/ci/bridge.rb | 14 | ||||
-rw-r--r-- | app/models/ci/build.rb | 56 | ||||
-rw-r--r-- | app/models/ci/build_need.rb | 2 | ||||
-rw-r--r-- | app/models/ci/build_runner_session.rb | 4 | ||||
-rw-r--r-- | app/models/ci/commit_with_pipeline.rb | 38 | ||||
-rw-r--r-- | app/models/ci/group.rb | 24 | ||||
-rw-r--r-- | app/models/ci/job_artifact.rb | 10 | ||||
-rw-r--r-- | app/models/ci/pipeline.rb | 6 | ||||
-rw-r--r-- | app/models/ci/ref.rb | 7 |
9 files changed, 132 insertions, 29 deletions
diff --git a/app/models/ci/bridge.rb b/app/models/ci/bridge.rb index 19a0d424e33..ef3891908f7 100644 --- a/app/models/ci/bridge.rb +++ b/app/models/ci/bridge.rb @@ -7,7 +7,6 @@ module Ci include Importable include AfterCommitQueue include Ci::HasRef - extend ::Gitlab::Utils::Override InvalidBridgeTypeError = Class.new(StandardError) InvalidTransitionError = Class.new(StandardError) @@ -200,13 +199,6 @@ module Ci end end - override :dependency_variables - def dependency_variables - return [] unless ::Feature.enabled?(:ci_bridge_dependency_variables, project, default_enabled: true) - - super - end - def target_revision_ref downstream_pipeline_params.dig(:target_revision, :ref) end @@ -218,7 +210,8 @@ module Ci project: downstream_project, source: :pipeline, target_revision: { - ref: target_ref || downstream_project.default_branch + ref: target_ref || downstream_project.default_branch, + variables_attributes: downstream_variables }, execute_params: { ignore_skip_ci: true, @@ -238,7 +231,8 @@ module Ci checkout_sha: parent_pipeline.sha, before: parent_pipeline.before_sha, source_sha: parent_pipeline.source_sha, - target_sha: parent_pipeline.target_sha + target_sha: parent_pipeline.target_sha, + variables_attributes: downstream_variables }, execute_params: { ignore_skip_ci: true, diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 71939f070cb..5e3f42d7c2c 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -27,7 +27,8 @@ module Ci 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? } + multi_build_steps: -> (build) { build.multi_build_steps? }, + return_exit_code: -> (build) { build.exit_codes_defined? } }.freeze DEFAULT_RETRIES = { @@ -146,6 +147,12 @@ module Ci .includes(:metadata, :job_artifacts_metadata) end + scope :with_project_and_metadata, -> do + if Feature.enabled?(:non_public_artifacts, type: :development) + joins(:metadata).includes(:project, :metadata) + end + end + scope :with_artifacts_not_expired, -> { with_downloadable_artifacts.where('artifacts_expire_at IS NULL OR artifacts_expire_at > ?', Time.current) } scope :with_expired_artifacts, -> { with_downloadable_artifacts.where('artifacts_expire_at < ?', Time.current) } scope :last_month, -> { where('created_at > ?', Date.today - 1.month) } @@ -382,12 +389,8 @@ module Ci end after_transition any => [:skipped, :canceled] do |build, transition| - if Feature.enabled?(:cd_skipped_deployment_status, build.project) - if transition.to_name == :skipped - build.deployment&.skip - else - build.deployment&.cancel - end + if transition.to_name == :skipped + build.deployment&.skip else build.deployment&.cancel end @@ -741,6 +744,16 @@ module Ci artifacts_metadata? end + def artifacts_public? + return true unless Feature.enabled?(:non_public_artifacts, type: :development) + + artifacts_public = options.dig(:artifacts, :public) + + return true if artifacts_public.nil? # Default artifacts:public to true + + options.dig(:artifacts, :public) + end + def artifacts_metadata_entry(path, **options) artifacts_metadata.open do |metadata_stream| metadata = Gitlab::Ci::Build::Artifacts::Metadata.new( @@ -1007,14 +1020,23 @@ module Ci end def debug_mode? - return false unless Feature.enabled?(:restrict_access_to_build_debug_mode, default_enabled: true) - # 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 } end + def drop_with_exit_code!(failure_reason, exit_code) + transaction do + conditionally_allow_failure!(exit_code) + drop!(failure_reason) + end + end + + def exit_codes_defined? + options.dig(:allow_failure_criteria, :exit_codes).present? + end + protected def run_status_commit_hooks! @@ -1098,6 +1120,22 @@ module Ci Gitlab::ErrorTracking.track_exception(e) end end + + def conditionally_allow_failure!(exit_code) + return unless ::Gitlab::Ci::Features.allow_failure_with_exit_codes_enabled? + return unless exit_code + + if allowed_to_fail_with_code?(exit_code) + update_columns(allow_failure: true) + end + end + + def allowed_to_fail_with_code?(exit_code) + options + .dig(:allow_failure_criteria, :exit_codes) + .to_a + .include?(exit_code) + end end end diff --git a/app/models/ci/build_need.rb b/app/models/ci/build_need.rb index b977a5f4419..fac615f97b9 100644 --- a/app/models/ci/build_need.rb +++ b/app/models/ci/build_need.rb @@ -6,7 +6,7 @@ module Ci include BulkInsertSafe - belongs_to :build, class_name: "Ci::Build", foreign_key: :build_id, inverse_of: :needs + belongs_to :build, class_name: "Ci::Processable", foreign_key: :build_id, inverse_of: :needs validates :build, presence: true validates :name, presence: true, length: { maximum: 128 } diff --git a/app/models/ci/build_runner_session.rb b/app/models/ci/build_runner_session.rb index bc7f17f046c..b6196048ca1 100644 --- a/app/models/ci/build_runner_session.rb +++ b/app/models/ci/build_runner_session.rb @@ -7,8 +7,8 @@ module Ci extend Gitlab::Ci::Model TERMINAL_SUBPROTOCOL = 'terminal.gitlab.com' - DEFAULT_SERVICE_NAME = 'build'.freeze - DEFAULT_PORT_NAME = 'default_port'.freeze + DEFAULT_SERVICE_NAME = 'build' + DEFAULT_PORT_NAME = 'default_port' self.table_name = 'ci_builds_runner_session' diff --git a/app/models/ci/commit_with_pipeline.rb b/app/models/ci/commit_with_pipeline.rb new file mode 100644 index 00000000000..7f952fb77a0 --- /dev/null +++ b/app/models/ci/commit_with_pipeline.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +class Ci::CommitWithPipeline < SimpleDelegator + include Presentable + + def initialize(commit) + @latest_pipelines = {} + super(commit) + end + + def pipelines + project.ci_pipelines.where(sha: sha) + end + + def last_pipeline + strong_memoize(:last_pipeline) do + pipelines.last + end + end + + def latest_pipeline(ref = nil) + @latest_pipelines.fetch(ref) do |ref| + @latest_pipelines[ref] = latest_pipeline_for_project(ref, project) + end + end + + def latest_pipeline_for_project(ref, pipeline_project) + pipeline_project.ci_pipelines.latest_pipeline_per_commit(id, ref)[id] + end + + def set_latest_pipeline_for_ref(ref, pipeline) + @latest_pipelines[ref] = pipeline + end + + def status(ref = nil) + latest_pipeline(ref)&.status + end +end diff --git a/app/models/ci/group.rb b/app/models/ci/group.rb index f0c035635b9..c7c0ec61e62 100644 --- a/app/models/ci/group.rb +++ b/app/models/ci/group.rb @@ -24,9 +24,22 @@ module Ci def status strong_memoize(:status) do + status_struct.status + end + end + + def success? + status.to_s == 'success' + end + + def has_warnings? + status_struct.warnings? + end + + def status_struct + strong_memoize(:status_struct) do Gitlab::Ci::Status::Composite .new(@jobs) - .status end end @@ -39,8 +52,13 @@ module Ci end end - def self.fabricate(project, stage) - stage.latest_statuses + # Construct a grouping of statuses for this stage. + # We allow the caller to pass in statuses for efficiency (avoiding N+1 + # queries). + def self.fabricate(project, stage, statuses = nil) + statuses ||= stage.latest_statuses + + statuses .sort_by(&:sortable_name).group_by(&:group_name) .map do |group_name, grouped_statuses| self.new(project, stage, name: group_name, jobs: grouped_statuses) diff --git a/app/models/ci/job_artifact.rb b/app/models/ci/job_artifact.rb index c80d50ea131..f13be3b3c86 100644 --- a/app/models/ci/job_artifact.rb +++ b/app/models/ci/job_artifact.rb @@ -9,6 +9,7 @@ module Ci include Sortable include Artifactable include FileStoreMounter + include EachBatch extend Gitlab::Ci::Model TEST_REPORT_FILE_TYPES = %w[junit].freeze @@ -133,6 +134,12 @@ 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_file_types, -> (file_types) do types = self.file_types.select { |file_type| file_types.include?(file_type) }.values @@ -170,7 +177,8 @@ module Ci end scope :downloadable, -> { where(file_type: DOWNLOADABLE_TYPES) } - scope :unlocked, -> { joins(job: :pipeline).merge(::Ci::Pipeline.unlocked).order(expire_at: :desc) } + scope :unlocked, -> { joins(job: :pipeline).merge(::Ci::Pipeline.unlocked) } + scope :order_expired_desc, -> { order(expire_at: :desc) } scope :with_destroy_preloads, -> { includes(project: [:route, :statistics]) } scope :scoped_project, -> { where('ci_job_artifacts.project_id = projects.id') } diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index 5e5f51d776f..4a579892e3f 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -68,8 +68,8 @@ module Ci has_many :variables, class_name: 'Ci::PipelineVariable' has_many :deployments, through: :builds has_many :environments, -> { distinct }, through: :deployments - has_many :latest_builds, -> { latest }, foreign_key: :commit_id, inverse_of: :pipeline, class_name: 'Ci::Build' - has_many :downloadable_artifacts, -> { not_expired.downloadable }, through: :latest_builds, source: :job_artifacts + has_many :latest_builds, -> { latest.with_project_and_metadata }, foreign_key: :commit_id, inverse_of: :pipeline, class_name: 'Ci::Build' + has_many :downloadable_artifacts, -> { not_expired.downloadable.with_job }, through: :latest_builds, source: :job_artifacts has_many :messages, class_name: 'Ci::PipelineMessage', inverse_of: :pipeline @@ -249,7 +249,7 @@ module Ci after_transition any => ::Ci::Pipeline.completed_statuses do |pipeline| pipeline.run_after_commit do - ::Ci::Pipelines::CreateArtifactWorker.perform_async(pipeline.id) + ::Ci::PipelineArtifacts::CoverageReportWorker.perform_async(pipeline.id) end end diff --git a/app/models/ci/ref.rb b/app/models/ci/ref.rb index 6e9b8416c10..713a0bf9c45 100644 --- a/app/models/ci/ref.rb +++ b/app/models/ci/ref.rb @@ -33,6 +33,9 @@ module Ci state :still_failing, value: 5 after_transition any => [:fixed, :success] do |ci_ref| + # Do not try to unlock if no artifacts are locked + next unless ci_ref.artifacts_locked? + ci_ref.run_after_commit do Ci::PipelineSuccessUnlockArtifactsWorker.perform_async(ci_ref.last_finished_pipeline_id) end @@ -54,6 +57,10 @@ module Ci Ci::Pipeline.last_finished_for_ref_id(self.id)&.id end + def artifacts_locked? + self.pipelines.where(locked: :artifacts_locked).exists? + end + def update_status_by!(pipeline) retry_lock(self) do next unless last_finished_pipeline_id == pipeline.id |