Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(PDK-735) Implement a YAML validator #612

Merged
merged 1 commit into from
Jan 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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