1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
# frozen_string_literal: true
module Gitlab
module Ci
class Lint
class Result
attr_reader :jobs, :merged_yaml, :errors, :warnings
def initialize(jobs:, merged_yaml:, errors:, warnings:)
@jobs = jobs
@merged_yaml = merged_yaml
@errors = errors
@warnings = warnings
end
def valid?
@errors.empty?
end
end
def initialize(project:, current_user:, sha: nil)
@project = project
@current_user = current_user
@sha = sha || project&.repository&.commit&.sha
end
def validate(content, dry_run: false)
if dry_run
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)
.payload
Result.new(
jobs: dry_run_convert_to_jobs(pipeline.stages),
merged_yaml: pipeline.merged_yaml,
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: @sha
).execute
Result.new(
jobs: static_validation_convert_to_jobs(result),
merged_yaml: result.merged_yaml,
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],
needs: job.dig(:needs_attributes)
}
end
end
jobs
end
end
end
end
|