Class: PDK::Validate::PuppetEPP

Inherits:
BaseValidator show all
Defined in:
lib/pdk/validate/puppet/puppet_epp.rb

Constant Summary collapse

ERROR_CONTEXT =

In Puppet >= 5.3.4, the error context formatting was changed to facilitate localization

%r{(?:file:\s(?<file>.+?)|line:\s(?<line>.+?)|column:\s(?<column>.+?))}
ERROR_CONTEXT_LEGACY =

In Puppet < 5.3.3, the error context was formatted in these variations:

- "at file_path:line_num:col_num"
- "at file_path:line_num"
- "at line line_num"
- "in file_path"
%r{(?:at\sline\s(?<line>\d+)|at\s(?<file>.+?):(?<line>\d+):(?<column>\d+)|at\s(?<file>.+?):(?<line>\d+)|in\s(?<file>.+?))}
PUPPET_LOGGER_PREFIX =
%r{^(debug|info|notice|warning|error|alert|critical):\s.+?$}i
PUPPET_SYNTAX_PATTERN =
%r{^
  (?<severity>.+?):\s
  (?<message>.+?)
  (?:
    \s\(#{ERROR_CONTEXT}(,\s#{ERROR_CONTEXT})*\)| # attempt to match the new localisation friendly location
    \s#{ERROR_CONTEXT_LEGACY}| # attempt to match the old " at file:line:column" location
    $                                               # handle cases where the output has no location
  )
$}x

Constants inherited from BaseValidator

BaseValidator::ALLOW_EMPTY_TARGETS, BaseValidator::IGNORE_DOTFILES, BaseValidator::INVOKE_STYLE

Class Method Summary collapse

Methods inherited from BaseValidator

allow_empty_targets?, cmd_path, ignore_dotfiles?, ignore_pathspec, parse_targets, process_invalid, process_skipped

Class Method Details

.cmdObject



30
31
32
# File 'lib/pdk/validate/puppet/puppet_epp.rb', line 30

def self.cmd
  'puppet'
end

.invoke(report, options) ⇒ Object



55
56
57
58
59
# File 'lib/pdk/validate/puppet/puppet_epp.rb', line 55

def self.invoke(report, options)
  super
ensure
  remove_validate_tmpdir
end

.nameObject



26
27
28
# File 'lib/pdk/validate/puppet/puppet_epp.rb', line 26

def self.name
  'puppet-epp'
end

.null_fileObject



77
78
79
# File 'lib/pdk/validate/puppet/puppet_epp.rb', line 77

def self.null_file
  Gem.win_platform? ? 'NUL' : '/dev/null'
end

.parse_offense(offense) ⇒ Object



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/pdk/validate/puppet/puppet_epp.rb', line 109

def self.parse_offense(offense)
  sanitize_console_output(offense)

  offense_data = {
    source:  name,
    state:  :failure,
  }

  if offense.match(PUPPET_LOGGER_PREFIX)
    attributes = offense.match(PUPPET_SYNTAX_PATTERN)

    unless attributes.nil?
      attributes.names.each do |name|
        offense_data[name.to_sym] = attributes[name] unless attributes[name].nil?
      end
    end
  else
    offense_data[:message] = offense
  end

  offense_data
end

.parse_options(_options, targets) ⇒ Object



46
47
48
49
50
51
52
53
# File 'lib/pdk/validate/puppet/puppet_epp.rb', line 46

def self.parse_options(_options, targets)
  # Due to PDK-1266 we need to run `puppet parser validate` with an empty
  # modulepath. On *nix, Ruby treats `/dev/null` as an empty directory
  # however it doesn't do so with `NUL` on Windows. The workaround for
  # this to ensure consistent behaviour is to create an empty temporary
  # directory and use that as the modulepath.
  ['epp', 'validate', '--config', null_file, '--modulepath', validate_tmpdir].concat(targets)
end

.parse_output(report, result, targets) ⇒ Object



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
# File 'lib/pdk/validate/puppet/puppet_epp.rb', line 81

def self.parse_output(report, result, targets)
  # Due to PUP-7504, we will have to programmatically construct the json
  # object from the text output for now.
  output = result[:stderr].split("\n").reject { |entry| entry.empty? }

  results_data = []
  output.each do |offense|
    offense_data = parse_offense(offense)
    results_data << offense_data
  end

  # puppet parser validate does not include files without problems in its
  # output, so we need to go through the list of targets and add passing
  # events to the report for any target not listed in the output.
  targets.reject { |target| results_data.any? { |j| j[:file] =~ %r{#{target}} } }.each do |target|
    report.add_event(
      file:     target,
      source:   name,
      severity: :ok,
      state:    :passed,
    )
  end

  results_data.each do |offense|
    report.add_event(offense)
  end
end

.patternObject



34
35
36
# File 'lib/pdk/validate/puppet/puppet_epp.rb', line 34

def self.pattern
  '**/*.epp'
end

.pattern_ignoreObject



38
39
40
# File 'lib/pdk/validate/puppet/puppet_epp.rb', line 38

def self.pattern_ignore
  ''
end

.remove_validate_tmpdirObject



67
68
69
70
71
72
73
74
75
# File 'lib/pdk/validate/puppet/puppet_epp.rb', line 67

def self.remove_validate_tmpdir
  return unless @validate_tmpdir
  return unless File.directory?(@validate_tmpdir)

  require 'fileutils'

  FileUtils.remove_entry_secure(@validate_tmpdir)
  @validate_tmpdir = nil
end

.sanitize_console_output(line) ⇒ Object



132
133
134
# File 'lib/pdk/validate/puppet/puppet_epp.rb', line 132

def self.sanitize_console_output(line)
  line.gsub!(%r{\e\[([;\d]+)?m}, '')
end

.spinner_text(_targets = nil) ⇒ Object



42
43
44
# File 'lib/pdk/validate/puppet/puppet_epp.rb', line 42

def self.spinner_text(_targets = nil)
  _('Checking Puppet EPP syntax (%{pattern}).') % { pattern: pattern }
end

.validate_tmpdirObject



61
62
63
64
65
# File 'lib/pdk/validate/puppet/puppet_epp.rb', line 61

def self.validate_tmpdir
  require 'tmpdir'

  @validate_tmpdir ||= Dir.mktmpdir('puppet-epp-validate')
end