2022-05-07 20:08:51 +05:30
|
|
|
#!/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)
|
2023-01-13 00:05:48 +05:30
|
|
|
|
|
|
|
unless parsed.valid?
|
|
|
|
warn "#{template.full_name} is invalid: #{parsed.errors.inspect}"
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
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
|