Commit 0364dfef authored by Grzegorz Bizon's avatar Grzegorz Bizon

Merge branch 'bridge-rules' into 'master'

rules: for bridge jobs

See merge request gitlab-org/gitlab!19605
parents 9b892cf4 b564d609
---
title: Added rules configuration for Ci::Bridge
merge_request: 19605
author:
type: added
...@@ -15,19 +15,25 @@ module EE ...@@ -15,19 +15,25 @@ module EE
include ::Gitlab::Config::Entry::Inheritable include ::Gitlab::Config::Entry::Inheritable
ALLOWED_KEYS = %i[trigger stage allow_failure only except ALLOWED_KEYS = %i[trigger stage allow_failure only except
when extends variables needs].freeze when extends variables needs rules].freeze
validations do validations do
validates :config, allowed_keys: ALLOWED_KEYS validates :config, allowed_keys: ALLOWED_KEYS
validates :config, presence: true validates :config, presence: true
validates :name, presence: true validates :name, presence: true
validates :name, type: Symbol validates :name, type: Symbol
validates :config, disallowed_keys: {
in: %i[only except when start_in],
message: 'key may not be used with `rules`'
},
if: :has_rules?
with_options allow_nil: true do with_options allow_nil: true do
validates :when, validates :when,
inclusion: { in: %w[on_success on_failure always], inclusion: { in: %w[on_success on_failure always],
message: 'should be on_success, on_failure or always' } message: 'should be on_success, on_failure or always' }
validates :extends, type: String validates :extends, type: String
validates :rules, array_of_hashes: true
end end
validate on: :composed do validate on: :composed do
...@@ -66,6 +72,13 @@ module EE ...@@ -66,6 +72,13 @@ module EE
description: 'Refs policy this job will be executed for.', description: 'Refs policy this job will be executed for.',
inherit: false inherit: false
entry :rules, ::Gitlab::Ci::Config::Entry::Rules,
description: 'List of evaluable Rules to determine job inclusion.',
inherit: false,
metadata: {
allowed_when: %w[on_success on_failure always never manual delayed].freeze
}
entry :variables, ::Gitlab::Ci::Config::Entry::Variables, entry :variables, ::Gitlab::Ci::Config::Entry::Variables,
description: 'Environment variables available for this job.', description: 'Environment variables available for this job.',
inherit: false inherit: false
...@@ -84,6 +97,21 @@ module EE ...@@ -84,6 +97,21 @@ module EE
true true
end end
def compose!(deps = nil)
super do
# This is something of a hack, see issue for details:
# https://gitlab.com/gitlab-org/gitlab/issues/31685
if !only_defined? && has_rules?
@entries.delete(:only)
@entries.delete(:except)
end
end
end
def has_rules?
@config&.key?(:rules)
end
def name def name
@metadata[:name] @metadata[:name]
end end
...@@ -97,6 +125,7 @@ module EE ...@@ -97,6 +125,7 @@ module EE
when: when_value, when: when_value,
extends: extends_value, extends: extends_value,
variables: (variables_value if variables_defined?), variables: (variables_value if variables_defined?),
rules: (rules_value if has_rules?),
only: only_value, only: only_value,
except: except_value }.compact except: except_value }.compact
end end
......
...@@ -34,6 +34,17 @@ describe EE::Gitlab::Ci::Config::Entry::Bridge do ...@@ -34,6 +34,17 @@ describe EE::Gitlab::Ci::Config::Entry::Bridge do
end end
it { is_expected.to be_falsey } it { is_expected.to be_falsey }
context 'with rules' do
let(:config) do
{
script: 'ls -al',
rules: [{ if: '$VAR == "value"', when: 'always' }]
}
end
it { is_expected.to be_falsey }
end
end end
context 'when config is a bridge job' do context 'when config is a bridge job' do
...@@ -43,6 +54,17 @@ describe EE::Gitlab::Ci::Config::Entry::Bridge do ...@@ -43,6 +54,17 @@ describe EE::Gitlab::Ci::Config::Entry::Bridge do
end end
it { is_expected.to be_truthy } it { is_expected.to be_truthy }
context 'with rules' do
let(:config) do
{
trigger: 'other-project',
rules: [{ if: '$VAR == "value"', when: 'always' }]
}
end
it { is_expected.to be_truthy }
end
end end
context 'when config is a hidden job' do context 'when config is a hidden job' do
...@@ -60,6 +82,16 @@ describe EE::Gitlab::Ci::Config::Entry::Bridge do ...@@ -60,6 +82,16 @@ describe EE::Gitlab::Ci::Config::Entry::Bridge do
subject.compose! subject.compose!
end end
let(:base_config) do
{
trigger: { project: 'some/project', branch: 'feature' },
needs: { pipeline: 'other/project' },
extends: '.some-key',
stage: 'deploy',
variables: { VARIABLE: '123' }
}
end
context 'when trigger config is a non-empty string' do context 'when trigger config is a non-empty string' do
let(:config) { { trigger: 'some/project' } } let(:config) { { trigger: 'some/project' } }
...@@ -117,21 +149,57 @@ describe EE::Gitlab::Ci::Config::Entry::Bridge do ...@@ -117,21 +149,57 @@ describe EE::Gitlab::Ci::Config::Entry::Bridge do
end end
end end
context 'when bridge configuration contains all supported keys' do context 'when bridge configuration contains trigger, needs, when, extends, stage, only, except, and variables' do
let(:config) do let(:config) do
{ trigger: { project: 'some/project', branch: 'feature' }, base_config.merge({
needs: { pipeline: 'other/project' },
when: 'always', when: 'always',
extends: '.some-key',
stage: 'deploy',
only: { variables: %w[$SOMEVARIABLE] }, only: { variables: %w[$SOMEVARIABLE] },
except: { refs: %w[feature] }, except: { refs: %w[feature] }
variables: { VARIABLE: '123' } } })
end end
it { is_expected.to be_valid } it { is_expected.to be_valid }
end end
context 'when bridge configuration uses rules' do
let(:config) { base_config.merge({ rules: [{ if: '$VAR == null', when: 'never' }] }) }
it { is_expected.to be_valid }
end
context 'when bridge configuration uses rules with job:when' do
let(:config) do
base_config.merge({
when: 'always',
rules: [{ if: '$VAR == null', when: 'never' }]
})
end
it { is_expected.not_to be_valid }
end
context 'when bridge configuration uses rules with only' do
let(:config) do
base_config.merge({
only: { variables: %w[$SOMEVARIABLE] },
rules: [{ if: '$VAR == null', when: 'never' }]
})
end
it { is_expected.not_to be_valid }
end
context 'when bridge configuration uses rules with except' do
let(:config) do
base_config.merge({
except: { refs: %w[feature] },
rules: [{ if: '$VAR == null', when: 'never' }]
})
end
it { is_expected.not_to be_valid }
end
context 'when trigger config is nil' do context 'when trigger config is nil' do
let(:config) { { trigger: nil } } let(:config) { { trigger: nil } }
......
...@@ -184,5 +184,44 @@ describe Ci::CreateCrossProjectPipelineService, '#execute' do ...@@ -184,5 +184,44 @@ describe Ci::CreateCrossProjectPipelineService, '#execute' do
end end
end end
end end
# TODO: Move this context into a feature spec that uses
# multiple pipeline processing services. Location TBD in:
# https://gitlab.com/gitlab-org/gitlab/issues/36216
context 'when configured with bridge job rules' do
before do
stub_ci_pipeline_yaml_file(config)
downstream_project.add_maintainer(upstream_project.owner)
end
let(:config) do
<<-EOY
hello:
script: echo world
bridge-job:
rules:
- if: $CI_COMMIT_REF_NAME == "master"
trigger:
project: #{downstream_project.full_path}
branch: master
EOY
end
let(:primary_pipeline) do
Ci::CreatePipelineService.new(upstream_project, upstream_project.owner, { ref: 'master' })
.execute(:push, save_on_errors: false)
end
let(:bridge) { primary_pipeline.processables.find_by(name: 'bridge-job') }
let(:service) { described_class.new(upstream_project, upstream_project.owner) }
context 'that include the bridge job' do
it 'creates the downstream pipeline' do
expect { service.execute(bridge) }
.to change(downstream_project.ci_pipelines, :count).by(1)
end
end
end
end end
end end
...@@ -8,9 +8,10 @@ describe Ci::CreatePipelineService, '#execute' do ...@@ -8,9 +8,10 @@ describe Ci::CreatePipelineService, '#execute' do
set(:plan_limits) { create(:plan_limits, plan: gold_plan) } set(:plan_limits) { create(:plan_limits, plan: gold_plan) }
set(:project) { create(:project, :repository, namespace: namespace) } set(:project) { create(:project, :repository, namespace: namespace) }
set(:user) { create(:user) } set(:user) { create(:user) }
let(:ref_name) { 'master' }
let(:service) do let(:service) do
params = { ref: 'master', params = { ref: ref_name,
before: '00000000', before: '00000000',
after: project.commit.id, after: project.commit.id,
commits: [{ message: 'some commit' }] } commits: [{ message: 'some commit' }] }
...@@ -101,6 +102,46 @@ describe Ci::CreatePipelineService, '#execute' do ...@@ -101,6 +102,46 @@ describe Ci::CreatePipelineService, '#execute' do
expect(bridge.yaml_variables) expect(bridge.yaml_variables)
.to include(key: 'CROSS', value: 'downstream', public: true) .to include(key: 'CROSS', value: 'downstream', public: true)
end end
context 'when configured with rules' do
before do
stub_ci_pipeline_yaml_file(config)
end
let(:downstream_project) { create(:project, :repository) }
let(:config) do
<<-EOY
hello:
script: echo world
bridge-job:
rules:
- if: $CI_COMMIT_REF_NAME == "master"
trigger:
project: #{downstream_project.full_path}
branch: master
EOY
end
context 'that include the bridge job' do
it 'persists the bridge job' do
pipeline = create_pipeline!
expect(pipeline.processables.pluck(:name)).to contain_exactly('hello', 'bridge-job')
end
end
context 'that exclude the bridge job' do
let(:ref_name) { 'refs/heads/wip' }
it 'does not include the bridge job' do
pipeline = create_pipeline!
expect(pipeline.processables.pluck(:name)).to eq(%w[hello])
end
end
end
end end
def create_pipeline! def create_pipeline!
......
...@@ -173,7 +173,7 @@ module Gitlab ...@@ -173,7 +173,7 @@ module Gitlab
@entries.delete(:type) @entries.delete(:type)
# This is something of a hack, see issue for details: # This is something of a hack, see issue for details:
# https://gitlab.com/gitlab-org/gitlab-foss/issues/67150 # https://gitlab.com/gitlab-org/gitlab/issues/31685
if !only_defined? && has_rules? if !only_defined? && has_rules?
@entries.delete(:only) @entries.delete(:only)
@entries.delete(:except) @entries.delete(:except)
......
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