Class: PDK::Validate::Puppet::PuppetEPPValidator

Inherits:
ExternalCommandValidator show all
Defined in:
lib/pdk/validate/puppet/puppet_epp_validator.rb

Constant Summary collapse

ERROR_CONTEXT =

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

/(?:file:\s(?<file>.+?)|line:\s(?<line>.+?)|column:\s(?<column>.+?))/.freeze
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"
/(?:at\sline\s(?<line>\d+)|at\s(?<file>.+?):(?<line>\d+):(?<column>\d+)|at\s(?<file>.+?):(?<line>\d+)|in\s(?<file>.+?))/.freeze
PUPPET_LOGGER_PREFIX =
/^(debug|info|notice|warning|error|alert|critical):\s.+?$/i.freeze
PUPPET_SYNTAX_PATTERN =
/^
  (?<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.freeze

Instance Attribute Summary

Attributes inherited from ExternalCommandValidator

#commands

Attributes inherited from Validator

#context, #options, #prepared

Instance Method Summary collapse

Methods inherited from ExternalCommandValidator

#alternate_bin_paths, #cmd_path, #prepare_invoke!, #spinner

Methods inherited from InvokableValidator

#allow_empty_targets?, #fnmatch?, #ignore_dotfiles?, #invoke_style, #parse_targets, #pattern_ignore, #prepare_invoke!, #process_invalid, #process_skipped, #spinner, #spinner_text, #valid_in_context?

Methods inherited from Validator

#initialize, #prepare_invoke!, #spinner, #spinner_text, #spinners_enabled?, #start_spinner, #stop_spinner, #valid_in_context?

Constructor Details

This class inherits a constructor from PDK::Validate::Validator

Instance Method Details

#cmdObject



31
32
33
# File 'lib/pdk/validate/puppet/puppet_epp_validator.rb', line 31

def cmd
  'puppet'
end

#invoke(report) ⇒ Object



52
53
54
55
56
# File 'lib/pdk/validate/puppet/puppet_epp_validator.rb', line 52

def invoke(report)
  super
ensure
  remove_validate_tmpdir
end

#nameObject



27
28
29
# File 'lib/pdk/validate/puppet/puppet_epp_validator.rb', line 27

def name
  'puppet-epp'
end

#null_fileObject



72
73
74
# File 'lib/pdk/validate/puppet/puppet_epp_validator.rb', line 72

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

#parse_offense(offense) ⇒ Object



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/pdk/validate/puppet/puppet_epp_validator.rb', line 104

def 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)

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

  offense_data
end

#parse_options(targets) ⇒ Object



43
44
45
46
47
48
49
50
# File 'lib/pdk/validate/puppet/puppet_epp_validator.rb', line 43

def parse_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



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

def 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(/\r?\n/).reject(&: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] =~ /#{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



35
36
37
# File 'lib/pdk/validate/puppet/puppet_epp_validator.rb', line 35

def pattern
  contextual_pattern('**/*.epp')
end

#remove_validate_tmpdirObject



64
65
66
67
68
69
70
# File 'lib/pdk/validate/puppet/puppet_epp_validator.rb', line 64

def remove_validate_tmpdir
  return unless @validate_tmpdir
  return unless PDK::Util::Filesystem.directory?(@validate_tmpdir)

  PDK::Util::Filesystem.remove_entry_secure(@validate_tmpdir)
  @validate_tmpdir = nil
end

#sanitize_console_output(line) ⇒ Object



125
126
127
# File 'lib/pdk/validate/puppet/puppet_epp_validator.rb', line 125

def sanitize_console_output(line)
  line.gsub!(/\e\[([;\d]+)?m/, '')
end

#spinner_text_for_targets(_targets) ⇒ Object



39
40
41
# File 'lib/pdk/validate/puppet/puppet_epp_validator.rb', line 39

def spinner_text_for_targets(_targets)
  format('Checking Puppet EPP syntax (%{pattern}).', pattern: pattern.join(' '))
end

#validate_tmpdirObject



58
59
60
61
62
# File 'lib/pdk/validate/puppet/puppet_epp_validator.rb', line 58

def validate_tmpdir
  require 'tmpdir'

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