diff options
Diffstat (limited to 'app/models/ci/build_dependencies.rb')
-rw-r--r-- | app/models/ci/build_dependencies.rb | 78 |
1 files changed, 76 insertions, 2 deletions
diff --git a/app/models/ci/build_dependencies.rb b/app/models/ci/build_dependencies.rb index 7e690dc413c..2c6a9a63bdb 100644 --- a/app/models/ci/build_dependencies.rb +++ b/app/models/ci/build_dependencies.rb @@ -2,6 +2,8 @@ module Ci class BuildDependencies + include ::Gitlab::Utils::StrongMemoize + attr_reader :processable def initialize(processable) @@ -9,7 +11,7 @@ module Ci end def all - (local + cross_project).uniq + (local + cross_pipeline + cross_project).uniq end # Dependencies local to the given pipeline @@ -23,6 +25,14 @@ module Ci deps end + # Dependencies from the same parent-pipeline hierarchy excluding + # the current job's pipeline + def cross_pipeline + strong_memoize(:cross_pipeline) do + fetch_dependencies_in_hierarchy + end + end + # Dependencies that are defined by project and ref def cross_project [] @@ -33,7 +43,7 @@ module Ci end def valid? - valid_local? && valid_cross_project? + valid_local? && valid_cross_pipeline? && valid_cross_project? end private @@ -44,6 +54,54 @@ module Ci ::Ci::Build end + def fetch_dependencies_in_hierarchy + deps_specifications = specified_cross_pipeline_dependencies + return [] if deps_specifications.empty? + + deps_specifications = expand_variables_and_validate(deps_specifications) + jobs_in_pipeline_hierarchy(deps_specifications) + end + + def jobs_in_pipeline_hierarchy(deps_specifications) + all_pipeline_ids = [] + all_job_names = [] + + deps_specifications.each do |spec| + all_pipeline_ids << spec[:pipeline] + all_job_names << spec[:job] + end + + model_class.latest.success + .in_pipelines(processable.pipeline.same_family_pipeline_ids) + .in_pipelines(all_pipeline_ids.uniq) + .by_name(all_job_names.uniq) + .select do |dependency| + # the query may not return exact matches pipeline-job, so we filter + # them separately. + deps_specifications.find do |spec| + spec[:pipeline] == dependency.pipeline_id && + spec[:job] == dependency.name + end + end + end + + def expand_variables_and_validate(specifications) + specifications.map do |spec| + pipeline = ExpandVariables.expand(spec[:pipeline].to_s, processable_variables).to_i + # current pipeline is not allowed because local dependencies + # should be used instead. + next if pipeline == processable.pipeline_id + + job = ExpandVariables.expand(spec[:job], processable_variables) + + { job: job, pipeline: pipeline } + end.compact + end + + def valid_cross_pipeline? + cross_pipeline.size == specified_cross_pipeline_dependencies.size + end + def valid_local? return true if Feature.enabled?(:ci_disable_validates_dependencies) @@ -78,6 +136,22 @@ module Ci scope.where(name: processable.options[:dependencies]) end + + def processable_variables + -> { processable.simple_variables_without_dependencies } + end + + def specified_cross_pipeline_dependencies + strong_memoize(:specified_cross_pipeline_dependencies) do + next [] unless Feature.enabled?(:ci_cross_pipeline_artifacts_download, processable.project, default_enabled: false) + + specified_cross_dependencies.select { |dep| dep[:pipeline] && dep[:artifacts] } + end + end + + def specified_cross_dependencies + Array(processable.options[:cross_dependencies]) + end end end |