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
|
#!/usr/bin/env ruby
# frozen_string_literal: true
require_relative '../config/environment'
require 'open3'
module LintTemplatesBash
module_function
EXCLUDED_RULES = [
"SC2046", "SC2086", # will be fixed later: https://gitlab.com/gitlab-org/gitlab/-/issues/352973
"SC1090", "SC1091", # we do not have access to sourced files for analysis.
"SC2154", # Referencing undefined variables is common and adding per-line exceptions for them is unintuitive for end-users
"SC2164" # CI/CD automatically fails if attempting to change to a directory which does not exist.
].join(",").freeze
EXCLUDED_TEMPLATES = [
"dotNET.gitlab-ci.yml" # Powershell
].freeze
def run
failed_templates = Gitlab::Template::GitlabCiYmlTemplate.all.filter_map do |template|
next if EXCLUDED_TEMPLATES.include?(template.full_name)
success = check_template(template)
template.full_name unless success
end
if failed_templates.any?
puts "The following templates have shellcheck violations:"
puts failed_templates.join("\n")
exit 1
end
end
def process_content(content)
Gitlab::Ci::YamlProcessor.new(content).execute
end
def job_script(job)
parts = [:before_script, :script, :after_script].map do |key|
job[key]&.join("\n")
end.compact
parts.prepend("#!/bin/bash\n").join("\n")
end
def shellcheck(script_content)
combined_streams, status = Open3.capture2e("shellcheck --exclude='#{EXCLUDED_RULES}' -", stdin_data: script_content)
[combined_streams, status.success?]
end
def check_job(job)
shellcheck(job_script(job))
end
def check_template(template)
parsed = process_content(template.content)
unless parsed.valid?
warn "#{template.full_name} is invalid: #{parsed.errors.inspect}"
return true
end
results = parsed.jobs.map do |name, job|
out, success = check_job(job)
unless success
puts "The '#{name}' job in #{template.full_name} has shellcheck failures:"
puts out
end
success
end
results.all?
end
end
LintTemplatesBash.run
|