Commit d04a12e0 authored by Marius Bobin's avatar Marius Bobin Committed by Fabio Pitino

Add variable expansion to cross pipeline artifacts

Variables can be specified when adding cross project dependencies with
needs:

```
build_job:
  stage: build
  script:
    - ls -lhR
  needs:
    - project: $CI_PROJECT_PATH
      job: $SOME_JOB_NAME_IN_OTHER_PROJECT
      ref: $CI_COMMIT_BRANCH
      artifacts: true
```
parent 22b5c365
...@@ -9,7 +9,7 @@ module Ci ...@@ -9,7 +9,7 @@ module Ci
## ##
# Variables in the environment name scope. # Variables in the environment name scope.
# #
def scoped_variables(environment: expanded_environment_name) def scoped_variables(environment: expanded_environment_name, dependencies: true)
Gitlab::Ci::Variables::Collection.new.tap do |variables| Gitlab::Ci::Variables::Collection.new.tap do |variables|
variables.concat(predefined_variables) variables.concat(predefined_variables)
variables.concat(project.predefined_variables) variables.concat(project.predefined_variables)
...@@ -18,7 +18,7 @@ module Ci ...@@ -18,7 +18,7 @@ module Ci
variables.concat(deployment_variables(environment: environment)) variables.concat(deployment_variables(environment: environment))
variables.concat(yaml_variables) variables.concat(yaml_variables)
variables.concat(user_variables) variables.concat(user_variables)
variables.concat(dependency_variables) variables.concat(dependency_variables) if dependencies
variables.concat(secret_instance_variables) variables.concat(secret_instance_variables)
variables.concat(secret_group_variables) variables.concat(secret_group_variables)
variables.concat(secret_project_variables(environment: environment)) variables.concat(secret_project_variables(environment: environment))
...@@ -45,6 +45,12 @@ module Ci ...@@ -45,6 +45,12 @@ module Ci
end end
end end
def simple_variables_without_dependencies
strong_memoize(:variables_without_dependencies) do
scoped_variables(environment: nil, dependencies: false).to_runner_variables
end
end
def user_variables def user_variables
Gitlab::Ci::Variables::Collection.new.tap do |variables| Gitlab::Ci::Variables::Collection.new.tap do |variables|
break variables if user.blank? break variables if user.blank?
......
...@@ -2134,6 +2134,26 @@ build_job: ...@@ -2134,6 +2134,26 @@ build_job:
artifacts: true artifacts: true
``` ```
Environment variables support for `project:`, `job:`, and `ref` was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/202093)
in GitLab 13.3. This is under development, but it is ready for production use. It is deployed
behind the `ci_expand_names_for_cross_pipeline_artifacts` feature flag, which is **disabled by default**.
[GitLab administrators with access to the GitLab Rails console](../../administration/feature_flags.md)
can enable it for your instance.
For example:
```yaml
build_job:
stage: build
script:
- ls -lhR
needs:
- project: $CI_PROJECT_PATH
job: $DEPENDENCY_JOB_NAME
ref: $CI_COMMIT_BRANCH
artifacts: true
```
NOTE: **Note:** NOTE: **Note:**
Downloading artifacts from jobs that are run in [`parallel:`](#parallel) is not supported. Downloading artifacts from jobs that are run in [`parallel:`](#parallel) is not supported.
......
...@@ -52,8 +52,11 @@ module EE ...@@ -52,8 +52,11 @@ module EE
def build_cross_dependency_relationship_fragment(dependency, search_scope) def build_cross_dependency_relationship_fragment(dependency, search_scope)
args = dependency.values_at(:job, :ref, :project) args = dependency.values_at(:job, :ref, :project)
dep_id = search_scope.max_build_id_by(*args) if ::Gitlab::Ci::Features.expand_names_for_cross_pipeline_artifacts?(project)
args = args.map { |value| ExpandVariables.expand(value, processable_variables) }
end
dep_id = search_scope.max_build_id_by(*args)
model_class.id_in(dep_id) model_class.id_in(dep_id)
end end
...@@ -61,6 +64,10 @@ module EE ...@@ -61,6 +64,10 @@ module EE
processable.user processable.user
end end
def processable_variables
-> { processable.simple_variables_without_dependencies }
end
def specified_cross_pipeline_dependencies def specified_cross_pipeline_dependencies
Array(processable.options[:cross_dependencies]) Array(processable.options[:cross_dependencies])
end end
......
---
title: Add variable expansion to cross pipeline artifacts
merge_request: 36578
author:
type: added
...@@ -86,6 +86,34 @@ RSpec.describe Ci::BuildDependencies do ...@@ -86,6 +86,34 @@ RSpec.describe Ci::BuildDependencies do
it { is_expected.to be_empty } it { is_expected.to be_empty }
end end
context 'with dependency names from environment variables' do
before do
job.yaml_variables.push(key: 'DEPENDENCY_NAME', value: 'dependency', public: true)
job.save!
end
let(:dependencies) do
[
{
project: '$CI_PROJECT_PATH',
job: '$DEPENDENCY_NAME',
ref: '$CI_COMMIT_BRANCH',
artifacts: true
}
]
end
it { is_expected.to contain_exactly(dependency) }
context 'with the feature flag disabled' do
before do
stub_feature_flags(ci_expand_names_for_cross_pipeline_artifacts: false)
end
it { is_expected.to be_empty }
end
end
end end
context 'with cross_dependencies to another pipeline in same project' do context 'with cross_dependencies to another pipeline in same project' do
......
...@@ -80,4 +80,40 @@ RSpec.describe Ci::CreatePipelineService do ...@@ -80,4 +80,40 @@ RSpec.describe Ci::CreatePipelineService do
expect(bridge_dag_job.status).to eq('pending') expect(bridge_dag_job.status).to eq('pending')
end end
end end
context 'with cross pipeline artifacts' do
let!(:dependency) { create(:ci_build, :success, name: 'dependency', project: downstream_project) }
let!(:dependency_variable) { create(:ci_job_variable, :dotenv_source, job: dependency) }
let(:config) do
<<~EOY
regular_job:
stage: build
variables:
DEPENDENCY_PROJECT: #{downstream_project.full_path}
DEPENDENCY_REF: #{dependency.ref}
DEPENDENCY_NAME: #{dependency.name}
script:
- echo 'hello'
needs:
- project: ${DEPENDENCY_PROJECT}
ref: ${DEPENDENCY_REF}
job: ${DEPENDENCY_NAME}
artifacts: true
EOY
end
before do
stub_ci_pipeline_yaml_file(config)
stub_licensed_features(cross_project_pipelines: true)
end
it 'has dependencies and variables', :aggregate_failures do
job = execute.builds.first
expect(job).to be_present
expect(job.all_dependencies).to include(dependency)
expect(job.scoped_variables_hash).to include(dependency_variable.key => dependency_variable.value)
end
end
end end
...@@ -79,6 +79,10 @@ module Gitlab ...@@ -79,6 +79,10 @@ module Gitlab
def self.reset_ci_minutes_for_all_namespaces? def self.reset_ci_minutes_for_all_namespaces?
::Feature.enabled?(:reset_ci_minutes_for_all_namespaces, default_enabled: false) ::Feature.enabled?(:reset_ci_minutes_for_all_namespaces, default_enabled: false)
end end
def self.expand_names_for_cross_pipeline_artifacts?(project)
::Feature.enabled?(:ci_expand_names_for_cross_pipeline_artifacts, project)
end
end end
end end
end end
......
...@@ -3111,6 +3111,14 @@ RSpec.describe Ci::Build do ...@@ -3111,6 +3111,14 @@ RSpec.describe Ci::Build do
end end
end end
describe '#simple_variables_without_dependencies' do
it 'does not load dependencies' do
expect(build).not_to receive(:dependency_variables)
build.simple_variables_without_dependencies
end
end
shared_examples "secret CI variables" do shared_examples "secret CI variables" do
context 'when ref is branch' do context 'when ref is branch' do
let(:build) { create(:ci_build, ref: 'master', tag: false, project: project) } let(:build) { create(:ci_build, ref: 'master', tag: false, project: project) }
......
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