Skip to content
Snippets Groups Projects
Commit a98649b7 authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent a4484fd2
No related branches found
No related tags found
No related merge requests found
Showing
with 642 additions and 86 deletions
Loading
Loading
@@ -94,7 +94,7 @@ module Gitlab
 
def on_38(stack) { fg: fg_color_256(stack) } end
 
def on_39(_) { fg: fg_color(9) } end
def on_39(_) { fg: nil } end
 
def on_40(_) { bg: bg_color(0) } end
 
Loading
Loading
@@ -114,8 +114,7 @@ module Gitlab
 
def on_48(stack) { bg: bg_color_256(stack) } end
 
# TODO: all the x9 never get called?
def on_49(_) { fg: fg_color(9) } end
def on_49(_) { bg: nil } end
 
def on_90(_) { fg: fg_color(0, 'l') } end
 
Loading
Loading
Loading
Loading
@@ -61,9 +61,9 @@ module Gitlab
case
when changes[:reset]
reset!
when changes[:fg]
when changes.key?(:fg)
@fg = changes[:fg]
when changes[:bg]
when changes.key?(:bg)
@bg = changes[:bg]
when changes[:enable]
@mask |= changes[:enable]
Loading
Loading
Loading
Loading
@@ -51,7 +51,7 @@ module Gitlab
validates :rules, array_of_hashes: true
end
 
validates :start_in, duration: { limit: '1 day' }, if: :delayed?
validates :start_in, duration: { limit: '1 week' }, if: :delayed?
validates :start_in, absence: true, if: -> { has_rules? || !delayed? }
 
validate do
Loading
Loading
Loading
Loading
@@ -5,9 +5,10 @@ module Gitlab
class Config
module Entry
class Need < ::Gitlab::Config::Entry::Simplifiable
strategy :Job, if: -> (config) { config.is_a?(String) }
strategy :JobString, if: -> (config) { config.is_a?(String) }
strategy :JobHash, if: -> (config) { config.is_a?(Hash) && config.key?(:job) }
 
class Job < ::Gitlab::Config::Entry::Node
class JobString < ::Gitlab::Config::Entry::Node
include ::Gitlab::Config::Entry::Validatable
 
validations do
Loading
Loading
@@ -20,7 +21,30 @@ module Gitlab
end
 
def value
{ name: @config }
{ name: @config, artifacts: true }
end
end
class JobHash < ::Gitlab::Config::Entry::Node
include ::Gitlab::Config::Entry::Validatable
include ::Gitlab::Config::Entry::Attributable
ALLOWED_KEYS = %i[job artifacts].freeze
attributes :job, :artifacts
validations do
validates :config, presence: true
validates :config, allowed_keys: ALLOWED_KEYS
validates :job, type: String, presence: true
validates :artifacts, boolean: true, allow_nil: true
end
def type
:job
end
def value
{ name: job, artifacts: artifacts || artifacts.nil? }
end
end
 
Loading
Loading
Loading
Loading
@@ -44,7 +44,7 @@ module Gitlab
 
if all_job_names = parallelized_jobs[job_need_name]
all_job_names.map do |job_name|
{ name: job_name }
job_need.merge(name: job_name)
end
else
job_need
Loading
Loading
Loading
Loading
@@ -6452,6 +6452,9 @@ msgstr ""
msgid "Enter merge request URLs"
msgstr ""
 
msgid "Enter new AWS Secret Access Key"
msgstr ""
msgid "Enter the issue description"
msgstr ""
 
Loading
Loading
Loading
Loading
@@ -116,7 +116,7 @@
"three": "^0.84.0",
"three-orbit-controls": "^82.1.0",
"three-stl-loader": "^1.0.4",
"timeago.js": "^3.0.2",
"timeago.js": "^4.0.1",
"tiptap": "^1.8.0",
"tiptap-commands": "^1.4.0",
"tiptap-extensions": "^1.8.0",
Loading
Loading
import { __, s__ } from '~/locale';
import * as datetimeUtility from '~/lib/utils/datetime_utility';
 
describe('Date time utils', () => {
describe('timeFor', () => {
it('returns `past due` when in past', () => {
it('returns localize `past due` when in past', () => {
const date = new Date();
date.setFullYear(date.getFullYear() - 1);
 
expect(datetimeUtility.timeFor(date)).toBe('Past due');
expect(datetimeUtility.timeFor(date)).toBe(s__('Timeago|Past due'));
});
 
it('returns remaining time when in the future', () => {
it('returns localized remaining time when in the future', () => {
const date = new Date();
date.setFullYear(date.getFullYear() + 1);
 
Loading
Loading
@@ -17,51 +18,51 @@ describe('Date time utils', () => {
// short of a full year, timeFor will return '11 months remaining'
date.setDate(date.getDate() + 1);
 
expect(datetimeUtility.timeFor(date)).toBe('1 year remaining');
expect(datetimeUtility.timeFor(date)).toBe(s__('Timeago|1 year remaining'));
});
});
 
describe('get day name', () => {
describe('get localized day name', () => {
it('should return Sunday', () => {
const day = datetimeUtility.getDayName(new Date('07/17/2016'));
 
expect(day).toBe('Sunday');
expect(day).toBe(__('Sunday'));
});
 
it('should return Monday', () => {
const day = datetimeUtility.getDayName(new Date('07/18/2016'));
 
expect(day).toBe('Monday');
expect(day).toBe(__('Monday'));
});
 
it('should return Tuesday', () => {
const day = datetimeUtility.getDayName(new Date('07/19/2016'));
 
expect(day).toBe('Tuesday');
expect(day).toBe(__('Tuesday'));
});
 
it('should return Wednesday', () => {
const day = datetimeUtility.getDayName(new Date('07/20/2016'));
 
expect(day).toBe('Wednesday');
expect(day).toBe(__('Wednesday'));
});
 
it('should return Thursday', () => {
const day = datetimeUtility.getDayName(new Date('07/21/2016'));
 
expect(day).toBe('Thursday');
expect(day).toBe(__('Thursday'));
});
 
it('should return Friday', () => {
const day = datetimeUtility.getDayName(new Date('07/22/2016'));
 
expect(day).toBe('Friday');
expect(day).toBe(__('Friday'));
});
 
it('should return Saturday', () => {
const day = datetimeUtility.getDayName(new Date('07/23/2016'));
 
expect(day).toBe('Saturday');
expect(day).toBe(__('Saturday'));
});
});
 
Loading
Loading
@@ -114,10 +115,10 @@ describe('Date time utils', () => {
 
describe('timeIntervalInWords', () => {
it('should return string with number of minutes and seconds', () => {
expect(datetimeUtility.timeIntervalInWords(9.54)).toEqual('9 seconds');
expect(datetimeUtility.timeIntervalInWords(1)).toEqual('1 second');
expect(datetimeUtility.timeIntervalInWords(200)).toEqual('3 minutes 20 seconds');
expect(datetimeUtility.timeIntervalInWords(6008)).toEqual('100 minutes 8 seconds');
expect(datetimeUtility.timeIntervalInWords(9.54)).toEqual(s__('Timeago|9 seconds'));
expect(datetimeUtility.timeIntervalInWords(1)).toEqual(s__('Timeago|1 second'));
expect(datetimeUtility.timeIntervalInWords(200)).toEqual(s__('Timeago|3 minutes 20 seconds'));
expect(datetimeUtility.timeIntervalInWords(6008)).toEqual(s__('Timeago|100 minutes 8 seconds'));
});
});
 
Loading
Loading
@@ -125,15 +126,15 @@ describe('dateInWords', () => {
const date = new Date('07/01/2016');
 
it('should return date in words', () => {
expect(datetimeUtility.dateInWords(date)).toEqual('July 1, 2016');
expect(datetimeUtility.dateInWords(date)).toEqual(s__('July 1, 2016'));
});
 
it('should return abbreviated month name', () => {
expect(datetimeUtility.dateInWords(date, true)).toEqual('Jul 1, 2016');
expect(datetimeUtility.dateInWords(date, true)).toEqual(s__('Jul 1, 2016'));
});
 
it('should return date in words without year', () => {
expect(datetimeUtility.dateInWords(date, true, true)).toEqual('Jul 1');
expect(datetimeUtility.dateInWords(date, true, true)).toEqual(s__('Jul 1'));
});
});
 
Loading
Loading
@@ -141,11 +142,11 @@ describe('monthInWords', () => {
const date = new Date('2017-01-20');
 
it('returns month name from provided date', () => {
expect(datetimeUtility.monthInWords(date)).toBe('January');
expect(datetimeUtility.monthInWords(date)).toBe(s__('January'));
});
 
it('returns abbreviated month name from provided date', () => {
expect(datetimeUtility.monthInWords(date, true)).toBe('Jan');
expect(datetimeUtility.monthInWords(date, true)).toBe(s__('Jan'));
});
});
 
Loading
Loading
Loading
Loading
@@ -68,8 +68,22 @@ describe Resolvers::IssuesResolver do
end
end
 
it 'searches issues' do
expect(resolve_issues(search: 'foo')).to contain_exactly(issue2)
context 'when searching issues' do
it 'returns correct issues' do
expect(resolve_issues(search: 'foo')).to contain_exactly(issue2)
end
it 'uses project search optimization' do
expected_arguments = {
search: 'foo',
attempt_project_search_optimizations: true,
iids: [],
project_id: project.id
}
expect(IssuesFinder).to receive(:new).with(anything, expected_arguments).and_call_original
resolve_issues(search: 'foo')
end
end
 
describe 'sorting' do
Loading
Loading
import 'timeago.js';
import { format } from 'timeago.js';
import Vue from 'vue';
import environmentItemComp from '~/environments/components/environment_item.vue';
 
Loading
Loading
@@ -139,8 +139,7 @@ describe('Environment item', () => {
});
 
it('should render last deployment date', () => {
const timeagoInstance = new timeago(); // eslint-disable-line
const formatedDate = timeagoInstance.format(environment.last_deployment.deployed_at);
const formatedDate = format(environment.last_deployment.deployed_at);
 
expect(
component.$el.querySelector('.environment-created-date-timeago').textContent,
Loading
Loading
Loading
Loading
@@ -147,6 +147,10 @@ describe Gitlab::Ci::Ansi2json::Style do
[%w[1], %w[0], '', 'resets style from format bold'],
[%w[1 3], %w[0], '', 'resets style from format bold and italic'],
[%w[1 3 term-fg-l-red term-bg-yellow], %w[0], '', 'resets all formats and colors'],
# default foreground
[%w[31 42], %w[39], 'term-bg-green', 'set foreground from red to default leaving background unchanged'],
# default background
[%w[31 42], %w[49], 'term-fg-red', 'set background from green to default leaving foreground unchanged'],
# misc
[[], %w[1 30 42 3], 'term-fg-l-black term-bg-green term-bold term-italic', 'adds fg color, bg color and formats from no style'],
[%w[3 31], %w[23 1 43], 'term-fg-l-red term-bg-yellow term-bold', 'replaces format italic with bold and adds a yellow background']
Loading
Loading
Loading
Loading
@@ -93,7 +93,7 @@ describe Gitlab::Ci::Config::Entry::Job do
 
context 'when delayed job' do
context 'when start_in is specified' do
let(:config) { { script: 'echo', when: 'delayed', start_in: '1 day' } }
let(:config) { { script: 'echo', when: 'delayed', start_in: '1 week' } }
 
it { expect(entry).to be_valid }
end
Loading
Loading
@@ -232,11 +232,9 @@ describe Gitlab::Ci::Config::Entry::Job do
 
context 'when delayed job' do
context 'when start_in is specified' do
let(:config) { { script: 'echo', when: 'delayed', start_in: '1 day' } }
let(:config) { { script: 'echo', when: 'delayed', start_in: '1 week' } }
 
it 'returns error about invalid type' do
expect(entry).to be_valid
end
it { expect(entry).to be_valid }
end
 
context 'when start_in is empty' do
Loading
Loading
@@ -257,8 +255,8 @@ describe Gitlab::Ci::Config::Entry::Job do
end
end
 
context 'when start_in is longer than one day' do
let(:config) { { when: 'delayed', start_in: '2 days' } }
context 'when start_in is longer than one week' do
let(:config) { { when: 'delayed', start_in: '8 days' } }
 
it 'returns error about exceeding the limit' do
expect(entry).not_to be_valid
Loading
Loading
Loading
Loading
@@ -5,31 +5,177 @@ require 'spec_helper'
describe ::Gitlab::Ci::Config::Entry::Need do
subject(:need) { described_class.new(config) }
 
context 'when job is specified' do
let(:config) { 'job_name' }
shared_examples 'job type' do
describe '#type' do
subject(:need_type) { need.type }
 
describe '#valid?' do
it { is_expected.to be_valid }
it { is_expected.to eq(:job) }
end
end
context 'with simple config' do
context 'when job is specified' do
let(:config) { 'job_name' }
describe '#valid?' do
it { is_expected.to be_valid }
end
describe '#value' do
it 'returns job needs configuration' do
expect(need.value).to eq(name: 'job_name', artifacts: true)
end
end
it_behaves_like 'job type'
end
context 'when need is empty' do
let(:config) { '' }
describe '#valid?' do
it { is_expected.not_to be_valid }
end
describe '#errors' do
it 'is returns an error about an empty config' do
expect(need.errors)
.to contain_exactly("job string config can't be blank")
end
end
it_behaves_like 'job type'
end
end
context 'with complex config' do
context 'with job name and artifacts true' do
let(:config) { { job: 'job_name', artifacts: true } }
describe '#valid?' do
it { is_expected.to be_valid }
end
describe '#value' do
it 'returns job needs configuration' do
expect(need.value).to eq(name: 'job_name', artifacts: true)
end
end
it_behaves_like 'job type'
end
context 'with job name and artifacts false' do
let(:config) { { job: 'job_name', artifacts: false } }
describe '#valid?' do
it { is_expected.to be_valid }
end
describe '#value' do
it 'returns job needs configuration' do
expect(need.value).to eq(name: 'job_name', artifacts: false)
end
end
it_behaves_like 'job type'
end
context 'with job name and artifacts nil' do
let(:config) { { job: 'job_name', artifacts: nil } }
 
describe '#value' do
it 'returns job needs configuration' do
expect(need.value).to eq(name: 'job_name')
describe '#valid?' do
it { is_expected.to be_valid }
end
describe '#value' do
it 'returns job needs configuration' do
expect(need.value).to eq(name: 'job_name', artifacts: true)
end
end
it_behaves_like 'job type'
end
context 'without artifacts key' do
let(:config) { { job: 'job_name' } }
describe '#valid?' do
it { is_expected.to be_valid }
end
describe '#value' do
it 'returns job needs configuration' do
expect(need.value).to eq(name: 'job_name', artifacts: true)
end
end
it_behaves_like 'job type'
end
context 'when job name is empty' do
let(:config) { { job: '', artifacts: true } }
describe '#valid?' do
it { is_expected.not_to be_valid }
end
describe '#errors' do
it 'is returns an error about an empty config' do
expect(need.errors)
.to contain_exactly("job hash job can't be blank")
end
end
it_behaves_like 'job type'
end
context 'when job name is not a string' do
let(:config) { { job: :job_name, artifacts: false } }
describe '#valid?' do
it { is_expected.not_to be_valid }
end
describe '#errors' do
it 'is returns an error about job type' do
expect(need.errors)
.to contain_exactly('job hash job should be a string')
end
end
it_behaves_like 'job type'
end
context 'when job has unknown keys' do
let(:config) { { job: 'job_name', artifacts: false, some: :key } }
describe '#valid?' do
it { is_expected.not_to be_valid }
end
describe '#errors' do
it 'is returns an error about job type' do
expect(need.errors)
.to contain_exactly('job hash config contains unknown keys: some')
end
end
it_behaves_like 'job type'
end
end
 
context 'when need is empty' do
let(:config) { '' }
context 'when need config is not a string or a hash' do
let(:config) { :job_name }
 
describe '#valid?' do
it { is_expected.not_to be_valid }
end
 
describe '#errors' do
it 'is returns an error about an empty config' do
it 'is returns an error about job type' do
expect(need.errors)
.to contain_exactly("job config can't be blank")
.to contain_exactly('unknown strategy has an unsupported type')
end
end
end
Loading
Loading
Loading
Loading
@@ -51,9 +51,34 @@ describe ::Gitlab::Ci::Config::Entry::Needs do
end
end
end
context 'when wrong needs type is used' do
let(:config) { [{ job: 'job_name', artifacts: true, some: :key }] }
describe '#valid?' do
it { is_expected.not_to be_valid }
end
describe '#errors' do
it 'returns error about incorrect type' do
expect(needs.errors).to contain_exactly(
'need config contains unknown keys: some')
end
end
end
end
 
describe '.compose!' do
shared_examples 'entry with descendant nodes' do
describe '#descendants' do
it 'creates valid descendant nodes' do
expect(needs.descendants.count).to eq 2
expect(needs.descendants)
.to all(be_an_instance_of(::Gitlab::Ci::Config::Entry::Need))
end
end
end
context 'when valid job entries composed' do
let(:config) { %w[first_job_name second_job_name] }
 
Loading
Loading
@@ -65,18 +90,80 @@ describe ::Gitlab::Ci::Config::Entry::Needs do
it 'returns key value' do
expect(needs.value).to eq(
job: [
{ name: 'first_job_name' },
{ name: 'second_job_name' }
{ name: 'first_job_name', artifacts: true },
{ name: 'second_job_name', artifacts: true }
]
)
end
end
 
describe '#descendants' do
it 'creates valid descendant nodes' do
expect(needs.descendants.count).to eq 2
expect(needs.descendants)
.to all(be_an_instance_of(::Gitlab::Ci::Config::Entry::Need))
it_behaves_like 'entry with descendant nodes'
end
context 'with complex job entries composed' do
let(:config) do
[
{ job: 'first_job_name', artifacts: true },
{ job: 'second_job_name', artifacts: false }
]
end
before do
needs.compose!
end
describe '#value' do
it 'returns key value' do
expect(needs.value).to eq(
job: [
{ name: 'first_job_name', artifacts: true },
{ name: 'second_job_name', artifacts: false }
]
)
end
end
it_behaves_like 'entry with descendant nodes'
end
context 'with mixed job entries composed' do
let(:config) do
[
'first_job_name',
{ job: 'second_job_name', artifacts: false }
]
end
before do
needs.compose!
end
describe '#value' do
it 'returns key value' do
expect(needs.value).to eq(
job: [
{ name: 'first_job_name', artifacts: true },
{ name: 'second_job_name', artifacts: false }
]
)
end
end
it_behaves_like 'entry with descendant nodes'
end
context 'with empty config' do
let(:config) do
[]
end
before do
needs.compose!
end
describe '#value' do
it 'returns empty value' do
expect(needs.value).to eq({})
end
end
end
Loading
Loading
Loading
Loading
@@ -105,7 +105,7 @@ describe Gitlab::Ci::Config::Normalizer do
context 'for needs' do
let(:expanded_job_attributes) do
expanded_job_names.map do |job_name|
{ name: job_name }
{ name: job_name, extra: :key }
end
end
 
Loading
Loading
@@ -117,7 +117,7 @@ describe Gitlab::Ci::Config::Normalizer do
script: 'echo 1',
needs: {
job: [
{ name: job_name.to_s }
{ name: job_name.to_s, extra: :key }
]
}
}
Loading
Loading
@@ -140,8 +140,8 @@ describe Gitlab::Ci::Config::Normalizer do
script: 'echo 1',
needs: {
job: [
{ name: job_name.to_s },
{ name: "other_job" }
{ name: job_name.to_s, extra: :key },
{ name: "other_job", extra: :key }
]
}
}
Loading
Loading
@@ -153,7 +153,7 @@ describe Gitlab::Ci::Config::Normalizer do
end
 
it "includes the regular job in dependencies" do
expect(subject.dig(:final_job, :needs, :job)).to include(name: 'other_job')
expect(subject.dig(:final_job, :needs, :job)).to include(name: 'other_job', extra: :key)
end
end
end
Loading
Loading
Loading
Loading
@@ -1525,8 +1525,48 @@ module Gitlab
name: "test1",
options: { script: ["test"] },
needs_attributes: [
{ name: "build1" },
{ name: "build2" }
{ name: "build1", artifacts: true },
{ name: "build2", artifacts: true }
],
when: "on_success",
allow_failure: false,
yaml_variables: []
)
end
end
context 'needs two builds' do
let(:needs) do
[
{ job: 'parallel', artifacts: false },
{ job: 'build1', artifacts: true },
'build2'
]
end
it "does create jobs with valid specification" do
expect(subject.builds.size).to eq(7)
expect(subject.builds[0]).to eq(
stage: "build",
stage_idx: 1,
name: "build1",
options: {
script: ["test"]
},
when: "on_success",
allow_failure: false,
yaml_variables: []
)
expect(subject.builds[4]).to eq(
stage: "test",
stage_idx: 2,
name: "test1",
options: { script: ["test"] },
needs_attributes: [
{ name: "parallel 1/2", artifacts: false },
{ name: "parallel 2/2", artifacts: false },
{ name: "build1", artifacts: true },
{ name: "build2", artifacts: true }
],
when: "on_success",
allow_failure: false,
Loading
Loading
@@ -1546,8 +1586,37 @@ module Gitlab
name: "test1",
options: { script: ["test"] },
needs_attributes: [
{ name: "parallel 1/2" },
{ name: "parallel 2/2" }
{ name: "parallel 1/2", artifacts: true },
{ name: "parallel 2/2", artifacts: true }
],
when: "on_success",
allow_failure: false,
yaml_variables: []
)
end
end
context 'needs dependencies artifacts' do
let(:needs) do
[
"build1",
{ job: "build2" },
{ job: "parallel", artifacts: true }
]
end
it "does create jobs with valid specification" do
expect(subject.builds.size).to eq(7)
expect(subject.builds[4]).to eq(
stage: "test",
stage_idx: 2,
name: "test1",
options: { script: ["test"] },
needs_attributes: [
{ name: "build1", artifacts: true },
{ name: "build2", artifacts: true },
{ name: "parallel 1/2", artifacts: true },
{ name: "parallel 2/2", artifacts: true }
],
when: "on_success",
allow_failure: false,
Loading
Loading
Loading
Loading
@@ -10,4 +10,11 @@ describe Ci::BuildNeed, model: true do
it { is_expected.to validate_presence_of(:build) }
it { is_expected.to validate_presence_of(:name) }
it { is_expected.to validate_length_of(:name).is_at_most(128) }
describe '.artifacts' do
let_it_be(:with_artifacts) { create(:ci_build_need, artifacts: true) }
let_it_be(:without_artifacts) { create(:ci_build_need, artifacts: false) }
it { expect(described_class.artifacts).to contain_exactly(with_artifacts) }
end
end
Loading
Loading
@@ -741,20 +741,26 @@ describe Ci::Build do
 
before do
needs.to_a.each do |need|
create(:ci_build_need, build: final, name: need)
create(:ci_build_need, build: final, **need)
end
end
 
subject { final.dependencies }
 
context 'when depedencies are defined' do
context 'when dependencies are defined' do
let(:dependencies) { %w(rspec staging) }
 
it { is_expected.to contain_exactly(rspec_test, staging) }
end
 
context 'when needs are defined' do
let(:needs) { %w(build rspec staging) }
let(:needs) do
[
{ name: 'build', artifacts: true },
{ name: 'rspec', artifacts: true },
{ name: 'staging', artifacts: true }
]
end
 
it { is_expected.to contain_exactly(build, rspec_test, staging) }
 
Loading
Loading
@@ -767,13 +773,44 @@ describe Ci::Build do
end
end
 
context 'when need artifacts are defined' do
let(:needs) do
[
{ name: 'build', artifacts: true },
{ name: 'rspec', artifacts: false },
{ name: 'staging', artifacts: true }
]
end
it { is_expected.to contain_exactly(build, staging) }
end
context 'when needs and dependencies are defined' do
let(:dependencies) { %w(rspec staging) }
let(:needs) { %w(build rspec staging) }
let(:needs) do
[
{ name: 'build', artifacts: true },
{ name: 'rspec', artifacts: true },
{ name: 'staging', artifacts: true }
]
end
 
it { is_expected.to contain_exactly(rspec_test, staging) }
end
 
context 'when needs and dependencies contradict' do
let(:dependencies) { %w(rspec staging) }
let(:needs) do
[
{ name: 'build', artifacts: true },
{ name: 'rspec', artifacts: false },
{ name: 'staging', artifacts: true }
]
end
it { is_expected.to contain_exactly(staging) }
end
context 'when nor dependencies or needs are defined' do
it { is_expected.to contain_exactly(build, rspec_test, rubocop_test, staging) }
end
Loading
Loading
# frozen_string_literal: true
require 'spec_helper'
describe Ci::CreatePipelineService do
context 'needs' do
let_it_be(:user) { create(:admin) }
let_it_be(:project) { create(:project, :repository, creator: user) }
let(:ref) { 'refs/heads/master' }
let(:source) { :push }
let(:service) { described_class.new(project, user, { ref: ref }) }
let(:pipeline) { service.execute(source) }
before do
stub_ci_pipeline_yaml_file(config)
end
context 'with a valid config' do
let(:config) do
<<~YAML
build_a:
stage: build
script:
- make
artifacts:
paths:
- binaries/
build_b:
stage: build
script:
- make
artifacts:
paths:
- other_binaries/
build_c:
stage: build
script:
- make
build_d:
stage: build
script:
- make
parallel: 3
test_a:
stage: test
script:
- ls
needs:
- build_a
- job: build_b
artifacts: true
- job: build_c
artifacts: false
dependencies:
- build_a
test_b:
stage: test
script:
- ls
parallel: 2
needs:
- build_a
- job: build_b
artifacts: true
- job: build_d
artifacts: false
test_c:
stage: test
script:
- ls
needs:
- build_a
- job: build_b
- job: build_c
artifacts: true
YAML
end
let(:test_a_build) { pipeline.builds.find_by!(name: 'test_a') }
it 'creates a pipeline with builds' do
expected_builds = [
'build_a', 'build_b', 'build_c', 'build_d 1/3', 'build_d 2/3',
'build_d 3/3', 'test_a', 'test_b 1/2', 'test_b 2/2', 'test_c'
]
expect(pipeline).to be_persisted
expect(pipeline.builds.pluck(:name)).to contain_exactly(*expected_builds)
end
it 'saves needs' do
expect(test_a_build.needs.map(&:attributes))
.to contain_exactly(
a_hash_including('name' => 'build_a', 'artifacts' => true),
a_hash_including('name' => 'build_b', 'artifacts' => true),
a_hash_including('name' => 'build_c', 'artifacts' => false)
)
end
it 'saves dependencies' do
expect(test_a_build.options)
.to match(a_hash_including('dependencies' => ['build_a']))
end
it 'artifacts default to true' do
test_job = pipeline.builds.find_by!(name: 'test_c')
expect(test_job.needs.map(&:attributes))
.to contain_exactly(
a_hash_including('name' => 'build_a', 'artifacts' => true),
a_hash_including('name' => 'build_b', 'artifacts' => true),
a_hash_including('name' => 'build_c', 'artifacts' => true)
)
end
it 'saves parallel jobs' do
['1/2', '2/2'].each do |part|
test_job = pipeline.builds.find_by(name: "test_b #{part}")
expect(test_job.needs.map(&:attributes))
.to contain_exactly(
a_hash_including('name' => 'build_a', 'artifacts' => true),
a_hash_including('name' => 'build_b', 'artifacts' => true),
a_hash_including('name' => 'build_d 1/3', 'artifacts' => false),
a_hash_including('name' => 'build_d 2/3', 'artifacts' => false),
a_hash_including('name' => 'build_d 3/3', 'artifacts' => false)
)
end
end
end
context 'with an invalid config' do
let(:config) do
<<~YAML
build_a:
stage: build
script:
- make
artifacts:
paths:
- binaries/
build_b:
stage: build
script:
- make
artifacts:
paths:
- other_binaries/
test_a:
stage: test
script:
- ls
needs:
- build_a
- job: build_b
artifacts: string
YAML
end
it { expect(pipeline).to be_persisted }
it { expect(pipeline.builds.any?).to be_falsey }
it 'assigns an error to the pipeline' do
expect(pipeline.yaml_errors)
.to eq('jobs:test_a:needs:need artifacts should be a boolean value')
end
end
end
end
Loading
Loading
@@ -1047,11 +1047,6 @@
"@types/istanbul-lib-coverage" "*"
"@types/istanbul-lib-report" "*"
 
"@types/jquery@^2.0.40":
version "2.0.48"
resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-2.0.48.tgz#3e90d8cde2d29015e5583017f7830cb3975b2eef"
integrity sha512-nNLzUrVjaRV/Ds1eHZLYTd7IZxs38cwwLSaqMJj8OTXY8xNUbxSK69bi9cMLvQ7dm/IBeQ1wHwQ0S1uYa0rd2w==
"@types/minimatch@*":
version "3.0.3"
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
Loading
Loading
@@ -10877,12 +10872,10 @@ thunky@^0.1.0:
resolved "https://registry.yarnpkg.com/thunky/-/thunky-0.1.0.tgz#bf30146824e2b6e67b0f2d7a4ac8beb26908684e"
integrity sha1-vzAUaCTituZ7Dy16Ssi+smkIaE4=
 
timeago.js@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/timeago.js/-/timeago.js-3.0.2.tgz#32a67e7c0d887ea42ca588d3aae26f77de5e76cc"
integrity sha1-MqZ+fA2IfqQspYjTquJvd95edsw=
dependencies:
"@types/jquery" "^2.0.40"
timeago.js@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/timeago.js/-/timeago.js-4.0.1.tgz#4be4aa19565ceaeb0da31fe14e01ce6ca4742da6"
integrity sha512-ePzZuMoJqUc44hJbUYtY1qtzU7IammxooDCcFKogLkS5Nj+iCabR0ZlmNOFX8Dm1r5EpvR5q/PotOJli/mEPew==
 
timed-out@^4.0.0:
version "4.0.1"
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment