# frozen_string_literal: true module Gitlab module Ci class Lint class Result attr_reader :jobs, :errors, :warnings def initialize(jobs:, errors:, warnings:) @jobs = jobs @errors = errors @warnings = warnings end def valid? @errors.empty? end end def initialize(project:, current_user:) @project = project @current_user = current_user end def validate(content, dry_run: false) if dry_run && Gitlab::Ci::Features.lint_creates_pipeline_with_dry_run?(@project) simulate_pipeline_creation(content) else static_validation(content) end end private def simulate_pipeline_creation(content) pipeline = ::Ci::CreatePipelineService .new(@project, @current_user, ref: @project.default_branch) .execute(:push, dry_run: true, content: content) Result.new( jobs: dry_run_convert_to_jobs(pipeline.stages), errors: pipeline.error_messages.map(&:content), warnings: pipeline.warning_messages(limit: ::Gitlab::Ci::Warnings::MAX_LIMIT).map(&:content) ) end def static_validation(content) result = Gitlab::Ci::YamlProcessor.new( content, project: @project, user: @current_user, sha: @project.repository.commit.sha ).execute Result.new( jobs: static_validation_convert_to_jobs(result), errors: result.errors, warnings: result.warnings.take(::Gitlab::Ci::Warnings::MAX_LIMIT) # rubocop: disable CodeReuse/ActiveRecord ) end def dry_run_convert_to_jobs(stages) stages.reduce([]) do |jobs, stage| jobs + stage.statuses.map do |job| { name: job.name, stage: stage.name, before_script: job.options[:before_script].to_a, script: job.options[:script].to_a, after_script: job.options[:after_script].to_a, tag_list: (job.tag_list if job.is_a?(::Ci::Build)).to_a, environment: job.options.dig(:environment, :name), when: job.when, allow_failure: job.allow_failure } end end end def static_validation_convert_to_jobs(result) jobs = [] return jobs unless result.valid? result.stages.each do |stage_name| result.builds.each do |job| next unless job[:stage] == stage_name jobs << { name: job[:name], stage: stage_name, before_script: job.dig(:options, :before_script).to_a, script: job.dig(:options, :script).to_a, after_script: job.dig(:options, :after_script).to_a, tag_list: job[:tag_list].to_a, only: job[:only], except: job[:except], environment: job[:environment], when: job[:when], allow_failure: job[:allow_failure] } end end jobs end end end end