Move policy related specs our of YAML processor tests
This commit is contained in:
parent
c7809d097a
commit
0e51842dca
7 changed files with 541 additions and 587 deletions
|
@ -15,8 +15,6 @@ module Gitlab
|
||||||
@except = attributes.delete(:except)
|
@except = attributes.delete(:except)
|
||||||
end
|
end
|
||||||
|
|
||||||
# TODO find a different solution
|
|
||||||
#
|
|
||||||
def user=(current_user)
|
def user=(current_user)
|
||||||
@attributes.merge!(user: current_user)
|
@attributes.merge!(user: current_user)
|
||||||
end
|
end
|
||||||
|
@ -43,10 +41,12 @@ module Gitlab
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_resource
|
def to_resource
|
||||||
|
strong_memoize(:resource) do
|
||||||
::Ci::Build.new(attributes)
|
::Ci::Build.new(attributes)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,7 +3,7 @@ module Gitlab
|
||||||
module Pipeline
|
module Pipeline
|
||||||
module Seed
|
module Seed
|
||||||
class Stage < Seed::Base
|
class Stage < Seed::Base
|
||||||
attr_reader :pipeline, :seeds
|
include Gitlab::Utils::StrongMemoize
|
||||||
|
|
||||||
delegate :size, to: :seeds
|
delegate :size, to: :seeds
|
||||||
delegate :dig, to: :seeds
|
delegate :dig, to: :seeds
|
||||||
|
@ -27,10 +27,16 @@ module Gitlab
|
||||||
project: @pipeline.project }
|
project: @pipeline.project }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def seeds
|
||||||
|
strong_memoize(:seeds_included) do
|
||||||
|
@seeds.select(&:included?)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# TODO specs
|
# TODO specs
|
||||||
#
|
#
|
||||||
def included?
|
def included?
|
||||||
@seeds.any?(&:included?)
|
seeds.any?
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_resource
|
def to_resource
|
||||||
|
|
|
@ -129,4 +129,6 @@ describe Gitlab::Ci::Pipeline::Chain::Populate do
|
||||||
expect { step.perform! }.to raise_error(described_class::PopulateError)
|
expect { step.perform! }.to raise_error(described_class::PopulateError)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
pending 'populating pipeline according to policies'
|
||||||
end
|
end
|
||||||
|
|
242
spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
Normal file
242
spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
Normal file
|
@ -0,0 +1,242 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe Gitlab::Ci::Pipeline::Seed::Build do
|
||||||
|
let(:pipeline) { create(:ci_empty_pipeline) }
|
||||||
|
|
||||||
|
let(:attributes) do
|
||||||
|
{ name: 'rspec',
|
||||||
|
ref: 'master',
|
||||||
|
commands: 'rspec' }
|
||||||
|
end
|
||||||
|
|
||||||
|
subject do
|
||||||
|
described_class.new(pipeline, attributes)
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#attributes' do
|
||||||
|
it 'returns hash attributes of a build' do
|
||||||
|
expect(subject.attributes).to be_a Hash
|
||||||
|
expect(subject.attributes)
|
||||||
|
.to include(:name, :project, :ref, :commands)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#user=' do
|
||||||
|
let(:user) { build(:user) }
|
||||||
|
|
||||||
|
it 'assignes user to a build' do
|
||||||
|
subject.user = user
|
||||||
|
|
||||||
|
expect(subject.attributes).to include(user: user)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#to_resource' do
|
||||||
|
it 'returns a valid build resource' do
|
||||||
|
expect(subject.to_resource).to be_a(::Ci::Build)
|
||||||
|
expect(subject.to_resource).to be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'memoizes a resource object' do
|
||||||
|
build = subject.to_resource
|
||||||
|
|
||||||
|
expect(build.object_id).to eq subject.to_resource.object_id
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'can not be persisted without explicit assignment' do
|
||||||
|
build = subject.to_resource
|
||||||
|
|
||||||
|
pipeline.save!
|
||||||
|
|
||||||
|
expect(build).not_to be_persisted
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'applying only/except policies' do
|
||||||
|
context 'when no branch policy is specified' do
|
||||||
|
let(:attributes) { { name: 'rspec' } }
|
||||||
|
|
||||||
|
it { is_expected.to be_included }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when branch policy does not match' do
|
||||||
|
context 'when using only' do
|
||||||
|
let(:attributes) { { name: 'rspec', only: { refs: ['deploy'] } } }
|
||||||
|
|
||||||
|
it { is_expected.not_to be_included }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when using except' do
|
||||||
|
let(:attributes) { { name: 'rspec', except: { refs: ['deploy'] } } }
|
||||||
|
|
||||||
|
it { is_expected.to be_included }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when branch regexp policy does not match' do
|
||||||
|
context 'when using only' do
|
||||||
|
let(:attributes) { { name: 'rspec', only: { refs: ['/^deploy$/'] } } }
|
||||||
|
|
||||||
|
it { is_expected.not_to be_included }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when using except' do
|
||||||
|
let(:attributes) { { name: 'rspec', except: { refs: ['/^deploy$/'] } } }
|
||||||
|
|
||||||
|
it { is_expected.to be_included }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when branch policy matches' do
|
||||||
|
context 'when using only' do
|
||||||
|
let(:attributes) { { name: 'rspec', only: { refs: ['deploy', 'master'] } } }
|
||||||
|
|
||||||
|
it { is_expected.to be_included }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when using except' do
|
||||||
|
let(:attributes) { { name: 'rspec', except: { refs: ['deploy', 'master'] } } }
|
||||||
|
|
||||||
|
it { is_expected.not_to be_included }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when keyword policy matches' do
|
||||||
|
context 'when using only' do
|
||||||
|
let(:attributes) { { name: 'rspec', only: { refs: ['branches'] } } }
|
||||||
|
|
||||||
|
it { is_expected.to be_included }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when using except' do
|
||||||
|
let(:attributes) { { name: 'rspec', except: { refs: ['branches'] } } }
|
||||||
|
|
||||||
|
it { is_expected.not_to be_included }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when keyword policy does not match' do
|
||||||
|
context 'when using only' do
|
||||||
|
let(:attributes) { { name: 'rspec', only: { refs: ['tags'] } } }
|
||||||
|
|
||||||
|
it { is_expected.not_to be_included }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when using except' do
|
||||||
|
let(:attributes) { { name: 'rspec', except: { refs: ['tags'] } } }
|
||||||
|
|
||||||
|
it { is_expected.to be_included }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when keywords and pipeline source policy matches' do
|
||||||
|
possibilities = [['pushes', 'push'],
|
||||||
|
['web', 'web'],
|
||||||
|
['triggers', 'trigger'],
|
||||||
|
['schedules', 'schedule'],
|
||||||
|
['api', 'api'],
|
||||||
|
['external', 'external']]
|
||||||
|
|
||||||
|
context 'when using only' do
|
||||||
|
possibilities.each do |keyword, source|
|
||||||
|
context "when using keyword `#{keyword}` and source `#{source}`" do
|
||||||
|
let(:pipeline) do
|
||||||
|
build(:ci_empty_pipeline, ref: 'deploy', tag: false, source: source)
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:attributes) { { name: 'rspec', only: { refs: [keyword] } } }
|
||||||
|
|
||||||
|
it { is_expected.to be_included }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when using except' do
|
||||||
|
possibilities.each do |keyword, source|
|
||||||
|
context "when using keyword `#{keyword}` and source `#{source}`" do
|
||||||
|
let(:pipeline) do
|
||||||
|
build(:ci_empty_pipeline, ref: 'deploy', tag: false, source: source)
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:attributes) { { name: 'rspec', except: { refs: [keyword] } } }
|
||||||
|
|
||||||
|
it { is_expected.not_to be_included }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when keywords and pipeline source does not match' do
|
||||||
|
possibilities = [['pushes', 'web'],
|
||||||
|
['web', 'push'],
|
||||||
|
['triggers', 'schedule'],
|
||||||
|
['schedules', 'external'],
|
||||||
|
['api', 'trigger'],
|
||||||
|
['external', 'api']]
|
||||||
|
|
||||||
|
context 'when using only' do
|
||||||
|
possibilities.each do |keyword, source|
|
||||||
|
context "when using keyword `#{keyword}` and source `#{source}`" do
|
||||||
|
let(:pipeline) do
|
||||||
|
build(:ci_empty_pipeline, ref: 'deploy', tag: false, source: source)
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:attributes) { { name: 'rspec', only: { refs: [keyword] } } }
|
||||||
|
|
||||||
|
it { is_expected.not_to be_included }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when using except' do
|
||||||
|
possibilities.each do |keyword, source|
|
||||||
|
context "when using keyword `#{keyword}` and source `#{source}`" do
|
||||||
|
let(:pipeline) do
|
||||||
|
build(:ci_empty_pipeline, ref: 'deploy', tag: false, source: source)
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:attributes) { { name: 'rspec', except: { refs: [keyword] } } }
|
||||||
|
|
||||||
|
it { is_expected.to be_included }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when repository path matches' do
|
||||||
|
context 'when using only' do
|
||||||
|
let(:attributes) do
|
||||||
|
{ name: 'rspec', only: { refs: ["branches@#{pipeline.project_full_path}"] } }
|
||||||
|
end
|
||||||
|
|
||||||
|
it { is_expected.to be_included }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when using except' do
|
||||||
|
let(:attributes) do
|
||||||
|
{ name: 'rspec', except: { refs: ["branches@#{pipeline.project_full_path}"] } }
|
||||||
|
end
|
||||||
|
|
||||||
|
it { is_expected.not_to be_included }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when repository path does not matches' do
|
||||||
|
context 'when using only' do
|
||||||
|
let(:attributes) do
|
||||||
|
{ name: 'rspec', only: { refs: ['branches@fork'] } }
|
||||||
|
end
|
||||||
|
|
||||||
|
it { is_expected.not_to be_included }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when using except' do
|
||||||
|
let(:attributes) do
|
||||||
|
{ name: 'rspec', except: { refs: ['branches@fork'] } }
|
||||||
|
end
|
||||||
|
|
||||||
|
it { is_expected.to be_included }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -6,7 +6,9 @@ describe Gitlab::Ci::Pipeline::Seed::Stage do
|
||||||
let(:attributes) do
|
let(:attributes) do
|
||||||
{ name: 'test',
|
{ name: 'test',
|
||||||
index: 0,
|
index: 0,
|
||||||
builds: [{ name: 'rspec' }, { name: 'spinach' }] }
|
builds: [{ name: 'rspec' },
|
||||||
|
{ name: 'spinach' },
|
||||||
|
{ name: 'deploy', only: { refs: ['feature'] } }] }
|
||||||
end
|
end
|
||||||
|
|
||||||
subject do
|
subject do
|
||||||
|
@ -27,7 +29,11 @@ describe Gitlab::Ci::Pipeline::Seed::Stage do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#seeds' do
|
describe '#seeds' do
|
||||||
it 'returns hash attributes of all builds' do
|
it 'returns build seeds' do
|
||||||
|
expect(subject.seeds).to all(be_a Gitlab::Ci::Pipeline::Seed::Build)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns build seeds including valid attributes' do
|
||||||
expect(subject.seeds.size).to eq 2
|
expect(subject.seeds.size).to eq 2
|
||||||
expect(subject.seeds.map(&:attributes)).to all(include(ref: 'master'))
|
expect(subject.seeds.map(&:attributes)).to all(include(ref: 'master'))
|
||||||
expect(subject.seeds.map(&:attributes)).to all(include(tag: false))
|
expect(subject.seeds.map(&:attributes)).to all(include(tag: false))
|
||||||
|
@ -55,6 +61,16 @@ describe Gitlab::Ci::Pipeline::Seed::Stage do
|
||||||
expect(subject.seeds.map(&:attributes)).to all(include(protected: false))
|
expect(subject.seeds.map(&:attributes)).to all(include(protected: false))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'filters seeds using only/except policies' do
|
||||||
|
expect(subject.seeds.map(&:attributes)).to satisfy do |seeds|
|
||||||
|
seeds.any? { |hash| hash.fetch(:name) == 'rspec' }
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(subject.seeds.map(&:attributes)).not_to satisfy do |seeds|
|
||||||
|
seeds.any? { |hash| hash.fetch(:name) == 'deploy' }
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#user=' do
|
describe '#user=' do
|
||||||
|
|
|
@ -18,6 +18,34 @@ module Gitlab
|
||||||
describe '#build_attributes' do
|
describe '#build_attributes' do
|
||||||
subject { described_class.new(config).build_attributes(:rspec) }
|
subject { described_class.new(config).build_attributes(:rspec) }
|
||||||
|
|
||||||
|
describe 'attributes list' do
|
||||||
|
let(:config) do
|
||||||
|
YAML.dump(
|
||||||
|
before_script: ['pwd'],
|
||||||
|
rspec: { script: 'rspec' }
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns valid build attributes' do
|
||||||
|
expect(subject).to eq({
|
||||||
|
stage: "test",
|
||||||
|
stage_idx: 1,
|
||||||
|
name: "rspec",
|
||||||
|
commands: "pwd\nrspec",
|
||||||
|
coverage_regex: nil,
|
||||||
|
tag_list: [],
|
||||||
|
options: {
|
||||||
|
before_script: ["pwd"],
|
||||||
|
script: ["rspec"]
|
||||||
|
},
|
||||||
|
allow_failure: false,
|
||||||
|
when: "on_success",
|
||||||
|
environment: nil,
|
||||||
|
yaml_variables: []
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe 'coverage entry' do
|
describe 'coverage entry' do
|
||||||
describe 'code coverage regexp' do
|
describe 'code coverage regexp' do
|
||||||
let(:config) do
|
let(:config) do
|
||||||
|
@ -105,297 +133,8 @@ module Gitlab
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#stage_seeds' do
|
describe 'only / except policies validations' do
|
||||||
context 'when no refs policy is specified' do
|
context 'when `only` has an invalid value' do
|
||||||
let(:config) do
|
|
||||||
YAML.dump(production: { stage: 'deploy', script: 'cap prod' },
|
|
||||||
rspec: { stage: 'test', script: 'rspec' },
|
|
||||||
spinach: { stage: 'test', script: 'spinach' })
|
|
||||||
end
|
|
||||||
|
|
||||||
let(:pipeline) { create(:ci_empty_pipeline) }
|
|
||||||
|
|
||||||
it 'correctly fabricates a stage seeds object' do
|
|
||||||
seeds = subject.stage_seeds(pipeline)
|
|
||||||
|
|
||||||
expect(seeds.size).to eq 2
|
|
||||||
expect(seeds.first.attributes[:name]).to eq 'test'
|
|
||||||
expect(seeds.second.attributes[:name]).to eq 'deploy'
|
|
||||||
expect(seeds.dig(0, 0, :name)).to eq 'rspec'
|
|
||||||
expect(seeds.dig(0, 1, :name)).to eq 'spinach'
|
|
||||||
expect(seeds.dig(1, 0, :name)).to eq 'production'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when refs policy is specified' do
|
|
||||||
let(:config) do
|
|
||||||
YAML.dump(production: { stage: 'deploy', script: 'cap prod', only: ['master'] },
|
|
||||||
spinach: { stage: 'test', script: 'spinach', only: ['tags'] })
|
|
||||||
end
|
|
||||||
|
|
||||||
let(:pipeline) do
|
|
||||||
create(:ci_empty_pipeline, ref: 'feature', tag: true)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns stage seeds only assigned to master to master' do
|
|
||||||
seeds = subject.stage_seeds(pipeline)
|
|
||||||
|
|
||||||
expect(seeds.size).to eq 1
|
|
||||||
expect(seeds.first.attributes[:name]).to eq 'test'
|
|
||||||
expect(seeds.dig(0, 0, :name)).to eq 'spinach'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when source policy is specified' do
|
|
||||||
let(:config) do
|
|
||||||
YAML.dump(production: { stage: 'deploy', script: 'cap prod', only: ['triggers'] },
|
|
||||||
spinach: { stage: 'test', script: 'spinach', only: ['schedules'] })
|
|
||||||
end
|
|
||||||
|
|
||||||
let(:pipeline) do
|
|
||||||
create(:ci_empty_pipeline, source: :schedule)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns stage seeds only assigned to schedules' do
|
|
||||||
seeds = subject.stage_seeds(pipeline)
|
|
||||||
|
|
||||||
expect(seeds.size).to eq 1
|
|
||||||
expect(seeds.first.attributes[:name]).to eq 'test'
|
|
||||||
expect(seeds.dig(0, 0, :name)).to eq 'spinach'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when kubernetes policy is specified' do
|
|
||||||
let(:config) do
|
|
||||||
YAML.dump(
|
|
||||||
spinach: { stage: 'test', script: 'spinach' },
|
|
||||||
production: {
|
|
||||||
stage: 'deploy',
|
|
||||||
script: 'cap',
|
|
||||||
only: { kubernetes: 'active' }
|
|
||||||
}
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when kubernetes is active' do
|
|
||||||
shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do
|
|
||||||
it 'returns seeds for kubernetes dependent job' do
|
|
||||||
seeds = subject.stage_seeds(pipeline)
|
|
||||||
|
|
||||||
expect(seeds.size).to eq 2
|
|
||||||
expect(seeds.dig(0, 0, :name)).to eq 'spinach'
|
|
||||||
expect(seeds.dig(1, 0, :name)).to eq 'production'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when user configured kubernetes from Integration > Kubernetes' do
|
|
||||||
let(:project) { create(:kubernetes_project) }
|
|
||||||
let(:pipeline) { create(:ci_empty_pipeline, project: project) }
|
|
||||||
|
|
||||||
it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when user configured kubernetes from CI/CD > Clusters' do
|
|
||||||
let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
|
|
||||||
let(:project) { cluster.project }
|
|
||||||
let(:pipeline) { create(:ci_empty_pipeline, project: project) }
|
|
||||||
|
|
||||||
it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when kubernetes is not active' do
|
|
||||||
it 'does not return seeds for kubernetes dependent job' do
|
|
||||||
seeds = subject.stage_seeds(pipeline)
|
|
||||||
|
|
||||||
expect(seeds.size).to eq 1
|
|
||||||
expect(seeds.dig(0, 0, :name)).to eq 'spinach'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#pipeline_stage_builds" do
|
|
||||||
let(:type) { 'test' }
|
|
||||||
|
|
||||||
it "returns builds if no branch specified" do
|
|
||||||
config = YAML.dump({
|
|
||||||
before_script: ["pwd"],
|
|
||||||
rspec: { script: "rspec" }
|
|
||||||
})
|
|
||||||
|
|
||||||
config_processor = Gitlab::Ci::YamlProcessor.new(config)
|
|
||||||
|
|
||||||
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "master")).size).to eq(1)
|
|
||||||
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "master")).first).to eq({
|
|
||||||
stage: "test",
|
|
||||||
stage_idx: 1,
|
|
||||||
name: "rspec",
|
|
||||||
commands: "pwd\nrspec",
|
|
||||||
coverage_regex: nil,
|
|
||||||
tag_list: [],
|
|
||||||
options: {
|
|
||||||
before_script: ["pwd"],
|
|
||||||
script: ["rspec"]
|
|
||||||
},
|
|
||||||
allow_failure: false,
|
|
||||||
when: "on_success",
|
|
||||||
environment: nil,
|
|
||||||
yaml_variables: []
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'only' do
|
|
||||||
it "does not return builds if only has another branch" do
|
|
||||||
config = YAML.dump({
|
|
||||||
before_script: ["pwd"],
|
|
||||||
rspec: { script: "rspec", only: ["deploy"] }
|
|
||||||
})
|
|
||||||
|
|
||||||
config_processor = Gitlab::Ci::YamlProcessor.new(config)
|
|
||||||
|
|
||||||
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "master")).size).to eq(0)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "does not return builds if only has regexp with another branch" do
|
|
||||||
config = YAML.dump({
|
|
||||||
before_script: ["pwd"],
|
|
||||||
rspec: { script: "rspec", only: ["/^deploy$/"] }
|
|
||||||
})
|
|
||||||
|
|
||||||
config_processor = Gitlab::Ci::YamlProcessor.new(config)
|
|
||||||
|
|
||||||
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "master")).size).to eq(0)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns builds if only has specified this branch" do
|
|
||||||
config = YAML.dump({
|
|
||||||
before_script: ["pwd"],
|
|
||||||
rspec: { script: "rspec", only: ["master"] }
|
|
||||||
})
|
|
||||||
|
|
||||||
config_processor = Gitlab::Ci::YamlProcessor.new(config)
|
|
||||||
|
|
||||||
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "master")).size).to eq(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns builds if only has a list of branches including specified" do
|
|
||||||
config = YAML.dump({
|
|
||||||
before_script: ["pwd"],
|
|
||||||
rspec: { script: "rspec", type: type, only: %w(master deploy) }
|
|
||||||
})
|
|
||||||
|
|
||||||
config_processor = Gitlab::Ci::YamlProcessor.new(config)
|
|
||||||
|
|
||||||
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "deploy")).size).to eq(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns builds if only has a branches keyword specified" do
|
|
||||||
config = YAML.dump({
|
|
||||||
before_script: ["pwd"],
|
|
||||||
rspec: { script: "rspec", type: type, only: ["branches"] }
|
|
||||||
})
|
|
||||||
|
|
||||||
config_processor = Gitlab::Ci::YamlProcessor.new(config)
|
|
||||||
|
|
||||||
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "deploy")).size).to eq(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "does not return builds if only has a tags keyword" do
|
|
||||||
config = YAML.dump({
|
|
||||||
before_script: ["pwd"],
|
|
||||||
rspec: { script: "rspec", type: type, only: ["tags"] }
|
|
||||||
})
|
|
||||||
|
|
||||||
config_processor = Gitlab::Ci::YamlProcessor.new(config)
|
|
||||||
|
|
||||||
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "deploy")).size).to eq(0)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns builds if only has special keywords specified and source matches" do
|
|
||||||
possibilities = [{ keyword: 'pushes', source: 'push' },
|
|
||||||
{ keyword: 'web', source: 'web' },
|
|
||||||
{ keyword: 'triggers', source: 'trigger' },
|
|
||||||
{ keyword: 'schedules', source: 'schedule' },
|
|
||||||
{ keyword: 'api', source: 'api' },
|
|
||||||
{ keyword: 'external', source: 'external' }]
|
|
||||||
|
|
||||||
possibilities.each do |possibility|
|
|
||||||
config = YAML.dump({
|
|
||||||
before_script: ["pwd"],
|
|
||||||
rspec: { script: "rspec", type: type, only: [possibility[:keyword]] }
|
|
||||||
})
|
|
||||||
|
|
||||||
config_processor = Gitlab::Ci::YamlProcessor.new(config)
|
|
||||||
|
|
||||||
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: 'deploy', tag: false, source: possibility[:source])).size).to eq(1)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "does not return builds if only has special keywords specified and source doesn't match" do
|
|
||||||
possibilities = [{ keyword: 'pushes', source: 'web' },
|
|
||||||
{ keyword: 'web', source: 'push' },
|
|
||||||
{ keyword: 'triggers', source: 'schedule' },
|
|
||||||
{ keyword: 'schedules', source: 'external' },
|
|
||||||
{ keyword: 'api', source: 'trigger' },
|
|
||||||
{ keyword: 'external', source: 'api' }]
|
|
||||||
|
|
||||||
possibilities.each do |possibility|
|
|
||||||
config = YAML.dump({
|
|
||||||
before_script: ["pwd"],
|
|
||||||
rspec: { script: "rspec", type: type, only: [possibility[:keyword]] }
|
|
||||||
})
|
|
||||||
|
|
||||||
config_processor = Gitlab::Ci::YamlProcessor.new(config)
|
|
||||||
|
|
||||||
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: 'deploy', tag: false, source: possibility[:source])).size).to eq(0)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns builds if only has current repository path" do
|
|
||||||
seed_pipeline = pipeline(ref: 'deploy')
|
|
||||||
|
|
||||||
config = YAML.dump({
|
|
||||||
before_script: ["pwd"],
|
|
||||||
rspec: {
|
|
||||||
script: "rspec",
|
|
||||||
type: type,
|
|
||||||
only: ["branches@#{seed_pipeline.project_full_path}"]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
config_processor = Gitlab::Ci::YamlProcessor.new(config)
|
|
||||||
|
|
||||||
expect(config_processor.pipeline_stage_builds(type, seed_pipeline).size).to eq(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "does not return builds if only has different repository path" do
|
|
||||||
config = YAML.dump({
|
|
||||||
before_script: ["pwd"],
|
|
||||||
rspec: { script: "rspec", type: type, only: ["branches@fork"] }
|
|
||||||
})
|
|
||||||
|
|
||||||
config_processor = Gitlab::Ci::YamlProcessor.new(config)
|
|
||||||
|
|
||||||
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "deploy")).size).to eq(0)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns build only for specified type" do
|
|
||||||
config = YAML.dump({
|
|
||||||
before_script: ["pwd"],
|
|
||||||
rspec: { script: "rspec", type: "test", only: %w(master deploy) },
|
|
||||||
staging: { script: "deploy", type: "deploy", only: %w(master deploy) },
|
|
||||||
production: { script: "deploy", type: "deploy", only: ["master@path", "deploy"] }
|
|
||||||
})
|
|
||||||
|
|
||||||
config_processor = Gitlab::Ci::YamlProcessor.new(config)
|
|
||||||
|
|
||||||
expect(config_processor.pipeline_stage_builds("deploy", pipeline(ref: "deploy")).size).to eq(2)
|
|
||||||
expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "deploy")).size).to eq(1)
|
|
||||||
expect(config_processor.pipeline_stage_builds("deploy", pipeline(ref: "master")).size).to eq(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'for invalid value' do
|
|
||||||
let(:config) { { rspec: { script: "rspec", type: "test", only: only } } }
|
let(:config) { { rspec: { script: "rspec", type: "test", only: only } } }
|
||||||
let(:processor) { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)) }
|
let(:processor) { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)) }
|
||||||
|
|
||||||
|
@ -426,163 +165,8 @@ module Gitlab
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
describe 'except' do
|
context 'when `except` has an invalid value' do
|
||||||
it "returns builds if except has another branch" do
|
|
||||||
config = YAML.dump({
|
|
||||||
before_script: ["pwd"],
|
|
||||||
rspec: { script: "rspec", except: ["deploy"] }
|
|
||||||
})
|
|
||||||
|
|
||||||
config_processor = Gitlab::Ci::YamlProcessor.new(config)
|
|
||||||
|
|
||||||
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "master")).size).to eq(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns builds if except has regexp with another branch" do
|
|
||||||
config = YAML.dump({
|
|
||||||
before_script: ["pwd"],
|
|
||||||
rspec: { script: "rspec", except: ["/^deploy$/"] }
|
|
||||||
})
|
|
||||||
|
|
||||||
config_processor = Gitlab::Ci::YamlProcessor.new(config)
|
|
||||||
|
|
||||||
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "master")).size).to eq(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "does not return builds if except has specified this branch" do
|
|
||||||
config = YAML.dump({
|
|
||||||
before_script: ["pwd"],
|
|
||||||
rspec: { script: "rspec", except: ["master"] }
|
|
||||||
})
|
|
||||||
|
|
||||||
config_processor = Gitlab::Ci::YamlProcessor.new(config)
|
|
||||||
|
|
||||||
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "master")).size).to eq(0)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "does not return builds if except has a list of branches including specified" do
|
|
||||||
config = YAML.dump({
|
|
||||||
before_script: ["pwd"],
|
|
||||||
rspec: { script: "rspec", type: type, except: %w(master deploy) }
|
|
||||||
})
|
|
||||||
|
|
||||||
config_processor = Gitlab::Ci::YamlProcessor.new(config)
|
|
||||||
|
|
||||||
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "deploy")).size).to eq(0)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "does not return builds if except has a branches keyword specified" do
|
|
||||||
config = YAML.dump({
|
|
||||||
before_script: ["pwd"],
|
|
||||||
rspec: { script: "rspec", type: type, except: ["branches"] }
|
|
||||||
})
|
|
||||||
|
|
||||||
config_processor = Gitlab::Ci::YamlProcessor.new(config)
|
|
||||||
|
|
||||||
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "deploy")).size).to eq(0)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns builds if except has a tags keyword" do
|
|
||||||
config = YAML.dump({
|
|
||||||
before_script: ["pwd"],
|
|
||||||
rspec: { script: "rspec", type: type, except: ["tags"] }
|
|
||||||
})
|
|
||||||
|
|
||||||
config_processor = Gitlab::Ci::YamlProcessor.new(config)
|
|
||||||
|
|
||||||
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "deploy")).size).to eq(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "does not return builds if except has special keywords specified and source matches" do
|
|
||||||
possibilities = [{ keyword: 'pushes', source: 'push' },
|
|
||||||
{ keyword: 'web', source: 'web' },
|
|
||||||
{ keyword: 'triggers', source: 'trigger' },
|
|
||||||
{ keyword: 'schedules', source: 'schedule' },
|
|
||||||
{ keyword: 'api', source: 'api' },
|
|
||||||
{ keyword: 'external', source: 'external' }]
|
|
||||||
|
|
||||||
possibilities.each do |possibility|
|
|
||||||
config = YAML.dump({
|
|
||||||
before_script: ["pwd"],
|
|
||||||
rspec: { script: "rspec", type: type, except: [possibility[:keyword]] }
|
|
||||||
})
|
|
||||||
|
|
||||||
config_processor = Gitlab::Ci::YamlProcessor.new(config)
|
|
||||||
|
|
||||||
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: 'deploy', tag: false, source: possibility[:source])).size).to eq(0)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns builds if except has special keywords specified and source doesn't match" do
|
|
||||||
possibilities = [{ keyword: 'pushes', source: 'web' },
|
|
||||||
{ keyword: 'web', source: 'push' },
|
|
||||||
{ keyword: 'triggers', source: 'schedule' },
|
|
||||||
{ keyword: 'schedules', source: 'external' },
|
|
||||||
{ keyword: 'api', source: 'trigger' },
|
|
||||||
{ keyword: 'external', source: 'api' }]
|
|
||||||
|
|
||||||
possibilities.each do |possibility|
|
|
||||||
config = YAML.dump({
|
|
||||||
before_script: ["pwd"],
|
|
||||||
rspec: { script: "rspec", type: type, except: [possibility[:keyword]] }
|
|
||||||
})
|
|
||||||
|
|
||||||
config_processor = Gitlab::Ci::YamlProcessor.new(config)
|
|
||||||
|
|
||||||
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: 'deploy', tag: false, source: possibility[:source])).size).to eq(1)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "does not return builds if except has current repository path" do
|
|
||||||
seed_pipeline = pipeline(ref: 'deploy')
|
|
||||||
|
|
||||||
config = YAML.dump({
|
|
||||||
before_script: ["pwd"],
|
|
||||||
rspec: {
|
|
||||||
script: "rspec",
|
|
||||||
type: type,
|
|
||||||
except: ["branches@#{seed_pipeline.project_full_path}"]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
config_processor = Gitlab::Ci::YamlProcessor.new(config)
|
|
||||||
|
|
||||||
expect(config_processor.pipeline_stage_builds(type, seed_pipeline).size).to eq(0)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns builds if except has different repository path" do
|
|
||||||
config = YAML.dump({
|
|
||||||
before_script: ["pwd"],
|
|
||||||
rspec: { script: "rspec", type: type, except: ["branches@fork"] }
|
|
||||||
})
|
|
||||||
|
|
||||||
config_processor = Gitlab::Ci::YamlProcessor.new(config)
|
|
||||||
|
|
||||||
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "deploy")).size).to eq(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
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({
|
|
||||||
before_script: ["pwd"],
|
|
||||||
rspec: { script: "rspec", type: "test", except: ["master", "deploy", "test@#{test_pipeline.project_full_path}"] },
|
|
||||||
staging: { script: "deploy", type: "deploy", except: ["master"] },
|
|
||||||
production: { script: "deploy", type: "deploy", except: ["master@#{master_pipeline.project_full_path}"] }
|
|
||||||
})
|
|
||||||
|
|
||||||
config_processor = Gitlab::Ci::YamlProcessor.new(config)
|
|
||||||
|
|
||||||
expect(config_processor.pipeline_stage_builds("deploy", deploy_pipeline).size).to eq(2)
|
|
||||||
expect(config_processor.pipeline_stage_builds("test", test_pipeline).size).to eq(0)
|
|
||||||
expect(config_processor.pipeline_stage_builds("deploy", master_pipeline).size).to eq(0)
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'for invalid value' do
|
|
||||||
let(:config) { { rspec: { script: "rspec", except: except } } }
|
let(:config) { { rspec: { script: "rspec", except: except } } }
|
||||||
let(:processor) { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)) }
|
let(:processor) { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)) }
|
||||||
|
|
||||||
|
@ -614,7 +198,6 @@ module Gitlab
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
describe "Scripts handling" do
|
describe "Scripts handling" do
|
||||||
let(:config_data) { YAML.dump(config) }
|
let(:config_data) { YAML.dump(config) }
|
||||||
|
|
|
@ -215,6 +215,122 @@ describe Ci::Pipeline, :mailer do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'pipeline stages' do
|
describe 'pipeline stages' do
|
||||||
|
describe '#stage_seeds' do
|
||||||
|
let(:pipeline) { build(:ci_pipeline, config: config) }
|
||||||
|
let(:config) { { rspec: { script: 'rake' } } }
|
||||||
|
|
||||||
|
it 'returns preseeded stage seeds object' do
|
||||||
|
expect(pipeline.stage_seeds)
|
||||||
|
.to all(be_a Gitlab::Ci::Pipeline::Seed::Base)
|
||||||
|
expect(pipeline.stage_seeds.count).to eq 1
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when no refs policy is specified' do
|
||||||
|
let(:config) do
|
||||||
|
{ production: { stage: 'deploy', script: 'cap prod' },
|
||||||
|
rspec: { stage: 'test', script: 'rspec' },
|
||||||
|
spinach: { stage: 'test', script: 'spinach' } }
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'correctly fabricates a stage seeds object' do
|
||||||
|
seeds = pipeline.stage_seeds
|
||||||
|
|
||||||
|
expect(seeds.size).to eq 2
|
||||||
|
expect(seeds.first.attributes[:name]).to eq 'test'
|
||||||
|
expect(seeds.second.attributes[:name]).to eq 'deploy'
|
||||||
|
expect(seeds.dig(0, 0, :name)).to eq 'rspec'
|
||||||
|
expect(seeds.dig(0, 1, :name)).to eq 'spinach'
|
||||||
|
expect(seeds.dig(1, 0, :name)).to eq 'production'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when refs policy is specified' do
|
||||||
|
let(:pipeline) do
|
||||||
|
build(:ci_pipeline, ref: 'feature', tag: true, config: config)
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:config) do
|
||||||
|
{ production: { stage: 'deploy', script: 'cap prod', only: ['master'] },
|
||||||
|
spinach: { stage: 'test', script: 'spinach', only: ['tags'] } }
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns stage seeds only assigned to master to master' do
|
||||||
|
seeds = pipeline.stage_seeds
|
||||||
|
|
||||||
|
expect(seeds.size).to eq 1
|
||||||
|
expect(seeds.first.attributes[:name]).to eq 'test'
|
||||||
|
expect(seeds.dig(0, 0, :name)).to eq 'spinach'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when source policy is specified' do
|
||||||
|
let(:pipeline) { build(:ci_pipeline, source: :schedule, config: config) }
|
||||||
|
|
||||||
|
let(:config) do
|
||||||
|
{ production: { stage: 'deploy', script: 'cap prod', only: ['triggers'] },
|
||||||
|
spinach: { stage: 'test', script: 'spinach', only: ['schedules'] } }
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns stage seeds only assigned to schedules' do
|
||||||
|
seeds = pipeline.stage_seeds
|
||||||
|
|
||||||
|
expect(seeds.size).to eq 1
|
||||||
|
expect(seeds.first.attributes[:name]).to eq 'test'
|
||||||
|
expect(seeds.dig(0, 0, :name)).to eq 'spinach'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when kubernetes policy is specified' do
|
||||||
|
let(:config) do
|
||||||
|
{
|
||||||
|
spinach: { stage: 'test', script: 'spinach' },
|
||||||
|
production: {
|
||||||
|
stage: 'deploy',
|
||||||
|
script: 'cap',
|
||||||
|
only: { kubernetes: 'active' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when kubernetes is active' do
|
||||||
|
shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do
|
||||||
|
it 'returns seeds for kubernetes dependent job' do
|
||||||
|
seeds = pipeline.stage_seeds
|
||||||
|
|
||||||
|
expect(seeds.size).to eq 2
|
||||||
|
expect(seeds.dig(0, 0, :name)).to eq 'spinach'
|
||||||
|
expect(seeds.dig(1, 0, :name)).to eq 'production'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when user configured kubernetes from Integration > Kubernetes' do
|
||||||
|
let(:project) { create(:kubernetes_project) }
|
||||||
|
let(:pipeline) { build(:ci_pipeline, project: project, config: config) }
|
||||||
|
|
||||||
|
it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when user configured kubernetes from CI/CD > Clusters' do
|
||||||
|
let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
|
||||||
|
let(:project) { cluster.project }
|
||||||
|
let(:pipeline) { build(:ci_pipeline, project: project, config: config) }
|
||||||
|
|
||||||
|
it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when kubernetes is not active' do
|
||||||
|
it 'does not return seeds for kubernetes dependent job' do
|
||||||
|
seeds = pipeline.stage_seeds
|
||||||
|
|
||||||
|
expect(seeds.size).to eq 1
|
||||||
|
expect(seeds.dig(0, 0, :name)).to eq 'spinach'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'legacy stages' do
|
||||||
before do
|
before do
|
||||||
create(:commit_status, pipeline: pipeline,
|
create(:commit_status, pipeline: pipeline,
|
||||||
stage: 'build',
|
stage: 'build',
|
||||||
|
@ -241,18 +357,6 @@ describe Ci::Pipeline, :mailer do
|
||||||
status: 'success')
|
status: 'success')
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#stage_seeds' do
|
|
||||||
let(:pipeline) do
|
|
||||||
build(:ci_pipeline, config: { rspec: { script: 'rake' } })
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns preseeded stage seeds object' do
|
|
||||||
expect(pipeline.stage_seeds)
|
|
||||||
.to all(be_a Gitlab::Ci::Pipeline::Seed::Base)
|
|
||||||
expect(pipeline.stage_seeds.count).to eq 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#legacy_stages' do
|
describe '#legacy_stages' do
|
||||||
subject { pipeline.legacy_stages }
|
subject { pipeline.legacy_stages }
|
||||||
|
|
||||||
|
@ -347,6 +451,7 @@ describe Ci::Pipeline, :mailer do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe 'state machine' do
|
describe 'state machine' do
|
||||||
let(:current) { Time.now.change(usec: 0) }
|
let(:current) { Time.now.change(usec: 0) }
|
||||||
|
|
Loading…
Reference in a new issue