debian-mirror-gitlab/lib/ci/gitlab_ci_yaml_processor.rb

217 lines
6 KiB
Ruby
Raw Normal View History

2015-09-25 12:07:36 +05:30
module Ci
class GitlabCiYamlProcessor
2017-08-17 22:00:37 +05:30
ValidationError = Class.new(StandardError)
2017-08-17 22:00:37 +05:30
include Gitlab::Ci::Config::Entry::LegacyValidationHelpers
2015-09-25 12:07:36 +05:30
2016-11-03 12:29:30 +05:30
attr_reader :path, :cache, :stages, :jobs
2015-09-25 12:07:36 +05:30
2015-11-26 14:37:03 +05:30
def initialize(config, path = nil)
@ci_config = Gitlab::Ci::Config.new(config)
@config = @ci_config.to_hash
@path = path
2015-09-25 12:07:36 +05:30
2016-08-24 12:49:21 +05:30
unless @ci_config.valid?
raise ValidationError, @ci_config.errors.first
end
2015-09-25 12:07:36 +05:30
2016-08-24 12:49:21 +05:30
initial_parsing
rescue Gitlab::Ci::Config::Loader::FormatError => e
raise ValidationError, e.message
2015-09-25 12:07:36 +05:30
end
2016-08-24 12:49:21 +05:30
def jobs_for_ref(ref, tag = false, trigger_request = nil)
@jobs.select do |_, job|
process?(job[:only], job[:except], ref, tag, trigger_request)
2016-06-22 15:30:34 +05:30
end
2015-09-25 12:07:36 +05:30
end
2016-08-24 12:49:21 +05:30
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
2015-09-25 12:07:36 +05:30
end
end
2016-08-24 12:49:21 +05:30
def builds_for_ref(ref, tag = false, trigger_request = nil)
jobs_for_ref(ref, tag, trigger_request).map do |name, _|
build_attributes(name)
end
2016-06-02 11:05:42 +05:30
end
2016-08-24 12:49:21 +05:30
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, _|
build_attributes(name)
end
2016-06-02 11:05:42 +05:30
end
2015-09-25 12:07:36 +05:30
2016-08-24 12:49:21 +05:30
def builds
@jobs.map do |name, _|
build_attributes(name)
end
2015-09-25 12:07:36 +05:30
end
2016-08-24 12:49:21 +05:30
def build_attributes(name)
job = @jobs[name.to_sym] || {}
2015-09-25 12:07:36 +05:30
{
2016-08-24 12:49:21 +05:30
stage_idx: @stages.index(job[:stage]),
2015-09-25 12:07:36 +05:30
stage: job[:stage],
2016-09-29 09:46:39 +05:30
commands: job[:commands],
2015-10-24 18:46:33 +05:30
tag_list: job[:tags] || [],
2016-09-13 17:45:13 +05:30
name: job[:name].to_s,
2017-08-17 22:00:37 +05:30
allow_failure: job[:ignore],
2015-10-24 18:46:33 +05:30
when: job[:when] || 'on_success',
2016-09-29 09:46:39 +05:30
environment: job[:environment_name],
2017-08-17 22:00:37 +05:30
coverage_regex: job[:coverage],
2016-08-24 12:49:21 +05:30
yaml_variables: yaml_variables(name),
2015-09-25 12:07:36 +05:30
options: {
2016-09-29 09:46:39 +05:30
image: job[:image],
services: job[:services],
2015-11-26 14:37:03 +05:30
artifacts: job[:artifacts],
2016-09-29 09:46:39 +05:30
cache: job[:cache],
2016-06-02 11:05:42 +05:30
dependencies: job[:dependencies],
2016-09-29 09:46:39 +05:30
after_script: job[:after_script],
environment: job[:environment],
2015-09-25 12:07:36 +05:30
}.compact
}
end
2016-09-29 09:46:39 +05:30
def self.validation_message(content)
return 'Please provide content of .gitlab-ci.yml' if content.blank?
begin
Ci::GitlabCiYamlProcessor.new(content)
nil
rescue ValidationError, Psych::SyntaxError => e
e.message
end
end
2016-08-24 12:49:21 +05:30
private
2016-08-24 12:49:21 +05:30
def initial_parsing
2016-09-13 17:45:13 +05:30
##
# Global config
#
2016-08-24 12:49:21 +05:30
@before_script = @ci_config.before_script
@image = @ci_config.image
@after_script = @ci_config.after_script
@services = @ci_config.services
@variables = @ci_config.variables
@stages = @ci_config.stages
@cache = @ci_config.cache
2016-06-02 11:05:42 +05:30
2016-09-13 17:45:13 +05:30
##
# Jobs
#
@jobs = @ci_config.jobs
2015-09-25 12:07:36 +05:30
2016-09-13 17:45:13 +05:30
@jobs.each do |name, job|
# logical validation for job
2015-09-25 12:07:36 +05:30
2016-09-13 17:45:13 +05:30
validate_job_stage!(name, job)
validate_job_dependencies!(name, job)
2016-11-03 12:29:30 +05:30
validate_job_environment!(name, job)
2016-09-13 17:45:13 +05:30
end
2016-08-24 12:49:21 +05:30
end
2015-09-25 12:07:36 +05:30
2016-08-24 12:49:21 +05:30
def yaml_variables(name)
2016-09-13 17:45:13 +05:30
variables = (@variables || {})
.merge(job_variables(name))
2016-08-24 12:49:21 +05:30
variables.map do |key, value|
2017-08-17 22:00:37 +05:30
{ key: key.to_s, value: value, public: true }
2015-09-25 12:07:36 +05:30
end
2016-08-24 12:49:21 +05:30
end
2015-09-25 12:07:36 +05:30
2016-08-24 12:49:21 +05:30
def job_variables(name)
job = @jobs[name.to_sym]
return {} unless job
2016-08-24 12:49:21 +05:30
job[:variables] || {}
end
2015-11-26 14:37:03 +05:30
2015-12-23 02:04:40 +05:30
def validate_job_stage!(name, job)
2016-09-13 17:45:13 +05:30
return unless job[:stage]
2016-08-24 12:49:21 +05:30
unless job[:stage].is_a?(String) && job[:stage].in?(@stages)
raise ValidationError, "#{name} job: stage parameter should be #{@stages.join(", ")}"
2015-11-26 14:37:03 +05:30
end
2015-12-23 02:04:40 +05:30
end
2015-11-26 14:37:03 +05:30
2016-06-02 11:05:42 +05:30
def validate_job_dependencies!(name, job)
2016-09-13 17:45:13 +05:30
return unless job[:dependencies]
2016-06-02 11:05:42 +05:30
2016-08-24 12:49:21 +05:30
stage_index = @stages.index(job[:stage])
2016-06-02 11:05:42 +05:30
job[:dependencies].each do |dependency|
raise ValidationError, "#{name} job: undefined dependency: #{dependency}" unless @jobs[dependency.to_sym]
2016-08-24 12:49:21 +05:30
unless @stages.index(@jobs[dependency.to_sym][:stage]) < stage_index
2016-06-02 11:05:42 +05:30
raise ValidationError, "#{name} job: dependency #{dependency} is not defined in prior stages"
end
end
end
2016-11-03 12:29:30 +05:30
def validate_job_environment!(name, job)
return unless job[:environment]
return unless job[:environment].is_a?(Hash)
environment = job[:environment]
validate_on_stop_job!(name, environment, environment[:on_stop])
end
def validate_on_stop_job!(name, environment, on_stop)
return unless on_stop
on_stop_job = @jobs[on_stop.to_sym]
unless on_stop_job
raise ValidationError, "#{name} job: on_stop job #{on_stop} is not defined"
end
unless on_stop_job[:environment]
raise ValidationError, "#{name} job: on_stop job #{on_stop} does not have environment defined"
end
unless on_stop_job[:environment][:name] == environment[:name]
raise ValidationError, "#{name} job: on_stop job #{on_stop} have different environment name"
end
unless on_stop_job[:environment][:action] == 'stop'
raise ValidationError, "#{name} job: on_stop job #{on_stop} needs to have action stop defined"
end
end
2016-06-02 11:05:42 +05:30
def process?(only_params, except_params, ref, tag, trigger_request)
2015-11-26 14:37:03 +05:30
if only_params.present?
2016-06-02 11:05:42 +05:30
return false unless matching?(only_params, ref, tag, trigger_request)
2015-11-26 14:37:03 +05:30
end
if except_params.present?
2016-06-02 11:05:42 +05:30
return false if matching?(except_params, ref, tag, trigger_request)
2015-11-26 14:37:03 +05:30
end
true
end
2016-06-02 11:05:42 +05:30
def matching?(patterns, ref, tag, trigger_request)
2015-11-26 14:37:03 +05:30
patterns.any? do |pattern|
2016-06-02 11:05:42 +05:30
match_ref?(pattern, ref, tag, trigger_request)
2015-11-26 14:37:03 +05:30
end
end
2016-06-02 11:05:42 +05:30
def match_ref?(pattern, ref, tag, trigger_request)
2015-11-26 14:37:03 +05:30
pattern, path = pattern.split('@', 2)
return false if path && path != self.path
return true if tag && pattern == 'tags'
return true if !tag && pattern == 'branches'
2016-06-02 11:05:42 +05:30
return true if trigger_request.present? && pattern == 'triggers'
2015-11-26 14:37:03 +05:30
if pattern.first == "/" && pattern.last == "/"
Regexp.new(pattern[1...-1]) =~ ref
else
pattern == ref
end
2015-09-25 12:07:36 +05:30
end
end
end