Commit b9c42a28 authored by Kamil Trzciński's avatar Kamil Trzciński

Merge branch 'improve-error-messages-for-ci-job-entries' into 'master'

Improve error message for job configs that fail to match an entry

See merge request gitlab-org/gitlab!40120
parents 1a4cdc25 1799495f
...@@ -122,39 +122,9 @@ module Gitlab ...@@ -122,39 +122,9 @@ module Gitlab
:needs, :retry, :parallel, :start_in, :needs, :retry, :parallel, :start_in,
:interruptible, :timeout, :resource_group, :release :interruptible, :timeout, :resource_group, :release
Matcher = Struct.new(:name, :config) do
def applies?
job_is_not_hidden? &&
config_is_a_hash? &&
has_job_keys?
end
private
def job_is_not_hidden?
!name.to_s.start_with?('.')
end
def config_is_a_hash?
config.is_a?(Hash)
end
def has_job_keys?
if name == :default
config.key?(:script)
else
(ALLOWED_KEYS & config.keys).any?
end
end
end
def self.matching?(name, config) def self.matching?(name, config)
if Gitlab::Ci::Features.job_entry_matches_all_keys? !name.to_s.start_with?('.') &&
Matcher.new(name, config).applies? config.is_a?(Hash) && config.key?(:script)
else
!name.to_s.start_with?('.') &&
config.is_a?(Hash) && config.key?(:script)
end
end end
def self.visible? def self.visible?
......
...@@ -14,8 +14,8 @@ module Gitlab ...@@ -14,8 +14,8 @@ module Gitlab
validates :config, type: Hash validates :config, type: Hash
validate do validate do
unless has_valid_jobs? each_unmatched_job do |name|
errors.add(:config, 'should contain valid jobs') errors.add(name, 'config should implement a script: or a trigger: keyword')
end end
unless has_visible_job? unless has_visible_job?
...@@ -23,9 +23,9 @@ module Gitlab ...@@ -23,9 +23,9 @@ module Gitlab
end end
end end
def has_valid_jobs? def each_unmatched_job
config.all? do |name, value| config.each do |name, value|
Jobs.find_type(name, value) yield(name) unless Jobs.find_type(name, value)
end end
end end
......
...@@ -134,7 +134,7 @@ module Gitlab ...@@ -134,7 +134,7 @@ module Gitlab
@jobs_config = @config @jobs_config = @config
.except(*self.class.reserved_nodes_names) .except(*self.class.reserved_nodes_names)
.select do |name, config| .select do |name, config|
Entry::Jobs.find_type(name, config).present? Entry::Jobs.find_type(name, config).present? || ALLOWED_KEYS.exclude?(name)
end end
@config = @config.except(*@jobs_config.keys) @config = @config.except(*@jobs_config.keys)
......
...@@ -64,10 +64,6 @@ module Gitlab ...@@ -64,10 +64,6 @@ module Gitlab
::Feature.enabled?(:ci_plan_needs_size_limit, project, default_enabled: true) ::Feature.enabled?(:ci_plan_needs_size_limit, project, default_enabled: true)
end end
def self.job_entry_matches_all_keys?
::Feature.enabled?(:ci_job_entry_matches_all_keys)
end
def self.lint_creates_pipeline_with_dry_run?(project) def self.lint_creates_pipeline_with_dry_run?(project)
::Feature.enabled?(:ci_lint_creates_pipeline_with_dry_run, project, default_enabled: true) ::Feature.enabled?(:ci_lint_creates_pipeline_with_dry_run, project, default_enabled: true)
end end
......
...@@ -150,7 +150,10 @@ RSpec.describe Projects::Ci::LintsController do ...@@ -150,7 +150,10 @@ RSpec.describe Projects::Ci::LintsController do
it 'assigns result with errors' do it 'assigns result with errors' do
subject subject
expect(assigns[:result].errors).to eq(['root config contains unknown keys: rubocop']) expect(assigns[:result].errors).to match_array([
'jobs rubocop config should implement a script: or a trigger: keyword',
'jobs config should contain at least one visible job'
])
end end
context 'with dry_run mode' do context 'with dry_run mode' do
...@@ -159,7 +162,7 @@ RSpec.describe Projects::Ci::LintsController do ...@@ -159,7 +162,7 @@ RSpec.describe Projects::Ci::LintsController do
it 'assigns result with errors' do it 'assigns result with errors' do
subject subject
expect(assigns[:result].errors).to eq(['root config contains unknown keys: rubocop']) expect(assigns[:result].errors).to eq(['jobs rubocop config should implement a script: or a trigger: keyword'])
end end
end end
end end
......
...@@ -74,16 +74,6 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job do ...@@ -74,16 +74,6 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job do
it { is_expected.to be_falsey } it { is_expected.to be_falsey }
end end
context 'when config does not contain script' do
let(:name) { :build }
let(:config) do
{ before_script: "cd ${PROJ_DIR} " }
end
it { is_expected.to be_truthy }
end
context 'when using the default job without script' do context 'when using the default job without script' do
let(:name) { :default } let(:name) { :default }
let(:config) do let(:config) do
...@@ -104,14 +94,6 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job do ...@@ -104,14 +94,6 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job do
it { is_expected.to be_truthy } it { is_expected.to be_truthy }
end end
context 'there are no shared keys between jobs and bridges' do
subject(:shared_values) do
described_class::ALLOWED_KEYS & Gitlab::Ci::Config::Entry::Bridge::ALLOWED_KEYS
end
it { is_expected.to be_empty }
end
end end
describe 'validations' do describe 'validations' do
......
...@@ -68,7 +68,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Jobs do ...@@ -68,7 +68,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Jobs do
let(:config) { { rspec: nil } } let(:config) { { rspec: nil } }
it 'reports error' do it 'reports error' do
expect(entry.errors).to include "jobs config should contain valid jobs" expect(entry.errors).to include 'jobs rspec config should implement a script: or a trigger: keyword'
end end
end end
......
...@@ -344,9 +344,9 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do ...@@ -344,9 +344,9 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
end end
describe '#errors' do describe '#errors' do
it 'reports errors about missing script' do it 'reports errors about missing script or trigger' do
expect(root.errors) expect(root.errors)
.to include "root config contains unknown keys: rspec" .to include 'jobs rspec config should implement a script: or a trigger: keyword'
end end
end end
end end
......
...@@ -72,7 +72,7 @@ RSpec.describe Gitlab::Ci::Lint do ...@@ -72,7 +72,7 @@ RSpec.describe Gitlab::Ci::Lint do
it 'returns a result with errors' do it 'returns a result with errors' do
expect(subject).not_to be_valid expect(subject).not_to be_valid
expect(subject.errors).to include(/root config contains unknown keys/) expect(subject.errors).to include(/jobs build config should implement a script: or a trigger: keyword/)
end end
end end
......
...@@ -2409,7 +2409,7 @@ module Gitlab ...@@ -2409,7 +2409,7 @@ module Gitlab
context 'returns error if job configuration is invalid' do context 'returns error if job configuration is invalid' do
let(:config) { YAML.dump({ extra: "bundle update" }) } let(:config) { YAML.dump({ extra: "bundle update" }) }
it_behaves_like 'returns errors', 'root config contains unknown keys: extra' it_behaves_like 'returns errors', 'jobs extra config should implement a script: or a trigger: keyword'
end end
context 'returns errors if services configuration is not correct' do context 'returns errors if services configuration is not correct' do
...@@ -2427,7 +2427,7 @@ module Gitlab ...@@ -2427,7 +2427,7 @@ module Gitlab
context 'returns errors if the job script is not defined' do context 'returns errors if the job script is not defined' do
let(:config) { YAML.dump({ rspec: { before_script: "test" } }) } let(:config) { YAML.dump({ rspec: { before_script: "test" } }) }
it_behaves_like 'returns errors', "jobs:rspec script can't be blank" it_behaves_like 'returns errors', 'jobs rspec config should implement a script: or a trigger: keyword'
end end
context 'returns errors if there are no visible jobs defined' do context 'returns errors if there are no visible jobs defined' do
......
...@@ -101,7 +101,7 @@ RSpec.describe Ci::CreatePipelineService do ...@@ -101,7 +101,7 @@ RSpec.describe Ci::CreatePipelineService do
end end
it 'contains only errors' do it 'contains only errors' do
error_message = 'root config contains unknown keys: invalid' error_message = 'jobs invalid config should implement a script: or a trigger: keyword'
expect(pipeline.yaml_errors).to eq(error_message) expect(pipeline.yaml_errors).to eq(error_message)
expect(pipeline.error_messages.map(&:content)).to contain_exactly(error_message) expect(pipeline.error_messages.map(&:content)).to contain_exactly(error_message)
expect(pipeline.errors.full_messages).to contain_exactly(error_message) expect(pipeline.errors.full_messages).to contain_exactly(error_message)
......
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