diff options
Diffstat (limited to 'app')
-rw-r--r-- | app/models/ci/build.rb | 54 | ||||
-rw-r--r-- | app/models/ci/processable/dependencies.rb | 87 | ||||
-rw-r--r-- | app/models/deployment.rb | 25 | ||||
-rw-r--r-- | app/models/environment.rb | 6 |
4 files changed, 126 insertions, 46 deletions
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index d0ea7439556..f9d17bfc8b7 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -513,14 +513,6 @@ module Ci success? && !deployment.try(:last?) end - def depends_on_builds - # Get builds of the same type - latest_builds = self.pipeline.builds.latest - - # Return builds from previous stages - latest_builds.where('stage_idx < ?', stage_idx) - end - def triggered_by?(current_user) user == current_user end @@ -825,41 +817,15 @@ module Ci end def all_dependencies - (dependencies + cross_dependencies).uniq - end - - def dependencies - return [] if empty_dependencies? - - depended_jobs = depends_on_builds - - # find all jobs that are needed - if Feature.enabled?(:ci_dag_support, project, default_enabled: true) && scheduling_type_dag? - depended_jobs = depended_jobs.where(name: needs.artifacts.select(:name)) - end - - # find all jobs that are dependent on - if options[:dependencies].present? - depended_jobs = depended_jobs.where(name: options[:dependencies]) - end - - # if both needs and dependencies are used, - # the end result will be an intersection between them - depended_jobs - end - - def cross_dependencies - [] - end - - def empty_dependencies? - options[:dependencies]&.empty? + dependencies.all end def has_valid_build_dependencies? - return true if Feature.enabled?('ci_disable_validates_dependencies') + dependencies.valid? + end - dependencies.all?(&:valid_dependency?) + def invalid_dependencies + dependencies.invalid_local end def valid_dependency? @@ -869,10 +835,6 @@ module Ci true end - def invalid_dependencies - dependencies.reject(&:valid_dependency?) - end - def runner_required_feature_names strong_memoize(:runner_required_feature_names) do RUNNER_FEATURES.select do |feature, method| @@ -950,6 +912,12 @@ module Ci private + def dependencies + strong_memoize(:dependencies) do + Ci::Processable::Dependencies.new(self) + end + end + def build_data @build_data ||= Gitlab::DataBuilder::Build.build(self) end diff --git a/app/models/ci/processable/dependencies.rb b/app/models/ci/processable/dependencies.rb new file mode 100644 index 00000000000..9d42ac4dc00 --- /dev/null +++ b/app/models/ci/processable/dependencies.rb @@ -0,0 +1,87 @@ +# frozen_string_literal: true + +module Ci + class Processable + class Dependencies + attr_reader :processable + + def initialize(processable) + @processable = processable + end + + def all + (local + cross_pipeline).uniq + end + + # Dependencies local to the given pipeline + def local + return [] if no_local_dependencies_specified? + + deps = model_class.where(pipeline_id: processable.pipeline_id).latest + deps = from_previous_stages(deps) + deps = from_needs(deps) + deps = from_dependencies(deps) + deps + end + + # Dependencies that are defined in other pipelines + def cross_pipeline + [] + end + + def invalid_local + local.reject(&:valid_dependency?) + end + + def valid? + valid_local? && valid_cross_pipeline? + end + + private + + # Dependencies can only be of Ci::Build type because only builds + # can create artifacts + def model_class + ::Ci::Build + end + + def valid_local? + return true if Feature.enabled?('ci_disable_validates_dependencies') + + local.all?(&:valid_dependency?) + end + + def valid_cross_pipeline? + true + end + + def project + processable.project + end + + def no_local_dependencies_specified? + processable.options[:dependencies]&.empty? + end + + def from_previous_stages(scope) + scope.before_stage(processable.stage_idx) + end + + def from_needs(scope) + return scope unless Feature.enabled?(:ci_dag_support, project, default_enabled: true) + return scope unless processable.scheduling_type_dag? + + needs_names = processable.needs.artifacts.select(:name) + scope.where(name: needs_names) + end + + def from_dependencies(scope) + return scope unless processable.options[:dependencies].present? + + scope.where(name: processable.options[:dependencies]) + end + end + end +end + +Ci::Processable::Dependencies.prepend_if_ee('EE::Ci::Processable::Dependencies') diff --git a/app/models/deployment.rb b/app/models/deployment.rb index 707c4e8157d..ba65acff7f3 100644 --- a/app/models/deployment.rb +++ b/app/models/deployment.rb @@ -7,6 +7,7 @@ class Deployment < ApplicationRecord include UpdatedAtFilterable include Importable include Gitlab::Utils::StrongMemoize + include FastDestroyAll belongs_to :project, required: true belongs_to :environment, required: true @@ -113,6 +114,26 @@ class Deployment < ApplicationRecord success.find_by!(iid: iid) end + class << self + ## + # FastDestroyAll concerns + def begin_fast_destroy + preload(:project).find_each.map do |deployment| + [deployment.project, deployment.ref_path] + end + end + + ## + # FastDestroyAll concerns + def finalize_fast_destroy(params) + by_project = params.group_by(&:shift) + + by_project.each do |project, ref_paths| + project.repository.delete_refs(*ref_paths.flatten) + end + end + end + def commit project.commit(sha) end @@ -280,12 +301,12 @@ class Deployment < ApplicationRecord errors.add(:ref, _('The branch or tag does not exist')) end - private - def ref_path File.join(environment.ref_path, 'deployments', iid.to_s) end + private + def legacy_finished_at self.created_at if success? && !read_attribute(:finished_at) end diff --git a/app/models/environment.rb b/app/models/environment.rb index e9b1c55726d..fecf13f349e 100644 --- a/app/models/environment.rb +++ b/app/models/environment.rb @@ -3,6 +3,7 @@ class Environment < ApplicationRecord include Gitlab::Utils::StrongMemoize include ReactiveCaching + include FastDestroyAll::Helpers self.reactive_cache_refresh_interval = 1.minute self.reactive_cache_lifetime = 55.seconds @@ -10,7 +11,10 @@ class Environment < ApplicationRecord belongs_to :project, required: true - has_many :deployments, -> { visible }, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent + use_fast_destroy :all_deployments + + has_many :all_deployments, class_name: 'Deployment' + has_many :deployments, -> { visible } has_many :successful_deployments, -> { success }, class_name: 'Deployment' has_many :active_deployments, -> { active }, class_name: 'Deployment' has_many :prometheus_alerts, inverse_of: :environment |