Commit c60bdf91 authored by Kamil Trzciński's avatar Kamil Trzciński

Merge branch 'backstage/gb/jobs-triggering-policy-specifications' into 'master'

Implement job policy specifications

Closes #37280

See merge request gitlab-org/gitlab-ce!14265
parents 7e69f188 14966419
...@@ -31,6 +31,7 @@ module Ci ...@@ -31,6 +31,7 @@ module Ci
has_many :auto_canceled_jobs, class_name: 'CommitStatus', foreign_key: 'auto_canceled_by_id' has_many :auto_canceled_jobs, class_name: 'CommitStatus', foreign_key: 'auto_canceled_by_id'
delegate :id, to: :project, prefix: true delegate :id, to: :project, prefix: true
delegate :full_path, to: :project, prefix: true
validates :source, exclusion: { in: %w(unknown), unless: :importing? }, on: :create validates :source, exclusion: { in: %w(unknown), unless: :importing? }, on: :create
validates :sha, presence: { unless: :importing? } validates :sha, presence: { unless: :importing? }
...@@ -336,7 +337,7 @@ module Ci ...@@ -336,7 +337,7 @@ module Ci
return @config_processor if defined?(@config_processor) return @config_processor if defined?(@config_processor)
@config_processor ||= begin @config_processor ||= begin
Gitlab::Ci::YamlProcessor.new(ci_yaml_file, project.full_path) Gitlab::Ci::YamlProcessor.new(ci_yaml_file)
rescue Gitlab::Ci::YamlProcessor::ValidationError, Psych::SyntaxError => e rescue Gitlab::Ci::YamlProcessor::ValidationError, Psych::SyntaxError => e
self.yaml_errors = e.message self.yaml_errors = e.message
nil nil
......
module Gitlab
module Ci
module Build
module Policy
def self.fabricate(specs)
specifications = specs.to_h.map do |spec, value|
self.const_get(spec.to_s.camelize).new(value)
end
specifications.compact
end
end
end
end
end
module Gitlab
module Ci
module Build
module Policy
class Kubernetes < Policy::Specification
def initialize(spec)
unless spec.to_sym == :active
raise UnknownPolicyError
end
end
def satisfied_by?(pipeline)
pipeline.has_kubernetes_active?
end
end
end
end
end
end
module Gitlab
module Ci
module Build
module Policy
class Refs < Policy::Specification
def initialize(refs)
@patterns = Array(refs)
end
def satisfied_by?(pipeline)
@patterns.any? do |pattern|
pattern, path = pattern.split('@', 2)
matches_path?(path, pipeline) &&
matches_pattern?(pattern, pipeline)
end
end
private
def matches_path?(path, pipeline)
return true unless path
pipeline.project_full_path == path
end
def matches_pattern?(pattern, pipeline)
return true if pipeline.tag? && pattern == 'tags'
return true if pipeline.branch? && pattern == 'branches'
return true if pipeline.source == pattern
return true if pipeline.source&.pluralize == pattern
if pattern.first == "/" && pattern.last == "/"
Regexp.new(pattern[1...-1]) =~ pipeline.ref
else
pattern == pipeline.ref
end
end
end
end
end
end
end
module Gitlab
module Ci
module Build
module Policy
##
# Abstract class that defines an interface of job policy
# specification.
#
# Used for job's only/except policy configuration.
#
class Specification
UnknownPolicyError = Class.new(StandardError)
def initialize(spec)
@spec = spec
end
def satisfied_by?(pipeline)
raise NotImplementedError
end
end
end
end
end
end
...@@ -5,12 +5,11 @@ module Gitlab ...@@ -5,12 +5,11 @@ module Gitlab
include Gitlab::Ci::Config::Entry::LegacyValidationHelpers include Gitlab::Ci::Config::Entry::LegacyValidationHelpers
attr_reader :path, :cache, :stages, :jobs attr_reader :cache, :stages, :jobs
def initialize(config, path = nil) def initialize(config)
@ci_config = Gitlab::Ci::Config.new(config) @ci_config = Gitlab::Ci::Config.new(config)
@config = @ci_config.to_hash @config = @ci_config.to_hash
@path = path
unless @ci_config.valid? unless @ci_config.valid?
raise ValidationError, @ci_config.errors.first raise ValidationError, @ci_config.errors.first
...@@ -21,28 +20,12 @@ module Gitlab ...@@ -21,28 +20,12 @@ module Gitlab
raise ValidationError, e.message raise ValidationError, e.message
end end
def builds_for_stage_and_ref(stage, ref, tag = false, source = nil)
jobs_for_stage_and_ref(stage, ref, tag, source).map do |name, _|
build_attributes(name)
end
end
def builds def builds
@jobs.map do |name, _| @jobs.map do |name, _|
build_attributes(name) build_attributes(name)
end end
end end
def stage_seeds(pipeline)
seeds = @stages.uniq.map do |stage|
builds = pipeline_stage_builds(stage, pipeline)
Gitlab::Ci::Stage::Seed.new(pipeline, stage, builds) if builds.any?
end
seeds.compact
end
def build_attributes(name) def build_attributes(name)
job = @jobs[name.to_sym] || {} job = @jobs[name.to_sym] || {}
...@@ -70,6 +53,32 @@ module Gitlab ...@@ -70,6 +53,32 @@ module Gitlab
}.compact } }.compact }
end end
def pipeline_stage_builds(stage, pipeline)
selected_jobs = @jobs.select do |_, job|
next unless job[:stage] == stage
only_specs = Gitlab::Ci::Build::Policy
.fabricate(job.fetch(:only, {}))
except_specs = Gitlab::Ci::Build::Policy
.fabricate(job.fetch(:except, {}))
only_specs.all? { |spec| spec.satisfied_by?(pipeline) } &&
except_specs.none? { |spec| spec.satisfied_by?(pipeline) }
end
selected_jobs.map { |_, job| build_attributes(job[:name]) }
end
def stage_seeds(pipeline)
seeds = @stages.uniq.map do |stage|
builds = pipeline_stage_builds(stage, pipeline)
Gitlab::Ci::Stage::Seed.new(pipeline, stage, builds) if builds.any?
end
seeds.compact
end
def self.validation_message(content) def self.validation_message(content)
return 'Please provide content of .gitlab-ci.yml' if content.blank? return 'Please provide content of .gitlab-ci.yml' if content.blank?
...@@ -83,34 +92,6 @@ module Gitlab ...@@ -83,34 +92,6 @@ module Gitlab
private private
def pipeline_stage_builds(stage, pipeline)
builds = builds_for_stage_and_ref(
stage, pipeline.ref, pipeline.tag?, pipeline.source)
builds.select do |build|
job = @jobs[build.fetch(:name).to_sym]
has_kubernetes = pipeline.has_kubernetes_active?
only_kubernetes = job.dig(:only, :kubernetes)
except_kubernetes = job.dig(:except, :kubernetes)
[!only_kubernetes && !except_kubernetes,
only_kubernetes && has_kubernetes,
except_kubernetes && !has_kubernetes].any?
end
end
def jobs_for_ref(ref, tag = false, source = nil)
@jobs.select do |_, job|
process?(job.dig(:only, :refs), job.dig(:except, :refs), ref, tag, source)
end
end
def jobs_for_stage_and_ref(stage, ref, tag = false, source = nil)
jobs_for_ref(ref, tag, source).select do |_, job|
job[:stage] == stage
end
end
def initial_parsing def initial_parsing
## ##
# Global config # Global config
...@@ -203,51 +184,6 @@ module Gitlab ...@@ -203,51 +184,6 @@ module Gitlab
raise ValidationError, "#{name} job: on_stop job #{on_stop} needs to have action stop defined" raise ValidationError, "#{name} job: on_stop job #{on_stop} needs to have action stop defined"
end end
end end
def process?(only_params, except_params, ref, tag, source)
if only_params.present?
return false unless matching?(only_params, ref, tag, source)
end
if except_params.present?
return false if matching?(except_params, ref, tag, source)
end
true
end
def matching?(patterns, ref, tag, source)
patterns.any? do |pattern|
pattern, path = pattern.split('@', 2)
matches_path?(path) && matches_pattern?(pattern, ref, tag, source)
end
end
def matches_path?(path)
return true unless path
path == self.path
end
def matches_pattern?(pattern, ref, tag, source)
return true if tag && pattern == 'tags'
return true if !tag && pattern == 'branches'
return true if source_to_pattern(source) == pattern
if pattern.first == "/" && pattern.last == "/"
Regexp.new(pattern[1...-1]) =~ ref
else
pattern == ref
end
end
def source_to_pattern(source)
if %w[api external web].include?(source)
source
else
source&.pluralize
end
end
end end
end end
end end
require 'spec_helper'
describe Gitlab::Ci::Build::Policy::Kubernetes do
let(:pipeline) { create(:ci_pipeline, project: project) }
context 'when kubernetes service is active' do
set(:project) { create(:kubernetes_project) }
it 'is satisfied by a kubernetes pipeline' do
expect(described_class.new('active'))
.to be_satisfied_by(pipeline)
end
end
context 'when kubernetes service is inactive' do
set(:project) { create(:project) }
it 'is not satisfied by a pipeline without kubernetes available' do
expect(described_class.new('active'))
.not_to be_satisfied_by(pipeline)
end
end
context 'when kubernetes policy is invalid' do
it 'raises an error' do
expect { described_class.new('unknown') }
.to raise_error(described_class::UnknownPolicyError)
end
end
end
require 'spec_helper'
describe Gitlab::Ci::Build::Policy::Refs do
describe '#satisfied_by?' do
context 'when matching ref' do
let(:pipeline) { build_stubbed(:ci_pipeline, ref: 'master') }
it 'is satisfied when pipeline branch matches' do
expect(described_class.new(%w[master deploy]))
.to be_satisfied_by(pipeline)
end
it 'is not satisfied when pipeline branch does not match' do
expect(described_class.new(%w[feature fix]))
.not_to be_satisfied_by(pipeline)
end
end
context 'when maching tags' do
context 'when pipeline runs for a tag' do
let(:pipeline) do
build_stubbed(:ci_pipeline, ref: 'feature', tag: true)
end
it 'is satisfied when tags matcher is specified' do
expect(described_class.new(%w[master tags]))
.to be_satisfied_by(pipeline)
end
end
context 'when pipeline is not created for a tag' do
let(:pipeline) do
build_stubbed(:ci_pipeline, ref: 'feature', tag: false)
end
it 'is not satisfied when tag match is specified' do
expect(described_class.new(%w[master tags]))
.not_to be_satisfied_by(pipeline)
end
end
end
context 'when also matching a path' do
let(:pipeline) do
build_stubbed(:ci_pipeline, ref: 'master')
end
it 'is satisfied when provided patch matches specified one' do
expect(described_class.new(%W[master@#{pipeline.project_full_path}]))
.to be_satisfied_by(pipeline)
end
it 'is not satisfied when path differs' do
expect(described_class.new(%w[master@some/fork/repository]))
.not_to be_satisfied_by(pipeline)
end
end
context 'when maching a source' do
let(:pipeline) { build_stubbed(:ci_pipeline, source: :push) }
it 'is satisifed when provided source keyword matches' do
expect(described_class.new(%w[pushes]))
.to be_satisfied_by(pipeline)
end
it 'is not satisfied when provided source keyword does not match' do
expect(described_class.new(%w[triggers]))
.not_to be_satisfied_by(pipeline)
end
end
context 'when matching a ref by a regular expression' do
let(:pipeline) { build_stubbed(:ci_pipeline, ref: 'docs-something') }
it 'is satisfied when regexp matches pipeline ref' do
expect(described_class.new(['/docs-.*/']))
.to be_satisfied_by(pipeline)
end
it 'is not satisfied when regexp does not match pipeline ref' do
expect(described_class.new(['/fix-.*/']))
.not_to be_satisfied_by(pipeline)
end
end
end
end
require 'spec_helper'
describe Gitlab::Ci::Build::Policy do
let(:policy) { spy('policy specification') }
before do
stub_const("#{described_class}::Something", policy)
end
describe '.fabricate' do
context 'when policy exists' do
it 'fabricates and initializes relevant policy' do
specs = described_class.fabricate(something: 'some value')
expect(specs).to be_an Array
expect(specs).to be_one
expect(policy).to have_received(:new).with('some value')
end
end
context 'when some policies are not defined' do
it 'gracefully skips unknown policies' do
expect { described_class.fabricate(unknown: 'first') }
.to raise_error(NameError)
end
end
context 'when passing a nil value as specs' do
it 'returns an empty array' do
specs = described_class.fabricate(nil)
expect(specs).to be_an Array
expect(specs).to be_empty
end
end
end
end
...@@ -3,8 +3,7 @@ require 'spec_helper' ...@@ -3,8 +3,7 @@ require 'spec_helper'
module Gitlab module Gitlab
module Ci module Ci
describe YamlProcessor, :lib do describe YamlProcessor, :lib do
subject { described_class.new(config, path) } subject { described_class.new(config) }
let(:path) { 'path' }
describe 'our current .gitlab-ci.yml' do describe 'our current .gitlab-ci.yml' do
let(:config) { File.read("#{Rails.root}/.gitlab-ci.yml") } let(:config) { File.read("#{Rails.root}/.gitlab-ci.yml") }
...@@ -17,7 +16,7 @@ module Gitlab ...@@ -17,7 +16,7 @@ module Gitlab
end end
describe '#build_attributes' do describe '#build_attributes' do
subject { described_class.new(config, path).build_attributes(:rspec) } subject { described_class.new(config).build_attributes(:rspec) }
describe 'coverage entry' do describe 'coverage entry' do
describe 'code coverage regexp' do describe 'code coverage regexp' do
...@@ -167,8 +166,6 @@ module Gitlab ...@@ -167,8 +166,6 @@ module Gitlab
end end
context 'when kubernetes policy is specified' do context 'when kubernetes policy is specified' do
let(:pipeline) { create(:ci_empty_pipeline) }
let(:config) do let(:config) do
YAML.dump( YAML.dump(
spinach: { stage: 'test', script: 'spinach' }, spinach: { stage: 'test', script: 'spinach' },
...@@ -204,7 +201,7 @@ module Gitlab ...@@ -204,7 +201,7 @@ module Gitlab
end end
end end
describe "#builds_for_stage_and_ref" do describe "#pipeline_stage_builds" do
let(:type) { 'test' } let(:type) { 'test' }
it "returns builds if no branch specified" do it "returns builds if no branch specified" do
...@@ -213,10 +210,10 @@ module Gitlab ...@@ -213,10 +210,10 @@ module Gitlab
rspec: { script: "rspec" } rspec: { script: "rspec" }
}) })
config_processor = Gitlab::Ci::YamlProcessor.new(config, path) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(1) expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "master")).size).to eq(1)
expect(config_processor.builds_for_stage_and_ref(type, "master").first).to eq({ expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "master")).first).to eq({
stage: "test", stage: "test",
stage_idx: 1, stage_idx: 1,
name: "rspec", name: "rspec",
...@@ -241,9 +238,9 @@ module Gitlab ...@@ -241,9 +238,9 @@ module Gitlab
rspec: { script: "rspec", only: ["deploy"] } rspec: { script: "rspec", only: ["deploy"] }
}) })
config_processor = Gitlab::Ci::YamlProcessor.new(config, path) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(0) expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "master")).size).to eq(0)
end end
it "does not return builds if only has regexp with another branch" do it "does not return builds if only has regexp with another branch" do
...@@ -252,9 +249,9 @@ module Gitlab ...@@ -252,9 +249,9 @@ module Gitlab
rspec: { script: "rspec", only: ["/^deploy$/"] } rspec: { script: "rspec", only: ["/^deploy$/"] }
}) })
config_processor = Gitlab::Ci::YamlProcessor.new(config, path) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(0) expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "master")).size).to eq(0)
end end
it "returns builds if only has specified this branch" do it "returns builds if only has specified this branch" do
...@@ -263,9 +260,9 @@ module Gitlab ...@@ -263,9 +260,9 @@ module Gitlab
rspec: { script: "rspec", only: ["master"] } rspec: { script: "rspec", only: ["master"] }
}) })
config_processor = Gitlab::Ci::YamlProcessor.new(config, path) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(1) expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "master")).size).to eq(1)
end end
it "returns builds if only has a list of branches including specified" do it "returns builds if only has a list of branches including specified" do
...@@ -274,9 +271,9 @@ module Gitlab ...@@ -274,9 +271,9 @@ module Gitlab
rspec: { script: "rspec", type: type, only: %w(master deploy) } rspec: { script: "rspec", type: type, only: %w(master deploy) }
}) })
config_processor = Gitlab::Ci::YamlProcessor.new(config, path) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1) expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "deploy")).size).to eq(1)
end end
it "returns builds if only has a branches keyword specified" do it "returns builds if only has a branches keyword specified" do
...@@ -285,9 +282,9 @@ module Gitlab ...@@ -285,9 +282,9 @@ module Gitlab
rspec: { script: "rspec", type: type, only: ["branches"] } rspec: { script: "rspec", type: type, only: ["branches"] }
}) })
config_processor = Gitlab::Ci::YamlProcessor.new(config, path) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1) expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "deploy")).size).to eq(1)
end end
it "does not return builds if only has a tags keyword" do it "does not return builds if only has a tags keyword" do
...@@ -296,9 +293,9 @@ module Gitlab ...@@ -296,9 +293,9 @@ module Gitlab
rspec: { script: "rspec", type: type, only: ["tags"] } rspec: { script: "rspec", type: type, only: ["tags"] }
}) })
config_processor = Gitlab::Ci::YamlProcessor.new(config, path) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(0) expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "deploy")).size).to eq(0)
end end
it "returns builds if only has special keywords specified and source matches" do it "returns builds if only has special keywords specified and source matches" do
...@@ -315,9 +312,9 @@ module Gitlab ...@@ -315,9 +312,9 @@ module Gitlab
rspec: { script: "rspec", type: type, only: [possibility[:keyword]] } rspec: { script: "rspec", type: type, only: [possibility[:keyword]] }
}) })
config_processor = Gitlab::Ci::YamlProcessor.new(config, path) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, possibility[:source]).size).to eq(1) expect(config_processor.pipeline_stage_builds(type, pipeline(ref: 'deploy', tag: false, source: possibility[:source])).size).to eq(1)
end end
end end
...@@ -335,21 +332,27 @@ module Gitlab ...@@ -335,21 +332,27 @@ module Gitlab
rspec: { script: "rspec", type: type, only: [possibility[:keyword]] } rspec: { script: "rspec", type: type, only: [possibility[:keyword]] }
}) })
config_processor = Gitlab::Ci::YamlProcessor.new(config, path) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, possibility[:source]).size).to eq(0) expect(config_processor.pipeline_stage_builds(type, pipeline(ref: 'deploy', tag: false, source: possibility[:source])).size).to eq(0)
end end
end end
it "returns builds if only has current repository path" do it "returns builds if only has current repository path" do
seed_pipeline = pipeline(ref: 'deploy')
config = YAML.dump({ config = YAML.dump({
before_script: ["pwd"], before_script: ["pwd"],
rspec: { script: "rspec", type: type, only: ["branches@path"] } rspec: {
script: "rspec",
type: type,
only: ["branches@#{seed_pipeline.project_full_path}"]
}
}) })
config_processor = Gitlab::Ci::YamlProcessor.new(config, path) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1) expect(config_processor.pipeline_stage_builds(type, seed_pipeline).size).to eq(1)
end end
it "does not return builds if only has different repository path" do it "does not return builds if only has different repository path" do
...@@ -358,9 +361,9 @@ module Gitlab ...@@ -358,9 +361,9 @@ module Gitlab
rspec: { script: "rspec", type: type, only: ["branches@fork"] } rspec: { script: "rspec", type: type, only: ["branches@fork"] }
}) })
config_processor = Gitlab::Ci::YamlProcessor.new(config, path) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(0) expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "deploy")).size).to eq(0)
end end
it "returns build only for specified type" do it "returns build only for specified type" do
...@@ -371,11 +374,11 @@ module Gitlab ...@@ -371,11 +374,11 @@ module Gitlab
production: { script: "deploy", type: "deploy", only: ["master@path", "deploy"] } production: { script: "deploy", type: "deploy", only: ["master@path", "deploy"] }
}) })
config_processor = Gitlab::Ci::YamlProcessor.new(config, 'fork') config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.builds_for_stage_and_ref("deploy", "deploy").size).to eq(2) expect(config_processor.pipeline_stage_builds("deploy", pipeline(ref: "deploy")).size).to eq(2)
expect(config_processor.builds_for_stage_and_ref("test", "deploy").size).to eq(1) expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "deploy")).size).to eq(1)
expect(config_processor.builds_for_stage_and_ref("deploy", "master").size).to eq(1) expect(config_processor.pipeline_stage_builds("deploy", pipeline(ref: "master")).size).to eq(1)
end end
context 'for invalid value' do context 'for invalid value' do
...@@ -418,9 +421,9 @@ module Gitlab ...@@ -418,9 +421,9 @@ module Gitlab
rspec: { script: "rspec", except: ["deploy"] } rspec: { script: "rspec", except: ["deploy"] }
}) })
config_processor = Gitlab::Ci::YamlProcessor.new(config, path) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(1) expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "master")).size).to eq(1)
end end
it "returns builds if except has regexp with another branch" do it "returns builds if except has regexp with another branch" do
...@@ -429,9 +432,9 @@ module Gitlab ...@@ -429,9 +432,9 @@ module Gitlab
rspec: { script: "rspec", except: ["/^deploy$/"] } rspec: { script: "rspec", except: ["/^deploy$/"] }
}) })
config_processor = Gitlab::Ci::YamlProcessor.new(config, path) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(1) expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "master")).size).to eq(1)
end end
it "does not return builds if except has specified this branch" do it "does not return builds if except has specified this branch" do
...@@ -440,9 +443,9 @@ module Gitlab ...@@ -440,9 +443,9 @@ module Gitlab
rspec: { script: "rspec", except: ["master"] } rspec: { script: "rspec", except: ["master"] }
}) })
config_processor = Gitlab::Ci::YamlProcessor.new(config, path) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(0) expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "master")).size).to eq(0)
end end
it "does not return builds if except has a list of branches including specified" do it "does not return builds if except has a list of branches including specified" do
...@@ -451,9 +454,9 @@ module Gitlab ...@@ -451,9 +454,9 @@ module Gitlab
rspec: { script: "rspec", type: type, except: %w(master deploy) } rspec: { script: "rspec", type: type, except: %w(master deploy) }
}) })
config_processor = Gitlab::Ci::YamlProcessor.new(config, path) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(0) expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "deploy")).size).to eq(0)
end end
it "does not return builds if except has a branches keyword specified" do it "does not return builds if except has a branches keyword specified" do
...@@ -462,9 +465,9 @@ module Gitlab ...@@ -462,9 +465,9 @@ module Gitlab
rspec: { script: "rspec", type: type, except: ["branches"] } rspec: { script: "rspec", type: type, except: ["branches"] }
}) })
config_processor = Gitlab::Ci::YamlProcessor.new(config, path) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(0) expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "deploy")).size).to eq(0)
end end
it "returns builds if except has a tags keyword" do it "returns builds if except has a tags keyword" do
...@@ -473,9 +476,9 @@ module Gitlab ...@@ -473,9 +476,9 @@ module Gitlab
rspec: { script: "rspec", type: type, except: ["tags"] } rspec: { script: "rspec", type: type, except: ["tags"] }
}) })
config_processor = Gitlab::Ci::YamlProcessor.new(config, path) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1) expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "deploy")).size).to eq(1)
end end
it "does not return builds if except has special keywords specified and source matches" do it "does not return builds if except has special keywords specified and source matches" do
...@@ -492,9 +495,9 @@ module Gitlab ...@@ -492,9 +495,9 @@ module Gitlab
rspec: { script: "rspec", type: type, except: [possibility[:keyword]] } rspec: { script: "rspec", type: type, except: [possibility[:keyword]] }
}) })
config_processor = Gitlab::Ci::YamlProcessor.new(config, path) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, possibility[:source]).size).to eq(0) expect(config_processor.pipeline_stage_builds(type, pipeline(ref: 'deploy', tag: false, source: possibility[:source])).size).to eq(0)
end end
end end
...@@ -512,21 +515,27 @@ module Gitlab ...@@ -512,21 +515,27 @@ module Gitlab
rspec: { script: "rspec", type: type, except: [possibility[:keyword]] } rspec: { script: "rspec", type: type, except: [possibility[:keyword]] }
}) })
config_processor = Gitlab::Ci::YamlProcessor.new(config, path) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, possibility[:source]).size).to eq(1) expect(config_processor.pipeline_stage_builds(type, pipeline(ref: 'deploy', tag: false, source: possibility[:source])).size).to eq(1)
end end
end end
it "does not return builds if except has current repository path" do it "does not return builds if except has current repository path" do
seed_pipeline = pipeline(ref: 'deploy')
config = YAML.dump({ config = YAML.dump({
before_script: ["pwd"], before_script: ["pwd"],
rspec: { script: "rspec", type: type, except: ["branches@path"] } rspec: {
script: "rspec",
type: type,
except: ["branches@#{seed_pipeline.project_full_path}"]
}
}) })
config_processor = Gitlab::Ci::YamlProcessor.new(config, path) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(0) expect(config_processor.pipeline_stage_builds(type, seed_pipeline).size).to eq(0)
end end
it "returns builds if except has different repository path" do it "returns builds if except has different repository path" do
...@@ -535,24 +544,28 @@ module Gitlab ...@@ -535,24 +544,28 @@ module Gitlab
rspec: { script: "rspec", type: type, except: ["branches@fork"] } rspec: { script: "rspec", type: type, except: ["branches@fork"] }
}) })
config_processor = Gitlab::Ci::YamlProcessor.new(config, path) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1) expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "deploy")).size).to eq(1)
end end
it "returns build except specified type" do it "returns build except specified type" do
master_pipeline = pipeline(ref: 'master')
test_pipeline = pipeline(ref: 'test')
deploy_pipeline = pipeline(ref: 'deploy')
config = YAML.dump({ config = YAML.dump({
before_script: ["pwd"], before_script: ["pwd"],
rspec: { script: "rspec", type: "test", except: ["master", "deploy", "test@fork"] }, rspec: { script: "rspec", type: "test", except: ["master", "deploy", "test@#{test_pipeline.project_full_path}"] },
staging: { script: "deploy", type: "deploy", except: ["master"] }, staging: { script: "deploy", type: "deploy", except: ["master"] },
production: { script: "deploy", type: "deploy", except: ["master@fork"] } production: { script: "deploy", type: "deploy", except: ["master@#{master_pipeline.project_full_path}"] }
}) })
config_processor = Gitlab::Ci::YamlProcessor.new(config, 'fork') config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.builds_for_stage_and_ref("deploy", "deploy").size).to eq(2) expect(config_processor.pipeline_stage_builds("deploy", deploy_pipeline).size).to eq(2)
expect(config_processor.builds_for_stage_and_ref("test", "test").size).to eq(0) expect(config_processor.pipeline_stage_builds("test", test_pipeline).size).to eq(0)
expect(config_processor.builds_for_stage_and_ref("deploy", "master").size).to eq(0) expect(config_processor.pipeline_stage_builds("deploy", master_pipeline).size).to eq(0)
end end
context 'for invalid value' do context 'for invalid value' do
...@@ -591,9 +604,9 @@ module Gitlab ...@@ -591,9 +604,9 @@ module Gitlab
describe "Scripts handling" do describe "Scripts handling" do
let(:config_data) { YAML.dump(config) } let(:config_data) { YAML.dump(config) }
let(:config_processor) { Gitlab::Ci::YamlProcessor.new(config_data, path) } let(:config_processor) { Gitlab::Ci::YamlProcessor.new(config_data) }
subject { config_processor.builds_for_stage_and_ref("test", "master").first } subject { config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).first }
describe "before_script" do describe "before_script" do
context "in global context" do context "in global context" do
...@@ -674,10 +687,10 @@ module Gitlab ...@@ -674,10 +687,10 @@ module Gitlab
before_script: ["pwd"], before_script: ["pwd"],
rspec: { script: "rspec" } }) rspec: { script: "rspec" } })
config_processor = Gitlab::Ci::YamlProcessor.new(config, path) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1) expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).size).to eq(1)
expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({ expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).first).to eq({
stage: "test", stage: "test",
stage_idx: 1, stage_idx: 1,
name: "rspec", name: "rspec",
...@@ -709,10 +722,10 @@ module Gitlab ...@@ -709,10 +722,10 @@ module Gitlab
command: ["/usr/local/bin/init", "run"] }, "docker:dind"], command: ["/usr/local/bin/init", "run"] }, "docker:dind"],
script: "rspec" } }) script: "rspec" } })
config_processor = Gitlab::Ci::YamlProcessor.new(config, path) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1) expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).size).to eq(1)
expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({ expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).first).to eq({
stage: "test", stage: "test",
stage_idx: 1, stage_idx: 1,
name: "rspec", name: "rspec",
...@@ -742,10 +755,10 @@ module Gitlab ...@@ -742,10 +755,10 @@ module Gitlab
before_script: ["pwd"], before_script: ["pwd"],
rspec: { script: "rspec" } }) rspec: { script: "rspec" } })
config_processor = Gitlab::Ci::YamlProcessor.new(config, path) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1) expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).size).to eq(1)
expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({ expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).first).to eq({
stage: "test", stage: "test",
stage_idx: 1, stage_idx: 1,
name: "rspec", name: "rspec",
...@@ -771,10 +784,10 @@ module Gitlab ...@@ -771,10 +784,10 @@ module Gitlab
before_script: ["pwd"], before_script: ["pwd"],
rspec: { image: "ruby:2.5", services: ["postgresql", "docker:dind"], script: "rspec" } }) rspec: { image: "ruby:2.5", services: ["postgresql", "docker:dind"], script: "rspec" } })
config_processor = Gitlab::Ci::YamlProcessor.new(config, path) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1) expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).size).to eq(1)
expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({ expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).first).to eq({
stage: "test", stage: "test",
stage_idx: 1, stage_idx: 1,
name: "rspec", name: "rspec",
...@@ -797,7 +810,7 @@ module Gitlab ...@@ -797,7 +810,7 @@ module Gitlab
end end
describe 'Variables' do describe 'Variables' do
let(:config_processor) { Gitlab::Ci::YamlProcessor.new(YAML.dump(config), path) } let(:config_processor) { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)) }
subject { config_processor.builds.first[:yaml_variables] } subject { config_processor.builds.first[:yaml_variables] }
...@@ -918,9 +931,9 @@ module Gitlab ...@@ -918,9 +931,9 @@ module Gitlab
rspec: { script: "rspec", when: when_state } rspec: { script: "rspec", when: when_state }
}) })
config_processor = Gitlab::Ci::YamlProcessor.new(config, path) config_processor = Gitlab::Ci::YamlProcessor.new(config)
builds = config_processor.builds_for_stage_and_ref("test", "master") builds = config_processor.pipeline_stage_builds("test", pipeline(ref: "master"))
expect(builds.size).to eq(1) expect(builds.size).to eq(1)
expect(builds.first[:when]).to eq(when_state) expect(builds.first[:when]).to eq(when_state)
end end
...@@ -951,8 +964,8 @@ module Gitlab ...@@ -951,8 +964,8 @@ module Gitlab
config_processor = Gitlab::Ci::YamlProcessor.new(config) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1) expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).size).to eq(1)
expect(config_processor.builds_for_stage_and_ref("test", "master").first[:options][:cache]).to eq( expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).first[:options][:cache]).to eq(
paths: ["logs/", "binaries/"], paths: ["logs/", "binaries/"],
untracked: true, untracked: true,
key: 'key', key: 'key',
...@@ -970,8 +983,8 @@ module Gitlab ...@@ -970,8 +983,8 @@ module Gitlab
config_processor = Gitlab::Ci::YamlProcessor.new(config) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1) expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).size).to eq(1)
expect(config_processor.builds_for_stage_and_ref("test", "master").first[:options][:cache]).to eq( expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).first[:options][:cache]).to eq(
paths: ["logs/", "binaries/"], paths: ["logs/", "binaries/"],
untracked: true, untracked: true,
key: 'key', key: 'key',
...@@ -990,8 +1003,8 @@ module Gitlab ...@@ -990,8 +1003,8 @@ module Gitlab
config_processor = Gitlab::Ci::YamlProcessor.new(config) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1) expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).size).to eq(1)
expect(config_processor.builds_for_stage_and_ref("test", "master").first[:options][:cache]).to eq( expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).first[:options][:cache]).to eq(
paths: ["test/"], paths: ["test/"],
untracked: false, untracked: false,
key: 'local', key: 'local',
...@@ -1019,8 +1032,8 @@ module Gitlab ...@@ -1019,8 +1032,8 @@ module Gitlab
config_processor = Gitlab::Ci::YamlProcessor.new(config) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1) expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).size).to eq(1)
expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({ expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).first).to eq({
stage: "test", stage: "test",
stage_idx: 1, stage_idx: 1,
name: "rspec", name: "rspec",
...@@ -1055,9 +1068,9 @@ module Gitlab ...@@ -1055,9 +1068,9 @@ module Gitlab
} }
}) })
config_processor = Gitlab::Ci::YamlProcessor.new(config, path) config_processor = Gitlab::Ci::YamlProcessor.new(config)
builds = config_processor.builds_for_stage_and_ref("test", "master") builds = config_processor.pipeline_stage_builds("test", pipeline(ref: "master"))
expect(builds.size).to eq(1) expect(builds.size).to eq(1)
expect(builds.first[:options][:artifacts][:when]).to eq(when_state) expect(builds.first[:options][:artifacts][:when]).to eq(when_state)
end end
...@@ -1072,7 +1085,7 @@ module Gitlab ...@@ -1072,7 +1085,7 @@ module Gitlab
end end
let(:processor) { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)) } let(:processor) { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)) }
let(:builds) { processor.builds_for_stage_and_ref('deploy', 'master') } let(:builds) { processor.pipeline_stage_builds('deploy', pipeline(ref: 'master')) }
context 'when a production environment is specified' do context 'when a production environment is specified' do
let(:environment) { 'production' } let(:environment) { 'production' }
...@@ -1229,7 +1242,7 @@ module Gitlab ...@@ -1229,7 +1242,7 @@ module Gitlab
describe "Hidden jobs" do describe "Hidden jobs" do
let(:config_processor) { Gitlab::Ci::YamlProcessor.new(config) } let(:config_processor) { Gitlab::Ci::YamlProcessor.new(config) }
subject { config_processor.builds_for_stage_and_ref("test", "master") } subject { config_processor.pipeline_stage_builds("test", pipeline(ref: "master")) }
shared_examples 'hidden_job_handling' do shared_examples 'hidden_job_handling' do
it "doesn't create jobs that start with dot" do it "doesn't create jobs that start with dot" do
...@@ -1277,7 +1290,7 @@ module Gitlab ...@@ -1277,7 +1290,7 @@ module Gitlab
describe "YAML Alias/Anchor" do describe "YAML Alias/Anchor" do
let(:config_processor) { Gitlab::Ci::YamlProcessor.new(config) } let(:config_processor) { Gitlab::Ci::YamlProcessor.new(config) }
subject { config_processor.builds_for_stage_and_ref("build", "master") } subject { config_processor.pipeline_stage_builds("build", pipeline(ref: "master")) }
shared_examples 'job_templates_handling' do shared_examples 'job_templates_handling' do
it "is correctly supported for jobs" do it "is correctly supported for jobs" do
...@@ -1377,182 +1390,182 @@ EOT ...@@ -1377,182 +1390,182 @@ EOT
it "returns errors if tags parameter is invalid" do it "returns errors if tags parameter is invalid" do
config = YAML.dump({ rspec: { script: "test", tags: "mysql" } }) config = YAML.dump({ rspec: { script: "test", tags: "mysql" } })
expect do expect do
Gitlab::Ci::YamlProcessor.new(config, path) Gitlab::Ci::YamlProcessor.new(config)
end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec tags should be an array of strings") end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec tags should be an array of strings")
end end
it "returns errors if before_script parameter is invalid" do it "returns errors if before_script parameter is invalid" do
config = YAML.dump({ before_script: "bundle update", rspec: { script: "test" } }) config = YAML.dump({ before_script: "bundle update", rspec: { script: "test" } })
expect do expect do
Gitlab::Ci::YamlProcessor.new(config, path) Gitlab::Ci::YamlProcessor.new(config)
end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "before_script config should be an array of strings") end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "before_script config should be an array of strings")
end end
it "returns errors if job before_script parameter is not an array of strings" do it "returns errors if job before_script parameter is not an array of strings" do
config = YAML.dump({ rspec: { script: "test", before_script: [10, "test"] } }) config = YAML.dump({ rspec: { script: "test", before_script: [10, "test"] } })
expect do expect do
Gitlab::Ci::YamlProcessor.new(config, path) Gitlab::Ci::YamlProcessor.new(config)
end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:before_script config should be an array of strings") end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:before_script config should be an array of strings")
end end
it "returns errors if after_script parameter is invalid" do it "returns errors if after_script parameter is invalid" do
config = YAML.dump({ after_script: "bundle update", rspec: { script: "test" } }) config = YAML.dump({ after_script: "bundle update", rspec: { script: "test" } })
expect do expect do
Gitlab::Ci::YamlProcessor.new(config, path) Gitlab::Ci::YamlProcessor.new(config)
end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "after_script config should be an array of strings") end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "after_script config should be an array of strings")
end end
it "returns errors if job after_script parameter is not an array of strings" do it "returns errors if job after_script parameter is not an array of strings" do
config = YAML.dump({ rspec: { script: "test", after_script: [10, "test"] } }) config = YAML.dump({ rspec: { script: "test", after_script: [10, "test"] } })
expect do expect do
Gitlab::Ci::YamlProcessor.new(config, path) Gitlab::Ci::YamlProcessor.new(config)
end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:after_script config should be an array of strings") end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:after_script config should be an array of strings")
end end
it "returns errors if image parameter is invalid" do it "returns errors if image parameter is invalid" do
config = YAML.dump({ image: ["test"], rspec: { script: "test" } }) config = YAML.dump({ image: ["test"], rspec: { script: "test" } })
expect do expect do
Gitlab::Ci::YamlProcessor.new(config, path) Gitlab::Ci::YamlProcessor.new(config)
end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "image config should be a hash or a string") end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "image config should be a hash or a string")
end end
it "returns errors if job name is blank" do it "returns errors if job name is blank" do
config = YAML.dump({ '' => { script: "test" } }) config = YAML.dump({ '' => { script: "test" } })
expect do expect do
Gitlab::Ci::YamlProcessor.new(config, path) Gitlab::Ci::YamlProcessor.new(config)
end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:job name can't be blank") end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:job name can't be blank")
end end
it "returns errors if job name is non-string" do it "returns errors if job name is non-string" do
config = YAML.dump({ 10 => { script: "test" } }) config = YAML.dump({ 10 => { script: "test" } })
expect do expect do
Gitlab::Ci::YamlProcessor.new(config, path) Gitlab::Ci::YamlProcessor.new(config)
end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:10 name should be a symbol") end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:10 name should be a symbol")
end end
it "returns errors if job image parameter is invalid" do it "returns errors if job image parameter is invalid" do
config = YAML.dump({ rspec: { script: "test", image: ["test"] } }) config = YAML.dump({ rspec: { script: "test", image: ["test"] } })
expect do expect do
Gitlab::Ci::YamlProcessor.new(config, path) Gitlab::Ci::YamlProcessor.new(config)
end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:image config should be a hash or a string") end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:image config should be a hash or a string")
end end
it "returns errors if services parameter is not an array" do it "returns errors if services parameter is not an array" do
config = YAML.dump({ services: "test", rspec: { script: "test" } }) config = YAML.dump({ services: "test", rspec: { script: "test" } })
expect do expect do
Gitlab::Ci::YamlProcessor.new(config, path) Gitlab::Ci::YamlProcessor.new(config)
end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "services config should be a array") end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "services config should be a array")
end end
it "returns errors if services parameter is not an array of strings" do it "returns errors if services parameter is not an array of strings" do
config = YAML.dump({ services: [10, "test"], rspec: { script: "test" } }) config = YAML.dump({ services: [10, "test"], rspec: { script: "test" } })
expect do expect do
Gitlab::Ci::YamlProcessor.new(config, path) Gitlab::Ci::YamlProcessor.new(config)
end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "service config should be a hash or a string") end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "service config should be a hash or a string")
end end
it "returns errors if job services parameter is not an array" do it "returns errors if job services parameter is not an array" do
config = YAML.dump({ rspec: { script: "test", services: "test" } }) config = YAML.dump({ rspec: { script: "test", services: "test" } })
expect do expect do
Gitlab::Ci::YamlProcessor.new(config, path) Gitlab::Ci::YamlProcessor.new(config)
end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:services config should be a array") end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:services config should be a array")
end end
it "returns errors if job services parameter is not an array of strings" do it "returns errors if job services parameter is not an array of strings" do
config = YAML.dump({ rspec: { script: "test", services: [10, "test"] } }) config = YAML.dump({ rspec: { script: "test", services: [10, "test"] } })
expect do expect do
Gitlab::Ci::YamlProcessor.new(config, path) Gitlab::Ci::YamlProcessor.new(config)
end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "service config should be a hash or a string") end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "service config should be a hash or a string")
end end
it "returns error if job configuration is invalid" do it "returns error if job configuration is invalid" do
config = YAML.dump({ extra: "bundle update" }) config = YAML.dump({ extra: "bundle update" })
expect do expect do
Gitlab::Ci::YamlProcessor.new(config, path) Gitlab::Ci::YamlProcessor.new(config)
end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:extra config should be a hash") end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:extra config should be a hash")
end end
it "returns errors if services configuration is not correct" do it "returns errors if services configuration is not correct" do
config = YAML.dump({ extra: { script: 'rspec', services: "test" } }) config = YAML.dump({ extra: { script: 'rspec', services: "test" } })
expect do expect do
Gitlab::Ci::YamlProcessor.new(config, path) Gitlab::Ci::YamlProcessor.new(config)
end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:extra:services config should be a array") end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:extra:services config should be a array")
end end
it "returns errors if there are no jobs defined" do it "returns errors if there are no jobs defined" do
config = YAML.dump({ before_script: ["bundle update"] }) config = YAML.dump({ before_script: ["bundle update"] })
expect do expect do
Gitlab::Ci::YamlProcessor.new(config, path) Gitlab::Ci::YamlProcessor.new(config)
end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs config should contain at least one visible job") end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs config should contain at least one visible job")
end end
it "returns errors if there are no visible jobs defined" do it "returns errors if there are no visible jobs defined" do
config = YAML.dump({ before_script: ["bundle update"], '.hidden'.to_sym => { script: 'ls' } }) config = YAML.dump({ before_script: ["bundle update"], '.hidden'.to_sym => { script: 'ls' } })
expect do expect do
Gitlab::Ci::YamlProcessor.new(config, path) Gitlab::Ci::YamlProcessor.new(config)
end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs config should contain at least one visible job") end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs config should contain at least one visible job")
end end
it "returns errors if job allow_failure parameter is not an boolean" do it "returns errors if job allow_failure parameter is not an boolean" do
config = YAML.dump({ rspec: { script: "test", allow_failure: "string" } }) config = YAML.dump({ rspec: { script: "test", allow_failure: "string" } })
expect do expect do
Gitlab::Ci::YamlProcessor.new(config, path) Gitlab::Ci::YamlProcessor.new(config)
end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec allow failure should be a boolean value") end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec allow failure should be a boolean value")
end end
it "returns errors if job stage is not a string" do it "returns errors if job stage is not a string" do
config = YAML.dump({ rspec: { script: "test", type: 1 } }) config = YAML.dump({ rspec: { script: "test", type: 1 } })
expect do expect do
Gitlab::Ci::YamlProcessor.new(config, path) Gitlab::Ci::YamlProcessor.new(config)
end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:type config should be a string") end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:type config should be a string")
end end
it "returns errors if job stage is not a pre-defined stage" do it "returns errors if job stage is not a pre-defined stage" do
config = YAML.dump({ rspec: { script: "test", type: "acceptance" } }) config = YAML.dump({ rspec: { script: "test", type: "acceptance" } })
expect do expect do
Gitlab::Ci::YamlProcessor.new(config, path) Gitlab::Ci::YamlProcessor.new(config)
end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "rspec job: stage parameter should be build, test, deploy") end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "rspec job: stage parameter should be build, test, deploy")
end end
it "returns errors if job stage is not a defined stage" do it "returns errors if job stage is not a defined stage" do
config = YAML.dump({ types: %w(build test), rspec: { script: "test", type: "acceptance" } }) config = YAML.dump({ types: %w(build test), rspec: { script: "test", type: "acceptance" } })
expect do expect do
Gitlab::Ci::YamlProcessor.new(config, path) Gitlab::Ci::YamlProcessor.new(config)
end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "rspec job: stage parameter should be build, test") end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "rspec job: stage parameter should be build, test")
end end
it "returns errors if stages is not an array" do it "returns errors if stages is not an array" do
config = YAML.dump({ stages: "test", rspec: { script: "test" } }) config = YAML.dump({ stages: "test", rspec: { script: "test" } })
expect do expect do
Gitlab::Ci::YamlProcessor.new(config, path) Gitlab::Ci::YamlProcessor.new(config)
end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "stages config should be an array of strings") end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "stages config should be an array of strings")
end end
it "returns errors if stages is not an array of strings" do it "returns errors if stages is not an array of strings" do
config = YAML.dump({ stages: [true, "test"], rspec: { script: "test" } }) config = YAML.dump({ stages: [true, "test"], rspec: { script: "test" } })
expect do expect do
Gitlab::Ci::YamlProcessor.new(config, path) Gitlab::Ci::YamlProcessor.new(config)
end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "stages config should be an array of strings") end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "stages config should be an array of strings")
end end
it "returns errors if variables is not a map" do it "returns errors if variables is not a map" do
config = YAML.dump({ variables: "test", rspec: { script: "test" } }) config = YAML.dump({ variables: "test", rspec: { script: "test" } })
expect do expect do
Gitlab::Ci::YamlProcessor.new(config, path) Gitlab::Ci::YamlProcessor.new(config)
end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "variables config should be a hash of key value pairs") end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "variables config should be a hash of key value pairs")
end end
it "returns errors if variables is not a map of key-value strings" do it "returns errors if variables is not a map of key-value strings" do
config = YAML.dump({ variables: { test: false }, rspec: { script: "test" } }) config = YAML.dump({ variables: { test: false }, rspec: { script: "test" } })
expect do expect do
Gitlab::Ci::YamlProcessor.new(config, path) Gitlab::Ci::YamlProcessor.new(config)
end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "variables config should be a hash of key value pairs") end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "variables config should be a hash of key value pairs")
end end
it "returns errors if job when is not on_success, on_failure or always" do it "returns errors if job when is not on_success, on_failure or always" do
config = YAML.dump({ rspec: { script: "test", when: 1 } }) config = YAML.dump({ rspec: { script: "test", when: 1 } })
expect do expect do
Gitlab::Ci::YamlProcessor.new(config, path) Gitlab::Ci::YamlProcessor.new(config)
end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec when should be on_success, on_failure, always or manual") end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec when should be on_success, on_failure, always or manual")
end end
...@@ -1694,6 +1707,10 @@ EOT ...@@ -1694,6 +1707,10 @@ EOT
end end
end end
end end
def pipeline(**attributes)
build_stubbed(:ci_empty_pipeline, **attributes)
end
end end
end end
end end
...@@ -26,6 +26,7 @@ describe Ci::Pipeline, :mailer do ...@@ -26,6 +26,7 @@ describe Ci::Pipeline, :mailer do
it { is_expected.to respond_to :git_author_name } it { is_expected.to respond_to :git_author_name }
it { is_expected.to respond_to :git_author_email } it { is_expected.to respond_to :git_author_email }
it { is_expected.to respond_to :short_sha } it { is_expected.to respond_to :short_sha }
it { is_expected.to delegate_method(:full_path).to(:project).with_prefix }
describe '#source' do describe '#source' do
context 'when creating new pipeline' do context 'when creating new pipeline' do
......
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