Commit dccc98d6 authored by Grzegorz Bizon's avatar Grzegorz Bizon

Merge branch 'move-dependencies-under-ci-build' into 'master'

Move Ci::Processable::Dependencies to Ci::BuildDependencies

See merge request gitlab-org/gitlab!28032
parents cf7c5f68 342de8be
...@@ -914,7 +914,7 @@ module Ci ...@@ -914,7 +914,7 @@ module Ci
def dependencies def dependencies
strong_memoize(:dependencies) do strong_memoize(:dependencies) do
Ci::Processable::Dependencies.new(self) Ci::BuildDependencies.new(self)
end end
end end
......
# frozen_string_literal: true
module Ci
class BuildDependencies
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
Ci::BuildDependencies.prepend_if_ee('EE::Ci::BuildDependencies')
# 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')
# frozen_string_literal: true
module EE
module Ci
module BuildDependencies
extend ActiveSupport::Concern
extend ::Gitlab::Utils::Override
include ::Gitlab::Utils::StrongMemoize
LIMIT = ::Gitlab::Ci::Config::Entry::Needs::NEEDS_CROSS_DEPENDENCIES_LIMIT
override :cross_pipeline
def cross_pipeline
strong_memoize(:cross_pipeline) do
fetch_cross_pipeline
end
end
private
override :valid_cross_pipeline?
def valid_cross_pipeline?
cross_pipeline.size == specified_cross_pipeline_dependencies.size
end
def fetch_cross_pipeline
return [] unless processable.user_id
return [] unless project.feature_available?(:cross_project_pipelines)
cross_dependencies_relationship
.preload(project: [:project_feature])
.select { |job| user.can?(:read_build, job) }
end
def cross_dependencies_relationship
deps = specified_cross_pipeline_dependencies
return model_class.none unless deps.any?
relationship_fragments = build_cross_dependencies_fragments(deps, model_class.latest.success)
return model_class.none unless relationship_fragments.any?
model_class.from_union(relationship_fragments).limit(LIMIT)
end
def build_cross_dependencies_fragments(deps, search_scope)
deps.inject([]) do |fragments, dep|
next fragments unless dep[:artifacts]
fragments << build_cross_dependency_relationship_fragment(dep, search_scope)
end
end
def build_cross_dependency_relationship_fragment(dependency, search_scope)
args = dependency.values_at(:job, :ref, :project)
dep_id = search_scope.max_build_id_by(*args)
model_class.id_in(dep_id)
end
def user
processable.user
end
def specified_cross_pipeline_dependencies
Array(processable.options[:cross_dependencies])
end
end
end
end
# frozen_string_literal: true
module EE
module Ci
module Processable
module Dependencies
extend ActiveSupport::Concern
extend ::Gitlab::Utils::Override
include ::Gitlab::Utils::StrongMemoize
LIMIT = ::Gitlab::Ci::Config::Entry::Needs::NEEDS_CROSS_DEPENDENCIES_LIMIT
override :cross_pipeline
def cross_pipeline
strong_memoize(:cross_pipeline) do
fetch_cross_pipeline
end
end
private
override :valid_cross_pipeline?
def valid_cross_pipeline?
cross_pipeline.size == specified_cross_pipeline_dependencies.size
end
def fetch_cross_pipeline
return [] unless processable.user_id
return [] unless project.feature_available?(:cross_project_pipelines)
cross_dependencies_relationship
.preload(project: [:project_feature])
.select { |job| user.can?(:read_build, job) }
end
def cross_dependencies_relationship
deps = specified_cross_pipeline_dependencies
return model_class.none unless deps.any?
relationship_fragments = build_cross_dependencies_fragments(deps, model_class.latest.success)
return model_class.none unless relationship_fragments.any?
model_class.from_union(relationship_fragments).limit(LIMIT)
end
def build_cross_dependencies_fragments(deps, search_scope)
deps.inject([]) do |fragments, dep|
next fragments unless dep[:artifacts]
fragments << build_cross_dependency_relationship_fragment(dep, search_scope)
end
end
def build_cross_dependency_relationship_fragment(dependency, search_scope)
args = dependency.values_at(:job, :ref, :project)
dep_id = search_scope.max_build_id_by(*args)
model_class.id_in(dep_id)
end
def user
processable.user
end
def specified_cross_pipeline_dependencies
Array(processable.options[:cross_dependencies])
end
end
end
end
end
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
describe Ci::Processable::Dependencies do describe Ci::BuildDependencies do
describe '#cross_pipeline' do describe '#cross_pipeline' do
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let_it_be(:project, refind: true) { create(:project, :repository) } let_it_be(:project, refind: true) { create(:project, :repository) }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
describe Ci::Processable::Dependencies do describe Ci::BuildDependencies do
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let_it_be(:project, reload: true) { create(:project, :repository) } let_it_be(:project, reload: true) { create(:project, :repository) }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment