Commit 47de5032 authored by Fabio Pitino's avatar Fabio Pitino

Extract Seed::Pipeline class from CI stage seeds

This refactoring makes high level pipeline creation
using a higher level object rather than treating lower
level seeds as primitive data structure.
parent 5a0b7fee
......@@ -40,7 +40,7 @@ module EE
end
def seeds_size
@command.stage_seeds.sum(&:size)
@command.pipeline_seed.size
end
end
end
......
......@@ -12,8 +12,7 @@ RSpec.describe EE::Gitlab::Ci::Pipeline::Quota::Size do
let(:pipeline) { build_stubbed(:ci_pipeline, project: project) }
let(:command) do
double(:command,
stage_seeds: [double(:seed_1, size: 1), double(:seed_2, size: 1)])
double(:command, pipeline_seed: double(:pipeline_seed, size: 2))
end
subject { described_class.new(namespace, pipeline, command) }
......
......@@ -13,7 +13,7 @@ RSpec.describe ::Gitlab::Ci::Pipeline::Chain::Limit::Size do
double(:command,
project: project,
current_user: user,
stage_seeds: [double(:seed_1, size: 1), double(:seed_2, size: 1)])
pipeline_seed: double(:seed, size: 1))
end
let(:step) { described_class.new(pipeline, command) }
......@@ -33,7 +33,7 @@ RSpec.describe ::Gitlab::Ci::Pipeline::Chain::Limit::Size do
project: project,
current_user: user,
save_incompleted: true,
stage_seeds: [double(:seed_1, size: 1), double(:seed_2, size: 1)])
pipeline_seed: double(:seed, size: 2))
end
it 'drops the pipeline' do
......@@ -83,7 +83,7 @@ RSpec.describe ::Gitlab::Ci::Pipeline::Chain::Limit::Size do
project: project,
current_user: user,
save_incompleted: false,
stage_seeds: [double(:seed_1, size: 1), double(:seed_2, size: 1)])
pipeline_seed: double(:seed, size: 2))
end
it 'does not drop the pipeline' do
......
......@@ -12,7 +12,7 @@ module Gitlab
:seeds_block, :variables_attributes, :push_options,
:chat_data, :allow_mirror_update, :bridge, :content, :dry_run,
# These attributes are set by Chains during processing:
:config_content, :yaml_processor_result, :stage_seeds
:config_content, :yaml_processor_result, :pipeline_seed
) do
include Gitlab::Utils::StrongMemoize
......
......@@ -10,12 +10,12 @@ module Gitlab
PopulateError = Class.new(StandardError)
def perform!
raise ArgumentError, 'missing stage seeds' unless @command.stage_seeds
raise ArgumentError, 'missing pipeline seed' unless @command.pipeline_seed
##
# Populate pipeline with all stages, and stages with builds.
#
pipeline.stages = @command.stage_seeds.map(&:to_resource)
pipeline.stages = @command.pipeline_seed.stages
if stage_names.empty?
return error('No stages / jobs for this pipeline.')
......
......@@ -29,11 +29,11 @@ module Gitlab
##
# Gather all runtime build/stage errors
#
if stage_seeds_errors
return error(stage_seeds_errors.join("\n"), config_error: true)
if pipeline_seed.errors
return error(pipeline_seed.errors.join("\n"), config_error: true)
end
@command.stage_seeds = stage_seeds
@command.pipeline_seed = pipeline_seed
end
def break?
......@@ -42,24 +42,12 @@ module Gitlab
private
def stage_seeds_errors
stage_seeds.flat_map(&:errors).compact.presence
end
def stage_seeds
strong_memoize(:stage_seeds) do
seeds = stages_attributes.inject([]) do |previous_stages, attributes|
seed = Gitlab::Ci::Pipeline::Seed::Stage.new(pipeline, attributes, previous_stages)
previous_stages + [seed]
end
seeds.select(&:included?)
def pipeline_seed
strong_memoize(:pipeline_seed) do
stages_attributes = @command.yaml_processor_result.stages_attributes
Gitlab::Ci::Pipeline::Seed::Pipeline.new(pipeline, stages_attributes)
end
end
def stages_attributes
@command.yaml_processor_result.stages_attributes
end
end
end
end
......
......@@ -34,11 +34,7 @@ module Gitlab
def pipeline_deployment_count
strong_memoize(:pipeline_deployment_count) do
@command.stage_seeds.sum do |stage_seed|
stage_seed.seeds.count do |build_seed|
build_seed.attributes[:environment].present?
end
end
@command.pipeline_seed.deployments_count
end
end
......
# frozen_string_literal: true
module Gitlab
module Ci
module Pipeline
module Seed
class Pipeline
include Gitlab::Utils::StrongMemoize
def initialize(pipeline, stages_attributes)
@pipeline = pipeline
@stages_attributes = stages_attributes
end
def errors
stage_seeds.flat_map(&:errors).compact.presence
end
def stages
stage_seeds.map(&:to_resource)
end
def size
stage_seeds.sum(&:size)
end
def deployments_count
stage_seeds.sum do |stage_seed|
stage_seed.seeds.count do |build_seed|
build_seed.attributes[:environment].present?
end
end
end
private
def stage_seeds
strong_memoize(:stage_seeds) do
seeds = @stages_attributes.inject([]) do |previous_stages, attributes|
seed = Gitlab::Ci::Pipeline::Seed::Stage.new(@pipeline, attributes, previous_stages)
previous_stages + [seed]
end
seeds.select(&:included?)
end
end
end
end
end
end
end
......@@ -7,26 +7,13 @@ RSpec.describe ::Gitlab::Ci::Pipeline::Chain::Limit::Deployments do
let_it_be(:project, reload: true) { create(:project, namespace: namespace) }
let_it_be(:plan_limits, reload: true) { create(:plan_limits, :default_plan) }
let(:stage_seeds) do
[
double(:test, seeds: [
double(:test, attributes: {})
]),
double(:staging, seeds: [
double(:staging, attributes: { environment: 'staging' })
]),
double(:production, seeds: [
double(:production, attributes: { environment: 'production' })
])
]
end
let(:pipeline_seed) { double(:pipeline_seed, deployments_count: 2) }
let(:save_incompleted) { false }
let(:command) do
double(:command,
project: project,
stage_seeds: stage_seeds,
pipeline_seed: pipeline_seed,
save_incompleted: save_incompleted
)
end
......
......@@ -50,8 +50,8 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do
it 'sets the seeds in the command object' do
run_chain
expect(command.stage_seeds).to all(be_a Gitlab::Ci::Pipeline::Seed::Base)
expect(command.stage_seeds.count).to eq 1
expect(command.pipeline_seed).to be_a(Gitlab::Ci::Pipeline::Seed::Pipeline)
expect(command.pipeline_seed.size).to eq 1
end
context 'when no ref policy is specified' do
......@@ -63,16 +63,18 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do
}
end
it 'correctly fabricates a stage seeds object' do
it 'correctly fabricates stages and builds' do
run_chain
seeds = command.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'
seed = command.pipeline_seed
expect(seed.stages.size).to eq 2
expect(seed.size).to eq 3
expect(seed.stages.first.name).to eq 'test'
expect(seed.stages.second.name).to eq 'deploy'
expect(seed.stages[0].statuses[0].name).to eq 'rspec'
expect(seed.stages[0].statuses[1].name).to eq 'spinach'
expect(seed.stages[1].statuses[0].name).to eq 'production'
end
end
......@@ -88,14 +90,14 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do
}
end
it 'returns stage seeds only assigned to master' do
it 'returns pipeline seed with jobs only assigned to master' do
run_chain
seeds = command.stage_seeds
seed = command.pipeline_seed
expect(seeds.size).to eq 1
expect(seeds.first.attributes[:name]).to eq 'test'
expect(seeds.dig(0, 0, :name)).to eq 'spinach'
expect(seed.size).to eq 1
expect(seed.stages.first.name).to eq 'test'
expect(seed.stages[0].statuses[0].name).to eq 'spinach'
end
end
......@@ -109,14 +111,14 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do
}
end
it 'returns stage seeds only assigned to schedules' do
it 'returns pipeline seed with jobs only assigned to schedules' do
run_chain
seeds = command.stage_seeds
seed = command.pipeline_seed
expect(seeds.size).to eq 1
expect(seeds.first.attributes[:name]).to eq 'test'
expect(seeds.dig(0, 0, :name)).to eq 'spinach'
expect(seed.size).to eq 1
expect(seed.stages.first.name).to eq 'test'
expect(seed.stages[0].statuses[0].name).to eq 'spinach'
end
end
......@@ -141,11 +143,11 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do
it 'returns seeds for kubernetes dependent job' do
run_chain
seeds = command.stage_seeds
seed = command.pipeline_seed
expect(seeds.size).to eq 2
expect(seeds.dig(0, 0, :name)).to eq 'spinach'
expect(seeds.dig(1, 0, :name)).to eq 'production'
expect(seed.size).to eq 2
expect(seed.stages[0].statuses[0].name).to eq 'spinach'
expect(seed.stages[1].statuses[0].name).to eq 'production'
end
end
end
......@@ -154,10 +156,10 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do
it 'does not return seeds for kubernetes dependent job' do
run_chain
seeds = command.stage_seeds
seed = command.pipeline_seed
expect(seeds.size).to eq 1
expect(seeds.dig(0, 0, :name)).to eq 'spinach'
expect(seed.size).to eq 1
expect(seed.stages[0].statuses[0].name).to eq 'spinach'
end
end
end
......@@ -173,10 +175,10 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do
it 'returns stage seeds only when variables expression is truthy' do
run_chain
seeds = command.stage_seeds
seed = command.pipeline_seed
expect(seeds.size).to eq 1
expect(seeds.dig(0, 0, :name)).to eq 'unit'
expect(seed.size).to eq 1
expect(seed.stages[0].statuses[0].name).to eq 'unit'
end
end
......
......@@ -10,24 +10,12 @@ RSpec.describe Gitlab::Ci::Pipeline::Quota::Deployments do
let(:pipeline) { build_stubbed(:ci_pipeline, project: project) }
let(:stage_seeds) do
[
double(:test, seeds: [
double(:test, attributes: {})
]),
double(:staging, seeds: [
double(:staging, attributes: { environment: 'staging' })
]),
double(:production, seeds: [
double(:production, attributes: { environment: 'production' })
])
]
end
let(:pipeline_seed) { double(:pipeline_seed, deployments_count: 2)}
let(:command) do
double(:command,
project: project,
stage_seeds: stage_seeds,
pipeline_seed: pipeline_seed,
save_incompleted: true
)
end
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Ci::Pipeline::Seed::Pipeline do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
let(:stages_attributes) do
[
{
name: 'build',
index: 0,
builds: [
{ name: 'init', scheduling_type: :stage },
{ name: 'build', scheduling_type: :stage }
]
},
{
name: 'test',
index: 1,
builds: [
{ name: 'rspec', scheduling_type: :stage },
{ name: 'staging', scheduling_type: :stage, environment: 'staging' },
{ name: 'deploy', scheduling_type: :stage, environment: 'production' }
]
}
]
end
subject(:seed) do
described_class.new(pipeline, stages_attributes)
end
describe '#stages' do
it 'returns the stage resources' do
stages = seed.stages
expect(stages).to all(be_a(Ci::Stage))
expect(stages.map(&:name)).to contain_exactly('build', 'test')
end
end
describe '#size' do
it 'returns the number of jobs' do
expect(seed.size).to eq(5)
end
end
describe '#errors' do
context 'when attributes are valid' do
it 'returns nil' do
expect(seed.errors).to be_nil
end
end
context 'when attributes are not valid' do
it 'returns the errors' do
stages_attributes[0][:builds] << {
name: 'invalid_job',
scheduling_type: :dag,
needs_attributes: [{ name: 'non-existent', artifacts: true }]
}
expect(seed.errors).to contain_exactly("invalid_job: needs 'non-existent'")
end
end
end
describe '#deployments_count' do
it 'counts the jobs having an environment associated' do
expect(seed.deployments_count).to eq(2)
end
end
end
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