summaryrefslogtreecommitdiff
path: root/lib/ci/gitlab_ci_yaml_processor.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ci/gitlab_ci_yaml_processor.rb')
-rw-r--r--lib/ci/gitlab_ci_yaml_processor.rb251
1 files changed, 0 insertions, 251 deletions
diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb
deleted file mode 100644
index 62b44389b15..00000000000
--- a/lib/ci/gitlab_ci_yaml_processor.rb
+++ /dev/null
@@ -1,251 +0,0 @@
-module Ci
- class GitlabCiYamlProcessor
- ValidationError = Class.new(StandardError)
-
- include Gitlab::Ci::Config::Entry::LegacyValidationHelpers
-
- attr_reader :path, :cache, :stages, :jobs
-
- def initialize(config, path = nil)
- @ci_config = Gitlab::Ci::Config.new(config)
- @config = @ci_config.to_hash
- @path = path
-
- unless @ci_config.valid?
- raise ValidationError, @ci_config.errors.first
- end
-
- initial_parsing
- rescue Gitlab::Ci::Config::Loader::FormatError => e
- raise ValidationError, e.message
- end
-
- def builds_for_stage_and_ref(stage, ref, tag = false, source = nil)
- jobs_for_stage_and_ref(stage, ref, tag, source).map do |name, _|
- build_attributes(name)
- end
- end
-
- def builds
- @jobs.map do |name, _|
- build_attributes(name)
- end
- end
-
- def stage_seeds(pipeline)
- seeds = @stages.uniq.map do |stage|
- builds = pipeline_stage_builds(stage, pipeline)
-
- Gitlab::Ci::Stage::Seed.new(pipeline, stage, builds) if builds.any?
- end
-
- seeds.compact
- end
-
- def build_attributes(name)
- job = @jobs[name.to_sym] || {}
-
- { stage_idx: @stages.index(job[:stage]),
- stage: job[:stage],
- commands: job[:commands],
- tag_list: job[:tags] || [],
- name: job[:name].to_s,
- allow_failure: job[:ignore],
- when: job[:when] || 'on_success',
- environment: job[:environment_name],
- coverage_regex: job[:coverage],
- yaml_variables: yaml_variables(name),
- options: {
- image: job[:image],
- services: job[:services],
- artifacts: job[:artifacts],
- cache: job[:cache],
- dependencies: job[:dependencies],
- before_script: job[:before_script],
- script: job[:script],
- after_script: job[:after_script],
- environment: job[:environment],
- retry: job[:retry]
- }.compact }
- end
-
- 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
-
- private
-
- def pipeline_stage_builds(stage, pipeline)
- builds = builds_for_stage_and_ref(
- stage, pipeline.ref, pipeline.tag?, pipeline.source)
-
- builds.select do |build|
- job = @jobs[build.fetch(:name).to_sym]
- has_kubernetes = pipeline.has_kubernetes_active?
- only_kubernetes = job.dig(:only, :kubernetes)
- except_kubernetes = job.dig(:except, :kubernetes)
-
- [!only_kubernetes && !except_kubernetes,
- only_kubernetes && has_kubernetes,
- except_kubernetes && !has_kubernetes].any?
- end
- end
-
- def jobs_for_ref(ref, tag = false, source = nil)
- @jobs.select do |_, job|
- process?(job.dig(:only, :refs), job.dig(:except, :refs), ref, tag, source)
- end
- end
-
- def jobs_for_stage_and_ref(stage, ref, tag = false, source = nil)
- jobs_for_ref(ref, tag, source).select do |_, job|
- job[:stage] == stage
- end
- end
-
- def initial_parsing
- ##
- # Global config
- #
- @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
-
- ##
- # Jobs
- #
- @jobs = @ci_config.jobs
-
- @jobs.each do |name, job|
- # logical validation for job
-
- validate_job_stage!(name, job)
- validate_job_dependencies!(name, job)
- validate_job_environment!(name, job)
- end
- end
-
- def yaml_variables(name)
- variables = (@variables || {})
- .merge(job_variables(name))
-
- variables.map do |key, value|
- { key: key.to_s, value: value, public: true }
- end
- end
-
- def job_variables(name)
- job = @jobs[name.to_sym]
- return {} unless job
-
- job[:variables] || {}
- end
-
- def validate_job_stage!(name, job)
- return unless job[:stage]
-
- unless job[:stage].is_a?(String) && job[:stage].in?(@stages)
- raise ValidationError, "#{name} job: stage parameter should be #{@stages.join(", ")}"
- end
- end
-
- def validate_job_dependencies!(name, job)
- return unless job[:dependencies]
-
- stage_index = @stages.index(job[:stage])
-
- job[:dependencies].each do |dependency|
- raise ValidationError, "#{name} job: undefined dependency: #{dependency}" unless @jobs[dependency.to_sym]
-
- unless @stages.index(@jobs[dependency.to_sym][:stage]) < stage_index
- raise ValidationError, "#{name} job: dependency #{dependency} is not defined in prior stages"
- end
- end
- end
-
- 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
-
- def process?(only_params, except_params, ref, tag, source)
- if only_params.present?
- return false unless matching?(only_params, ref, tag, source)
- end
-
- if except_params.present?
- return false if matching?(except_params, ref, tag, source)
- end
-
- true
- end
-
- def matching?(patterns, ref, tag, source)
- patterns.any? do |pattern|
- pattern, path = pattern.split('@', 2)
- matches_path?(path) && matches_pattern?(pattern, ref, tag, source)
- end
- end
-
- def matches_path?(path)
- return true unless path
-
- path == self.path
- end
-
- def matches_pattern?(pattern, ref, tag, source)
- return true if tag && pattern == 'tags'
- return true if !tag && pattern == 'branches'
- return true if source_to_pattern(source) == pattern
-
- if pattern.first == "/" && pattern.last == "/"
- Regexp.new(pattern[1...-1]) =~ ref
- else
- pattern == ref
- end
- end
-
- def source_to_pattern(source)
- if %w[api external web].include?(source)
- source
- else
- source&.pluralize
- end
- end
- end
-end