Skip to content

Commit

Permalink
Merge pull request #612 from rodjek/pdk-735
Browse files Browse the repository at this point in the history
(PDK-735) Implement a YAML validator
  • Loading branch information
bmjen authored Jan 8, 2019
2 parents 1fb549a + 644375f commit 26aad19
Show file tree
Hide file tree
Showing 16 changed files with 362 additions and 21 deletions.
2 changes: 1 addition & 1 deletion lib/pdk/cli/validate.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ module PDK::CLI
usage _('validate [validators] [options] [targets]')
summary _('Run static analysis tests.')
description _(
"Run metadata, Puppet, Ruby, or Tasks validation.\n\n" \
"Run metadata, YAML, Puppet, Ruby, or Tasks validation.\n\n" \
'[validators] is an optional comma-separated list of validators to use. ' \
'If not specified, all validators are used. ' \
"Note that when using PowerShell, the list of validators must be enclosed in single quotes.\n\n" \
Expand Down
7 changes: 4 additions & 3 deletions lib/pdk/module.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ module PDK
module Module
DEFAULT_IGNORED = [
'/pkg/',
'.*',
'~*',
'/coverage',
'/checksums.json',
Expand All @@ -13,8 +12,10 @@ module Module
'/vendor/',
].freeze

def default_ignored_pathspec
@default_ignored_pathspec ||= PathSpec.new(DEFAULT_IGNORED)
def default_ignored_pathspec(ignore_dotfiles = true)
PathSpec.new(DEFAULT_IGNORED).tap do |ps|
ps.add('.*') if ignore_dotfiles
end
end
module_function :default_ignored_pathspec
end
Expand Down
10 changes: 8 additions & 2 deletions lib/pdk/module/templatedir.rb
Original file line number Diff line number Diff line change
Expand Up @@ -269,8 +269,14 @@ def read_config(loc)
if File.file?(loc) && File.readable?(loc)
begin
YAML.safe_load(File.read(loc), [], [], true)
rescue StandardError => e
PDK.logger.warn(_("'%{file}' is not a valid YAML file: %{message}") % { file: loc, message: e.message })
rescue Psych::SyntaxError => e
PDK.logger.warn _("'%{file}' is not a valid YAML file: %{problem} %{context} at line %{line} column %{column}") % {
file: loc,
problem: e.problem,
context: e.context,
line: e.line,
column: e.column,
}
{}
end
else
Expand Down
9 changes: 8 additions & 1 deletion lib/pdk/validate.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,18 @@
require 'pdk/validate/puppet_validator'
require 'pdk/validate/ruby_validator'
require 'pdk/validate/tasks_validator'
require 'pdk/validate/yaml_validator'

module PDK
module Validate
def self.validators
@validators ||= [MetadataValidator, PuppetValidator, RubyValidator, TasksValidator].freeze
@validators ||= [
MetadataValidator,
YAMLValidator,
PuppetValidator,
RubyValidator,
TasksValidator,
].freeze
end

class ParseOutputError < StandardError; end
Expand Down
14 changes: 10 additions & 4 deletions lib/pdk/validate/base_validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ class BaseValidator
# false - PDK will pass the globbed targets to the validator command.
ALLOW_EMPTY_TARGETS = false

IGNORE_DOTFILES = true

def self.cmd_path
File.join(PDK::Util.module_root, 'bin', cmd)
end
Expand Down Expand Up @@ -49,10 +51,10 @@ def self.parse_targets(options)
if respond_to?(:pattern)
if File.directory?(target)
target_root = PDK::Util.module_root
pattern_glob = Array(pattern).map { |p| Dir.glob(File.join(target_root, p)) }
pattern_glob = Array(pattern).map { |p| Dir.glob(File.join(target_root, p), File::FNM_DOTMATCH) }

target_list = pattern_glob.flatten.map do |file|
if File.fnmatch(File.join(File.expand_path(target), '*'), file)
if File.fnmatch(File.join(File.expand_path(target), '*'), file, File::FNM_DOTMATCH)
Pathname.new(file).relative_path_from(Pathname.new(PDK::Util.module_root)).to_s
end
end
Expand All @@ -65,7 +67,7 @@ def self.parse_targets(options)
elsif File.file?(target)
if Array(pattern).include? target
target
elsif Array(pattern).any? { |p| File.fnmatch(File.expand_path(p), File.expand_path(target)) }
elsif Array(pattern).any? { |p| File.fnmatch(File.expand_path(p), File.expand_path(target), File::FNM_DOTMATCH) }
target
else
skipped << target
Expand All @@ -83,7 +85,7 @@ def self.parse_targets(options)
end

def self.ignore_pathspec
ignore_pathspec = PDK::Module.default_ignored_pathspec.dup
ignore_pathspec = PDK::Module.default_ignored_pathspec(ignore_dotfiles?)

if respond_to?(:pattern_ignore)
Array(pattern_ignore).each do |pattern|
Expand All @@ -94,6 +96,10 @@ def self.ignore_pathspec
ignore_pathspec
end

def self.ignore_dotfiles?
self::IGNORE_DOTFILES
end

def self.parse_options(_options, targets)
targets
end
Expand Down
109 changes: 109 additions & 0 deletions lib/pdk/validate/yaml/syntax.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
require 'pdk'
require 'pdk/cli/exec'
require 'pdk/validate/base_validator'
require 'pdk/util'
require 'pathname'

module PDK
module Validate
class YAML
class Syntax < BaseValidator
IGNORE_DOTFILES = false

def self.name
'yaml-syntax'
end

def self.pattern
[
'**/*.yaml',
'*.yaml',
'**/*.yml',
'*.yml',
]
end

def self.spinner_text(_targets = [])
_('Checking YAML syntax (%{targets}).') % {
targets: pattern,
}
end

def self.create_spinner(targets = [], options = {})
return unless PDK::CLI::Util.interactive?
options = options.merge(PDK::CLI::Util.spinner_opts_for_platform)

exec_group = options[:exec_group]
@spinner = if exec_group
exec_group.add_spinner(spinner_text(targets), options)
else
TTY::Spinner.new("[:spinner] #{spinner_text(targets)}", options)
end
@spinner.auto_spin
end

def self.stop_spinner(exit_code)
if exit_code.zero? && @spinner
@spinner.success
elsif @spinner
@spinner.error
end
end

def self.invoke(report, options = {})
targets, skipped, invalid = parse_targets(options)

process_skipped(report, skipped)
process_invalid(report, invalid)

return 0 if targets.empty?

return_val = 0
create_spinner(targets, options)

targets.each do |target|
unless File.readable?(target)
report.add_event(
file: target,
source: name,
state: :failure,
severity: 'error',
message: _('Could not be read.'),
)
return_val = 1
next
end

begin
::YAML.safe_load(File.read(target), [], [], true)

report.add_event(
file: target,
source: name,
state: :passed,
severity: 'ok',
)
rescue Psych::SyntaxError => e
report.add_event(
file: target,
source: name,
state: :failure,
severity: 'error',
line: e.line,
column: e.column,
message: _('%{problem} %{context}') % {
problem: e.problem,
context: e.context,
},
)
return_val = 1
end
end

stop_spinner(return_val)
return_val
end
end
end
end
end
31 changes: 31 additions & 0 deletions lib/pdk/validate/yaml_validator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
require 'pdk'
require 'pdk/cli/exec'
require 'pdk/validate/base_validator'
require 'pdk/validate/yaml/syntax'

module PDK
module Validate
class YAMLValidator < BaseValidator
def self.name
'yaml'
end

def self.validators
[
PDK::Validate::YAML::Syntax,
]
end

def self.invoke(report, options = {})
exit_code = 0

validators.each do |validator|
exit_code = validator.invoke(report, options)
break if exit_code != 0
end

exit_code
end
end
end
end
1 change: 1 addition & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
let(:validators) do
[
PDK::Validate::MetadataValidator,
PDK::Validate::YAMLValidator,
PDK::Validate::PuppetValidator,
PDK::Validate::RubyValidator,
PDK::Validate::TasksValidator,
Expand Down
4 changes: 2 additions & 2 deletions spec/support/it_accepts_metadata_json_targets.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

before(:each) do
glob_pattern.each do |pattern|
allow(Dir).to receive(:glob).with(pattern).and_return(globbed_files)
allow(Dir).to receive(:glob).with(pattern, anything).and_return(globbed_files)
end
end

Expand All @@ -19,7 +19,7 @@

context 'and the module contains a metadata.json file' do
before(:each) do
allow(Dir).to receive(:glob).with(module_metadata_json).and_return([module_metadata_json])
allow(Dir).to receive(:glob).with(module_metadata_json, anything).and_return([module_metadata_json])
allow(File).to receive(:expand_path).with(module_root).and_return(module_root)
end

Expand Down
2 changes: 1 addition & 1 deletion spec/support/it_accepts_pp_targets.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
let(:glob_pattern) { File.join(module_root, described_class.pattern) }

before(:each) do
allow(Dir).to receive(:glob).with(glob_pattern).and_return(globbed_files)
allow(Dir).to receive(:glob).with(glob_pattern, anything).and_return(globbed_files)
allow(File).to receive(:expand_path).with(module_root).and_return(module_root)
end

Expand Down
8 changes: 4 additions & 4 deletions spec/unit/pdk/validate/base_validator_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@

before(:each) do
allow(File).to receive(:directory?).and_return(true)
allow(Dir).to receive(:glob).with(glob_pattern).and_return(globbed_files)
allow(Dir).to receive(:glob).with(glob_pattern, anything).and_return(globbed_files)
allow(File).to receive(:expand_path).with(module_root).and_return(module_root)
end

Expand All @@ -114,7 +114,7 @@

before(:each) do
allow(File).to receive(:directory?).and_return(true)
allow(Dir).to receive(:glob).with(glob_pattern).and_return(globbed_files)
allow(Dir).to receive(:glob).with(glob_pattern, anything).and_return(globbed_files)
allow(File).to receive(:expand_path).with(module_root).and_return(module_root)
end

Expand All @@ -134,7 +134,7 @@
let(:globbed_target2) { targets2.map { |target| File.join(module_root, target) } }

before(:each) do
allow(Dir).to receive(:glob).with(glob_pattern).and_return(globbed_target2)
allow(Dir).to receive(:glob).with(glob_pattern, anything).and_return(globbed_target2)
allow(File).to receive(:directory?).with('target1.pp').and_return(false)
allow(File).to receive(:directory?).with('target2/').and_return(true)
allow(File).to receive(:file?).with('target1.pp').and_return(true)
Expand Down Expand Up @@ -163,7 +163,7 @@
end

before(:each) do
allow(Dir).to receive(:glob).with(File.join(module_root, described_class.pattern)).and_return(globbed_target2)
allow(Dir).to receive(:glob).with(File.join(module_root, described_class.pattern), anything).and_return(globbed_target2)
allow(File).to receive(:directory?).with('target3/').and_return(true)
end

Expand Down
2 changes: 1 addition & 1 deletion spec/unit/pdk/validate/puppet_syntax_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

before(:each) do
allow(Dir).to receive(:glob).with(any_args).and_call_original
allow(Dir).to receive(:glob).with(glob_pattern).and_return(globbed_files)
allow(Dir).to receive(:glob).with(glob_pattern, anything).and_return(globbed_files)
allow(File).to receive(:expand_path).with(any_args).and_call_original
allow(File).to receive(:expand_path).with(module_root).and_return(module_root)
end
Expand Down
2 changes: 1 addition & 1 deletion spec/unit/pdk/validate/rubocop_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
end

before(:each) do
allow(Dir).to receive(:glob).with(glob_pattern).and_return(globbed_target2)
allow(Dir).to receive(:glob).with(glob_pattern, anything).and_return(globbed_target2)
allow(File).to receive(:directory?).with('target1.rb').and_return(false)
allow(File).to receive(:directory?).with('target2/').and_return(true)
allow(File).to receive(:file?).with('target1.rb').and_return(true)
Expand Down
2 changes: 1 addition & 1 deletion spec/unit/pdk/validate/tasks/name_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

before(:each) do
globbed_targets = targets.map { |r| File.join(module_root, r) }
allow(Dir).to receive(:glob).with(glob_pattern).and_return(globbed_targets)
allow(Dir).to receive(:glob).with(glob_pattern, anything).and_return(globbed_targets)
allow(File).to receive(:expand_path).with(module_root).and_return(module_root)
end

Expand Down
Loading

0 comments on commit 26aad19

Please sign in to comment.