Class: PuppetLint::Bin

Inherits:
Object
  • Object
show all
Defined in:
lib/puppet-lint/bin.rb

Overview

Internal: The logic of the puppet-lint bin script, contained in a class for ease of testing.

Instance Method Summary collapse

Constructor Details

#initialize(args) ⇒ Bin

Public: Initialise a new PuppetLint::Bin.

args - An Array of command line argument Strings to be passed to the option

parser.

Examples

PuppetLint::Bin.new(ARGV).run


17
18
19
# File 'lib/puppet-lint/bin.rb', line 17

def initialize(args)
  @args = args
end

Instance Method Details

#report_sarif(problems, base_path, base_path_uri) ⇒ Object

Internal: Print the reported problems in SARIF format to stdout.

problems - An Array of problem Hashes as returned by

PuppetLint::Checks#run.

Returns nothing.



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/puppet-lint/bin.rb', line 122

def report_sarif(problems, base_path, base_path_uri)
  sarif_file = File.read(File.join(__dir__, 'report', 'sarif_template.json'))
  sarif = JSON.parse(sarif_file)
  sarif['runs'][0]['originalUriBaseIds']['ROOTPATH']['uri'] = base_path_uri
  rules = sarif['runs'][0]['tool']['driver']['rules'] = []
  results = sarif['runs'][0]['results'] = []
  problems.each do |messages|
    messages.each do |message|
      relative_path = Pathname.new(message[:fullpath]).relative_path_from(Pathname.new(base_path))
      rules = sarif['runs'][0]['tool']['driver']['rules']
      rule_exists = rules.any? { |r| r['id'] == message[:check] }
      unless rule_exists
        new_rule = { 'id' => message[:check] }
        new_rule['fullDescription'] = { 'text' => message[:description] } unless message[:description].nil?
        new_rule['fullDescription'] = { 'text' => 'Check for any syntax error and record an error of each instance found.' } if new_rule['fullDescription'].nil? && message[:check] == :syntax
        new_rule['defaultConfiguration'] = { 'level' => message[:KIND].downcase } if ['error', 'warning'].include?(message[:KIND].downcase)
        new_rule['helpUri'] = message[:help_uri] unless message[:help_uri].nil?
        rules << new_rule
      end
      rule_index = rules.index { |r| r['id'] == message[:check] }
      result = {
        'ruleId' => message[:check],
        'ruleIndex' => rule_index,
        'message' => { 'text' => message[:message] },
        'locations' => [{ 'physicalLocation' => { 'artifactLocation' => { 'uri' => relative_path, 'uriBaseId' => 'ROOTPATH' },
                                                  'region' => { 'startLine' => message[:line], 'startColumn' => message[:column] } } }]
      }
      results << result
    end
  end
  puts JSON.pretty_generate(sarif)
end

#runObject

Public: Run puppet-lint as a command line tool.

Returns an Integer exit code to be passed back to the shell.



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
# File 'lib/puppet-lint/bin.rb', line 24

def run
  begin
    opts = PuppetLint::OptParser.build(@args)
    opts.parse!(@args)
  rescue OptionParser::InvalidOption => e
    puts "puppet-lint: #{e.message}"
    puts "puppet-lint: try 'puppet-lint --help' for more information"
    return 1
  end

  if PuppetLint.configuration.display_version
    puts "puppet-lint #{PuppetLint::VERSION}"
    return 0
  end

  if PuppetLint.configuration.list_checks
    puts PuppetLint.configuration.checks
    return 0
  end

  if @args[0].nil?
    puts 'puppet-lint: no file specified'
    puts "puppet-lint: try 'puppet-lint --help' for more information"
    return 1
  end

  begin
    path = @args[0]
    full_path = File.expand_path(path, ENV.fetch('PWD', nil))
    full_base_path = if File.directory?(full_path)
                       full_path
                     else
                       File.dirname(full_path)
                     end

    full_base_path_uri = if full_base_path.start_with?('/')
                           'file://' + full_base_path
                         else
                           'file:///' + full_base_path
                         end

    full_base_path_uri += '/' unless full_base_path_uri.end_with?('/')

    path = path.gsub(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
    path = if File.directory?(path)
             Dir.glob("#{path}/**/*.pp")
           else
             @args
           end

    PuppetLint.configuration.with_filename = true if path.length > 1

    return_val = 0
    ignore_paths = PuppetLint.configuration.ignore_paths
    all_problems = []

    path.each do |f|
      next if ignore_paths.any? { |p| File.fnmatch(p, f) }

      l = PuppetLint.new
      l.file = f
      l.run
      all_problems << l.print_problems

      return_val = 1 if l.errors? || (l.warnings? && PuppetLint.configuration.fail_on_warnings)

      next unless PuppetLint.configuration.fix && l.problems.none? { |r| r[:check] == :syntax }

      File.binwrite(f, l.manifest)
    end

    if PuppetLint.configuration.sarif
      report_sarif(all_problems, full_base_path, full_base_path_uri)
    elsif PuppetLint.configuration.json
      all_problems.each do |problems|
        problems.each do |problem|
          problem.delete_if { |key, _| [:description, :help_uri].include?(key) }
        end
      end
      puts JSON.pretty_generate(all_problems)
    end

    PuppetLint::Report::CodeClimateReporter.write_report_file(all_problems, PuppetLint.configuration.codeclimate_report_file) if PuppetLint.configuration.codeclimate_report_file

    return_val
  rescue PuppetLint::NoCodeError
    puts 'puppet-lint: no file specified or specified file does not exist'
    puts "puppet-lint: try 'puppet-lint --help' for more information"
    1
  end
end