Commit 11286336 authored by Thong Kuah's avatar Thong Kuah

Merge branch...

Merge branch '31441-make-it-easy-for-includes-to-add-jobs-at-beginning-end-of-pipeline' into 'master'

Make it easy for includes to add jobs at beginning/end of pipeline

See merge request gitlab-org/gitlab!18205
parents 0544ea42 b53bd7c0
---
title: Add two new predefined stages to pipelines
merge_request: 18205
author:
type: added
...@@ -78,8 +78,13 @@ module Gitlab ...@@ -78,8 +78,13 @@ module Gitlab
def build_config(config) def build_config(config)
initial_config = Gitlab::Config::Loader::Yaml.new(config).load! initial_config = Gitlab::Config::Loader::Yaml.new(config).load!
initial_config = Config::External::Processor.new(initial_config, @context).perform initial_config = Config::External::Processor.new(initial_config, @context).perform
initial_config = Config::Extendable.new(initial_config).to_hash
Config::Extendable.new(initial_config).to_hash if Feature.enabled?(:ci_pre_post_pipeline_stages, @context.project, default_enabled: true)
initial_config = Config::EdgeStagesInjector.new(initial_config).to_hash
end
initial_config
end end
def build_context(project:, sha:, user:) def build_context(project:, sha:, user:)
......
# frozen_string_literal: true
module Gitlab
module Ci
class Config
class EdgeStagesInjector
PRE_PIPELINE = '.pre'
POST_PIPELINE = '.post'
EDGES = [PRE_PIPELINE, POST_PIPELINE].freeze
def self.wrap_stages(stages)
stages = stages.to_a - EDGES
stages.unshift PRE_PIPELINE
stages.push POST_PIPELINE
stages
end
def initialize(config)
@config = config.to_h.deep_dup
end
def to_hash
if config.key?(:stages)
process(:stages)
elsif config.key?(:types)
process(:types)
else
config
end
end
private
attr_reader :config
delegate :wrap_stages, to: :class
def process(keyword)
stages = extract_stages(keyword)
return config if stages.empty?
stages = wrap_stages(stages)
config[keyword] = stages
config
end
def extract_stages(keyword)
stages = config[keyword]
return [] unless stages.is_a?(Array)
stages
end
end
end
end
end
...@@ -15,7 +15,7 @@ module Gitlab ...@@ -15,7 +15,7 @@ module Gitlab
end end
def self.default def self.default
%w[build test deploy] Config::EdgeStagesInjector.wrap_stages %w[build test deploy]
end end
end end
end end
......
# frozen_string_literal: true
require 'fast_spec_helper'
describe Gitlab::Ci::Config::EdgeStagesInjector do
describe '#call' do
subject { described_class.new(config).to_hash }
context 'without stages' do
let(:config) do
{
test: { script: 'test' }
}
end
it { is_expected.to match config }
end
context 'with values' do
let(:config) do
{
stages: %w[stage1 stage2],
test: { script: 'test' }
}
end
let(:expected_stages) do
%w[.pre stage1 stage2 .post]
end
it { is_expected.to match(config.merge(stages: expected_stages)) }
end
context 'with bad values' do
let(:config) do
{
stages: 'stage1',
test: { script: 'test' }
}
end
it { is_expected.to match(config) }
end
context 'with collision values' do
let(:config) do
{
stages: %w[.post stage1 .pre .post stage2],
test: { script: 'test' }
}
end
let(:expected_stages) do
%w[.pre stage1 stage2 .post]
end
it { is_expected.to match(config.merge(stages: expected_stages)) }
end
context 'with types' do
let(:config) do
{
types: %w[stage1 stage2],
test: { script: 'test' }
}
end
let(:expected_config) do
{
types: %w[.pre stage1 stage2 .post],
test: { script: 'test' }
}
end
it { is_expected.to match expected_config }
end
context 'with types' do
let(:config) do
{
types: %w[.post stage1 .pre .post stage2],
test: { script: 'test' }
}
end
let(:expected_config) do
{
types: %w[.pre stage1 stage2 .post],
test: { script: 'test' }
}
end
it { is_expected.to match expected_config }
end
end
describe '.wrap_stages' do
subject { described_class.wrap_stages(stages) }
context 'with empty value' do
let(:stages) {}
it { is_expected.to eq %w[.pre .post] }
end
context 'with values' do
let(:stages) { %w[s1 .pre] }
it { is_expected.to eq %w[.pre s1 .post] }
end
end
end
...@@ -215,7 +215,7 @@ describe Gitlab::Ci::Config::Entry::Root do ...@@ -215,7 +215,7 @@ describe Gitlab::Ci::Config::Entry::Root do
describe '#stages_value' do describe '#stages_value' do
it 'returns an array of root stages' do it 'returns an array of root stages' do
expect(root.stages_value).to eq %w[build test deploy] expect(root.stages_value).to eq %w[.pre build test deploy .post]
end end
end end
......
...@@ -42,7 +42,7 @@ describe Gitlab::Ci::Config::Entry::Stages do ...@@ -42,7 +42,7 @@ describe Gitlab::Ci::Config::Entry::Stages do
describe '.default' do describe '.default' do
it 'returns default stages' do it 'returns default stages' do
expect(described_class.default).to eq %w[build test deploy] expect(described_class.default).to eq %w[.pre build test deploy .post]
end end
end end
end end
...@@ -51,6 +51,54 @@ describe Gitlab::Ci::Config do ...@@ -51,6 +51,54 @@ describe Gitlab::Ci::Config do
end end
end end
end end
describe '#stages' do
subject(:subject) { config.stages }
context 'with default stages' do
let(:default_stages) do
%w[.pre build test deploy .post]
end
it { is_expected.to eq default_stages }
end
context 'with custom stages' do
let(:yml) do
<<-EOS
stages:
- stage1
- stage2
job1:
stage: stage1
script:
- ls
EOS
end
it { is_expected.to eq %w[.pre stage1 stage2 .post] }
end
context 'with feature disabled' do
before do
stub_feature_flags(ci_pre_post_pipeline_stages: false)
end
let(:yml) do
<<-EOS
stages:
- stage1
- stage2
job1:
stage: stage1
script:
- ls
EOS
end
it { is_expected.to eq %w[stage1 stage2] }
end
end
end end
context 'when using extendable hash' do context 'when using extendable hash' do
......
...@@ -26,7 +26,7 @@ module Gitlab ...@@ -26,7 +26,7 @@ module Gitlab
it 'returns valid build attributes' do it 'returns valid build attributes' do
expect(subject).to eq({ expect(subject).to eq({
stage: "test", stage: "test",
stage_idx: 1, stage_idx: 2,
name: "rspec", name: "rspec",
options: { options: {
before_script: ["pwd"], before_script: ["pwd"],
...@@ -56,7 +56,7 @@ module Gitlab ...@@ -56,7 +56,7 @@ module Gitlab
it 'returns valid build attributes' do it 'returns valid build attributes' do
expect(subject).to eq({ expect(subject).to eq({
stage: 'test', stage: 'test',
stage_idx: 1, stage_idx: 2,
name: 'rspec', name: 'rspec',
options: { script: ['rspec'] }, options: { script: ['rspec'] },
rules: [ rules: [
...@@ -209,13 +209,16 @@ module Gitlab ...@@ -209,13 +209,16 @@ module Gitlab
end end
let(:attributes) do let(:attributes) do
[{ name: "build", [{ name: ".pre",
index: 0, index: 0,
builds: [] }, builds: [] },
{ name: "test", { name: "build",
index: 1, index: 1,
builds: [] },
{ name: "test",
index: 2,
builds: builds:
[{ stage_idx: 1, [{ stage_idx: 2,
stage: "test", stage: "test",
name: "rspec", name: "rspec",
allow_failure: false, allow_failure: false,
...@@ -225,9 +228,9 @@ module Gitlab ...@@ -225,9 +228,9 @@ module Gitlab
only: { refs: ["branches"] }, only: { refs: ["branches"] },
except: {} }] }, except: {} }] },
{ name: "deploy", { name: "deploy",
index: 2, index: 3,
builds: builds:
[{ stage_idx: 2, [{ stage_idx: 3,
stage: "deploy", stage: "deploy",
name: "prod", name: "prod",
allow_failure: false, allow_failure: false,
...@@ -235,7 +238,10 @@ module Gitlab ...@@ -235,7 +238,10 @@ module Gitlab
yaml_variables: [], yaml_variables: [],
options: { script: ["cap prod"] }, options: { script: ["cap prod"] },
only: { refs: ["tags"] }, only: { refs: ["tags"] },
except: {} }] }] except: {} }] },
{ name: ".post",
index: 4,
builds: [] }]
end end
it 'returns stages seed attributes' do it 'returns stages seed attributes' do
...@@ -425,7 +431,7 @@ module Gitlab ...@@ -425,7 +431,7 @@ module Gitlab
expect(config_processor.stage_builds_attributes("test").size).to eq(1) expect(config_processor.stage_builds_attributes("test").size).to eq(1)
expect(config_processor.stage_builds_attributes("test").first).to eq({ expect(config_processor.stage_builds_attributes("test").first).to eq({
stage: "test", stage: "test",
stage_idx: 1, stage_idx: 2,
name: "rspec", name: "rspec",
options: { options: {
before_script: ["pwd"], before_script: ["pwd"],
...@@ -456,7 +462,7 @@ module Gitlab ...@@ -456,7 +462,7 @@ module Gitlab
expect(config_processor.stage_builds_attributes("test").size).to eq(1) expect(config_processor.stage_builds_attributes("test").size).to eq(1)
expect(config_processor.stage_builds_attributes("test").first).to eq({ expect(config_processor.stage_builds_attributes("test").first).to eq({
stage: "test", stage: "test",
stage_idx: 1, stage_idx: 2,
name: "rspec", name: "rspec",
options: { options: {
before_script: ["pwd"], before_script: ["pwd"],
...@@ -485,7 +491,7 @@ module Gitlab ...@@ -485,7 +491,7 @@ module Gitlab
expect(config_processor.stage_builds_attributes("test").size).to eq(1) expect(config_processor.stage_builds_attributes("test").size).to eq(1)
expect(config_processor.stage_builds_attributes("test").first).to eq({ expect(config_processor.stage_builds_attributes("test").first).to eq({
stage: "test", stage: "test",
stage_idx: 1, stage_idx: 2,
name: "rspec", name: "rspec",
options: { options: {
before_script: ["pwd"], before_script: ["pwd"],
...@@ -510,7 +516,7 @@ module Gitlab ...@@ -510,7 +516,7 @@ module Gitlab
expect(config_processor.stage_builds_attributes("test").size).to eq(1) expect(config_processor.stage_builds_attributes("test").size).to eq(1)
expect(config_processor.stage_builds_attributes("test").first).to eq({ expect(config_processor.stage_builds_attributes("test").first).to eq({
stage: "test", stage: "test",
stage_idx: 1, stage_idx: 2,
name: "rspec", name: "rspec",
options: { options: {
before_script: ["pwd"], before_script: ["pwd"],
...@@ -977,7 +983,7 @@ module Gitlab ...@@ -977,7 +983,7 @@ module Gitlab
expect(config_processor.stage_builds_attributes("test").size).to eq(1) expect(config_processor.stage_builds_attributes("test").size).to eq(1)
expect(config_processor.stage_builds_attributes("test").first).to eq({ expect(config_processor.stage_builds_attributes("test").first).to eq({
stage: "test", stage: "test",
stage_idx: 1, stage_idx: 2,
name: "rspec", name: "rspec",
options: { options: {
before_script: ["pwd"], before_script: ["pwd"],
...@@ -1272,7 +1278,7 @@ module Gitlab ...@@ -1272,7 +1278,7 @@ module Gitlab
expect(subject.builds.size).to eq(5) expect(subject.builds.size).to eq(5)
expect(subject.builds[0]).to eq( expect(subject.builds[0]).to eq(
stage: "build", stage: "build",
stage_idx: 0, stage_idx: 1,
name: "build1", name: "build1",
options: { options: {
script: ["test"] script: ["test"]
...@@ -1283,7 +1289,7 @@ module Gitlab ...@@ -1283,7 +1289,7 @@ module Gitlab
) )
expect(subject.builds[2]).to eq( expect(subject.builds[2]).to eq(
stage: "test", stage: "test",
stage_idx: 1, stage_idx: 2,
name: "test1", name: "test1",
options: { options: {
script: ["test"], script: ["test"],
...@@ -1398,7 +1404,7 @@ module Gitlab ...@@ -1398,7 +1404,7 @@ module Gitlab
expect(subject.size).to eq(1) expect(subject.size).to eq(1)
expect(subject.first).to eq({ expect(subject.first).to eq({
stage: "test", stage: "test",
stage_idx: 1, stage_idx: 2,
name: "normal_job", name: "normal_job",
options: { options: {
script: ["test"] script: ["test"]
...@@ -1442,7 +1448,7 @@ module Gitlab ...@@ -1442,7 +1448,7 @@ module Gitlab
expect(subject.size).to eq(2) expect(subject.size).to eq(2)
expect(subject.first).to eq({ expect(subject.first).to eq({
stage: "build", stage: "build",
stage_idx: 0, stage_idx: 1,
name: "job1", name: "job1",
options: { options: {
script: ["execute-script-for-job"] script: ["execute-script-for-job"]
...@@ -1453,7 +1459,7 @@ module Gitlab ...@@ -1453,7 +1459,7 @@ module Gitlab
}) })
expect(subject.second).to eq({ expect(subject.second).to eq({
stage: "build", stage: "build",
stage_idx: 0, stage_idx: 1,
name: "job2", name: "job2",
options: { options: {
script: ["execute-script-for-job"] script: ["execute-script-for-job"]
...@@ -1665,14 +1671,14 @@ module Gitlab ...@@ -1665,14 +1671,14 @@ module Gitlab
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) 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 .pre, build, test, deploy, .post")
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) 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 .pre, build, test, .post")
end end
it "returns errors if stages is not an array" do it "returns errors if stages is not an array" 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