Commit 550466dd authored by Rémy Coutable's avatar Rémy Coutable

Merge branch 'store-variables-and-when-in-builds-table' into 'master'

Store when and yaml variables in builds table

## What does this MR do?
Stores `when` and `yaml_variables` in `ci_builds` table.

## Why was this MR needed?
This is done in order to simplify the code responsible for creating a pipeline builds.

## What are the relevant issue numbers?
This made as a pre-step for https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5295.

## Does this MR meet the acceptance criteria?

- [x] [CHANGELOG](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CHANGELOG) entry added
- [x] [Documentation created/updated](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/development/doc_styleguide.md)
- [x] API support added
- Tests
  - [x] Added for this feature/bug
  - [x] All builds are passing
- [x] Conform by the [style guides](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#style-guides)
- [x] Branch has no merge conflicts with `master` (if you do - rebase it please)
- [ ] [Squashed related commits together](https://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits)

See merge request !5296
parents 2556d6d3 ffea9c46
......@@ -16,6 +16,7 @@ v 8.10.0 (unreleased)
- Align flash messages with left side of page content !4959 (winniehell)
- Display tooltip for "Copy to Clipboard" button !5164 (winniehell)
- Use default cursor for table header of project files !5165 (winniehell)
- Store when and yaml variables in builds table
- Display last commit of deleted branch in push events !4699 (winniehell)
- Escape file extension when parsing search results !5141 (winniehell)
- Apply the trusted_proxies config to the rack request object for use with rack_attack
......
......@@ -5,6 +5,7 @@ module Ci
belongs_to :erased_by, class_name: 'User'
serialize :options
serialize :yaml_variables
validates :coverage, numericality: true, allow_blank: true
validates_presence_of :ref
......@@ -52,6 +53,8 @@ module Ci
new_build.stage = build.stage
new_build.stage_idx = build.stage_idx
new_build.trigger_request = build.trigger_request
new_build.yaml_variables = build.yaml_variables
new_build.when = build.when
new_build.user = user
new_build.environment = build.environment
new_build.save
......@@ -118,7 +121,12 @@ module Ci
end
def variables
predefined_variables + yaml_variables + project_variables + trigger_variables
variables = []
variables += predefined_variables
variables += yaml_variables if yaml_variables
variables += project_variables
variables += trigger_variables
variables
end
def merge_request
......@@ -395,30 +403,6 @@ module Ci
self.update(erased_by: user, erased_at: Time.now, artifacts_expire_at: nil)
end
def yaml_variables
global_yaml_variables + job_yaml_variables
end
def global_yaml_variables
if pipeline.config_processor
pipeline.config_processor.global_variables.map do |key, value|
{ key: key, value: value, public: true }
end
else
[]
end
end
def job_yaml_variables
if pipeline.config_processor
pipeline.config_processor.job_variables(name).map do |key, value|
{ key: key, value: value, public: true }
end
else
[]
end
end
def project_variables
project.variables.map do |variable|
{ key: variable.key, value: variable.value, public: false }
......
......@@ -36,7 +36,9 @@ module Ci
:allow_failure,
:stage,
:stage_idx,
:environment)
:environment,
:when,
:yaml_variables)
build_attrs.merge!(pipeline: @pipeline,
ref: @pipeline.ref,
......
class AddWhenAndYamlVariablesToCiBuilds < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
def change
add_column :ci_builds, :when, :string
add_column :ci_builds, :yaml_variables, :text
end
end
......@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20160715134306) do
ActiveRecord::Schema.define(version: 20160716115710) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
......@@ -168,6 +168,8 @@ ActiveRecord::Schema.define(version: 20160715134306) do
t.string "environment"
t.datetime "artifacts_expire_at"
t.integer "artifacts_size"
t.string "when"
t.text "yaml_variables"
end
add_index "ci_builds", ["commit_id", "stage_idx", "created_at"], name: "index_ci_builds_on_commit_id_and_stage_idx_and_created_at", using: :btree
......
......@@ -31,28 +31,34 @@ module Ci
raise ValidationError, e.message
end
def builds_for_stage_and_ref(stage, ref, tag = false, trigger_request = nil)
builds.select do |build|
build[:stage] == stage &&
process?(build[:only], build[:except], ref, tag, trigger_request)
def jobs_for_ref(ref, tag = false, trigger_request = nil)
@jobs.select do |_, job|
process?(job[:only], job[:except], ref, tag, trigger_request)
end
end
def builds
@jobs.map do |name, job|
build_job(name, job)
def jobs_for_stage_and_ref(stage, ref, tag = false, trigger_request = nil)
jobs_for_ref(ref, tag, trigger_request).select do |_, job|
job[:stage] == stage
end
end
def global_variables
@variables
def builds_for_ref(ref, tag = false, trigger_request = nil)
jobs_for_ref(ref, tag, trigger_request).map do |name, job|
build_job(name, job)
end
end
def job_variables(name)
job = @jobs[name.to_sym]
return [] unless job
def builds_for_stage_and_ref(stage, ref, tag = false, trigger_request = nil)
jobs_for_stage_and_ref(stage, ref, tag, trigger_request).map do |name, job|
build_job(name, job)
end
end
job[:variables] || []
def builds
@jobs.map do |name, job|
build_job(name, job)
end
end
private
......@@ -95,11 +101,10 @@ module Ci
commands: [job[:before_script] || @before_script, job[:script]].flatten.compact.join("\n"),
tag_list: job[:tags] || [],
name: name,
only: job[:only],
except: job[:except],
allow_failure: job[:allow_failure] || false,
when: job[:when] || 'on_success',
environment: job[:environment],
yaml_variables: yaml_variables(name),
options: {
image: job[:image] || @image,
services: job[:services] || @services,
......@@ -111,6 +116,24 @@ module Ci
}
end
def yaml_variables(name)
variables = global_variables.merge(job_variables(name))
variables.map do |key, value|
{ key: key, value: value, public: true }
end
end
def global_variables
@variables || {}
end
def job_variables(name)
job = @jobs[name.to_sym]
return {} unless job
job[:variables] || {}
end
def validate!
@jobs.each do |name, job|
validate_job!(name, job)
......
......@@ -15,6 +15,11 @@ FactoryGirl.define do
services: ["postgres"]
}
end
yaml_variables do
[
{ key: :DB_NAME, value: 'postgres', public: true }
]
end
pipeline factory: :ci_pipeline
......
......@@ -19,15 +19,14 @@ module Ci
expect(config_processor.builds_for_stage_and_ref(type, "master").first).to eq({
stage: "test",
stage_idx: 1,
except: nil,
name: :rspec,
only: nil,
commands: "pwd\nrspec",
tag_list: [],
options: {},
allow_failure: false,
when: "on_success",
environment: nil,
yaml_variables: []
})
end
......@@ -432,11 +431,9 @@ module Ci
expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1)
expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({
except: nil,
stage: "test",
stage_idx: 1,
name: :rspec,
only: nil,
commands: "pwd\nrspec",
tag_list: [],
options: {
......@@ -446,6 +443,7 @@ module Ci
allow_failure: false,
when: "on_success",
environment: nil,
yaml_variables: []
})
end
......@@ -461,11 +459,9 @@ module Ci
expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1)
expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({
except: nil,
stage: "test",
stage_idx: 1,
name: :rspec,
only: nil,
commands: "pwd\nrspec",
tag_list: [],
options: {
......@@ -475,101 +471,126 @@ module Ci
allow_failure: false,
when: "on_success",
environment: nil,
yaml_variables: []
})
end
end
describe 'Variables' do
context 'when global variables are defined' do
it 'returns global variables' do
variables = {
VAR1: 'value1',
VAR2: 'value2',
}
let(:config_processor) { GitlabCiYamlProcessor.new(YAML.dump(config), path) }
config = YAML.dump({
subject { config_processor.builds.first[:yaml_variables] }
context 'when global variables are defined' do
let(:variables) do
{ VAR1: 'value1', VAR2: 'value2' }
end
let(:config) do
{
variables: variables,
before_script: ['pwd'],
rspec: { script: 'rspec' }
})
}
end
config_processor = GitlabCiYamlProcessor.new(config, path)
it 'returns global variables' do
expect(subject).to contain_exactly(
{ key: :VAR1, value: 'value1', public: true },
{ key: :VAR2, value: 'value2', public: true }
)
end
end
expect(config_processor.global_variables).to eq(variables)
context 'when job and global variables are defined' do
let(:global_variables) do
{ VAR1: 'global1', VAR3: 'global3' }
end
let(:job_variables) do
{ VAR1: 'value1', VAR2: 'value2' }
end
let(:config) do
{
before_script: ['pwd'],
variables: global_variables,
rspec: { script: 'rspec', variables: job_variables }
}
end
it 'returns all unique variables' do
expect(subject).to contain_exactly(
{ key: :VAR3, value: 'global3', public: true },
{ key: :VAR1, value: 'value1', public: true },
{ key: :VAR2, value: 'value2', public: true }
)
end
end
context 'when job variables are defined' do
context 'when syntax is correct' do
it 'returns job variables' do
variables = {
KEY1: 'value1',
SOME_KEY_2: 'value2'
let(:config) do
{
before_script: ['pwd'],
rspec: { script: 'rspec', variables: variables }
}
end
config = YAML.dump(
{ before_script: ['pwd'],
rspec: {
variables: variables,
script: 'rspec' }
})
context 'when also global variables are defined' do
config_processor = GitlabCiYamlProcessor.new(config, path)
end
expect(config_processor.job_variables(:rspec)).to eq variables
context 'when syntax is correct' do
let(:variables) do
{ VAR1: 'value1', VAR2: 'value2' }
end
it 'returns job variables' do
expect(subject).to contain_exactly(
{ key: :VAR1, value: 'value1', public: true },
{ key: :VAR2, value: 'value2', public: true }
)
end
end
context 'when syntax is incorrect' do
context 'when variables defined but invalid' do
it 'raises error' do
variables = [:KEY1, 'value1', :KEY2, 'value2']
config = YAML.dump(
{ before_script: ['pwd'],
rspec: {
variables: variables,
script: 'rspec' }
})
let(:variables) do
[ :VAR1, 'value1', :VAR2, 'value2' ]
end
expect { GitlabCiYamlProcessor.new(config, path) }
it 'raises error' do
expect { subject }
.to raise_error(GitlabCiYamlProcessor::ValidationError,
/job: variables should be a map/)
end
end
context 'when variables key defined but value not specified' do
it 'returns empty array' do
config = YAML.dump(
{ before_script: ['pwd'],
rspec: {
variables: nil,
script: 'rspec' }
})
config_processor = GitlabCiYamlProcessor.new(config, path)
let(:variables) do
nil
end
it 'returns empty array' do
##
# When variables config is empty, we assume this is a valid
# configuration, see issue #18775
#
expect(config_processor.job_variables(:rspec))
.to be_an_instance_of(Array).and be_empty
expect(subject).to be_an_instance_of(Array)
expect(subject).to be_empty
end
end
end
end
context 'when job variables are not defined' do
it 'returns empty array' do
config = YAML.dump({
let(:config) do
{
before_script: ['pwd'],
rspec: { script: 'rspec' }
})
config_processor = GitlabCiYamlProcessor.new(config, path)
}
end
expect(config_processor.job_variables(:rspec)).to eq []
it 'returns empty array' do
expect(subject).to be_an_instance_of(Array)
expect(subject).to be_empty
end
end
end
......@@ -681,11 +702,9 @@ module Ci
expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1)
expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({
except: nil,
stage: "test",
stage_idx: 1,
name: :rspec,
only: nil,
commands: "pwd\nrspec",
tag_list: [],
options: {
......@@ -701,6 +720,7 @@ module Ci
when: "on_success",
allow_failure: false,
environment: nil,
yaml_variables: []
})
end
......@@ -819,17 +839,16 @@ module Ci
it "doesn't create jobs that start with dot" do
expect(subject.size).to eq(1)
expect(subject.first).to eq({
except: nil,
stage: "test",
stage_idx: 1,
name: :normal_job,
only: nil,
commands: "test",
tag_list: [],
options: {},
when: "on_success",
allow_failure: false,
environment: nil,
yaml_variables: []
})
end
end
......@@ -865,30 +884,28 @@ module Ci
it "is correctly supported for jobs" do
expect(subject.size).to eq(2)
expect(subject.first).to eq({
except: nil,
stage: "build",
stage_idx: 0,
name: :job1,
only: nil,
commands: "execute-script-for-job",
tag_list: [],
options: {},
when: "on_success",
allow_failure: false,
environment: nil,
yaml_variables: []
})
expect(subject.second).to eq({
except: nil,
stage: "build",
stage_idx: 0,
name: :job2,
only: nil,
commands: "execute-script-for-job",
tag_list: [],
options: {},
when: "on_success",
allow_failure: false,
environment: nil,
yaml_variables: []
})
end
end
......
......@@ -208,7 +208,7 @@ describe Ci::Build, models: true do
end
before do
build.update_attributes(stage: 'stage')
build.update_attributes(stage: 'stage', yaml_variables: yaml_variables)
end
it { is_expected.to eq(predefined_variables + yaml_variables) }
......@@ -260,22 +260,6 @@ describe Ci::Build, models: true do
it { is_expected.to eq(predefined_variables + predefined_trigger_variable + yaml_variables + secure_variables + trigger_variables) }
end
context 'when job variables are defined' do
##
# Job-level variables are defined in gitlab_ci.yml fixture
#
context 'when job variables are unique' do
let(:build) { create(:ci_build, name: 'staging') }
it 'includes job variables' do
expect(subject).to include(
{ key: :KEY1, value: 'value1', public: true },
{ key: :KEY2, value: 'value2', public: true }
)
end
end
end
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