Skip to content

Commit

Permalink
(PDK-470) Validation of task metadata.
Browse files Browse the repository at this point in the history
  • Loading branch information
bmjen committed Oct 2, 2017
1 parent 6b504d1 commit f418f51
Show file tree
Hide file tree
Showing 10 changed files with 171 additions and 26 deletions.
2 changes: 1 addition & 1 deletion lib/pdk/validators/base_validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def self.parse_targets(options)
skipped << target if target_list.flatten.empty?
target_list
elsif File.file?(target)
if target.eql? pattern
if Array(pattern).flatten.include? target
target
elsif Array[pattern].flatten.map { |p| File.fnmatch(p, File.expand_path(target)) }.include? true
target
Expand Down
2 changes: 1 addition & 1 deletion lib/pdk/validators/metadata/metadata_json_lint.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def self.cmd
end

def self.spinner_text(targets = [])
_('Checking metadata style (%{targets}).') % {
_('Checking module metadata style (%{targets}).') % {
targets: PDK::Util.targets_relative_to_pwd(targets).join(' '),
}
end
Expand Down
6 changes: 3 additions & 3 deletions lib/pdk/validators/metadata/metadata_syntax.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ def self.name
end

def self.pattern
'metadata.json'
['metadata.json', 'tasks/**.json']
end

def self.spinner_text(targets = [])
def self.spinner_text(_targets = [])
_('Checking metadata syntax (%{targets}).') % {
targets: PDK::Util.targets_relative_to_pwd(targets).join(' '),
targets: pattern.join(' '),
}
end

Expand Down
128 changes: 128 additions & 0 deletions lib/pdk/validators/metadata/task_metadata_lint.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
require 'pdk'
require 'pdk/cli/exec'
require 'pdk/validators/base_validator'
require 'pdk/util'
require 'pathname'
require 'json-schema'
require 'addressable'

module PDK
module Validate
class TaskMetadataLint < BaseValidator
def self.name
'task-metadata-lint'
end

def self.pattern
'tasks/**.json'
end

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

def self.create_spinner(targets = [], options = {})
return if PDK.logger.debug?
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.schema_file
schema = ''
if PDK::Util.package_install? && File.exist?(File.join(PDK::Util.package_cachedir, 'task.json'))
schema = File.read(File.join(PDK::Util.package_cachedir, 'task.json'))
else
PDK.logger.debug(_('Task Metadata Schema was not found in the cache. Now downloading from the forge.'))
begin
schema = open('https://forgeapi.puppet.com/schemas/task.json').read
rescue
raise PDK::CLI::FatalError, _('Unable to download Task Metadata Schema file. Please check internet connectivity and retry this action.')
end
end
JSON.parse(schema)
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
# Need to set the JSON Parser and State Generator to the Native one to be
# compatible with the multi_json adapter.
JSON.parser = JSON::Ext::Parser if defined?(JSON::Ext::Parser)
JSON.generator = JSON::Ext::Generator

begin
errors = JSON::Validator.fully_validate(schema_file, File.read(target)) || []
rescue JSON::Schema::SchemaError => e
raise PDK::CLI::FatalError, _('Unable to validate Task Metadata. %{error}.') % { error: e.message }
end

if errors.empty?
report.add_event(
file: target,
source: name,
state: :passed,
severity: 'ok',
)
else
errors.each do |error|
# strip off the trailing parts that aren't relevant
error = error.split('in schema').first if error.include? 'in schema'

report.add_event(
file: target,
source: name,
state: :failure,
severity: 'error',
message: error,
)
end
return_val = 1
end
end
end

stop_spinner(return_val)
return_val
end
end
end
end
3 changes: 2 additions & 1 deletion lib/pdk/validators/metadata_validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
require 'pdk/validators/base_validator'
require 'pdk/validators/metadata/metadata_json_lint'
require 'pdk/validators/metadata/metadata_syntax'
require 'pdk/validators/metadata/task_metadata_lint'

module PDK
module Validate
Expand All @@ -12,7 +13,7 @@ def self.name
end

def self.metadata_validators
[MetadataSyntax, MetadataJSONLint]
[MetadataSyntax, MetadataJSONLint, TaskMetadataLint]
end

def self.invoke(report, options = {})
Expand Down
1 change: 1 addition & 0 deletions pdk.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Gem::Specification.new do |spec|
spec.add_runtime_dependency 'tty-spinner', '0.5.0'
spec.add_runtime_dependency 'tty-prompt', '0.13.1'
spec.add_runtime_dependency 'json_pure', '~> 2.1.0'
spec.add_runtime_dependency 'json-schema', '2.8.0'
spec.add_runtime_dependency 'tty-which', '0.3.0'

# Used in the pdk-module-template
Expand Down
21 changes: 10 additions & 11 deletions spec/acceptance/validate_all_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ class validate_all { }
describe command('pdk validate') do
its(:exit_status) { is_expected.to eq(0) }
its(:stderr) { is_expected.to match(%r{Running all available validators}i) }
its(:stderr) { is_expected.to match(%r{Checking metadata syntax \(metadata\.json\)}i) }
its(:stderr) { is_expected.to match(%r{Checking metadata style \(metadata\.json\)}i) }
its(:stderr) { is_expected.to match(%r{Checking metadata syntax}i) }
its(:stderr) { is_expected.to match(%r{Checking module metadata style}i) }
its(:stderr) { is_expected.to match(%r{Checking Puppet manifest syntax}i) }
its(:stderr) { is_expected.to match(%r{Checking Puppet manifest style}i) }
its(:stderr) { is_expected.to match(%r{Checking Ruby code style}i) }
Expand All @@ -47,8 +47,8 @@ class validate_all {
describe command('pdk validate') do
its(:exit_status) { is_expected.not_to eq(0) }
its(:stderr) { is_expected.to match(%r{Running all available validators}i) }
its(:stderr) { is_expected.to match(%r{Checking metadata syntax \(metadata\.json\)}i) }
its(:stderr) { is_expected.to match(%r{Checking metadata style \(metadata\.json\)}i) }
its(:stderr) { is_expected.to match(%r{Checking metadata syntax}i) }
its(:stderr) { is_expected.to match(%r{Checking module metadata style}i) }
its(:stderr) { is_expected.to match(%r{Checking Puppet manifest syntax}i) }
its(:stderr) { is_expected.to match(%r{Checking Ruby code style}i) }
end
Expand All @@ -57,8 +57,8 @@ class validate_all {
its(:exit_status) { is_expected.not_to eq(0) }
its(:stderr) { is_expected.to match(%r{Running all available validators}i) }
its(:stderr) { is_expected.to match(%r{Validating module using \d+ threads}i) }
its(:stderr) { is_expected.to match(%r{Checking metadata syntax \(metadata\.json\)}i) }
its(:stderr) { is_expected.to match(%r{Checking metadata style \(metadata\.json\)}i) }
its(:stderr) { is_expected.to match(%r{Checking metadata syntax}i) }
its(:stderr) { is_expected.to match(%r{Checking module metadata style}i) }
its(:stderr) { is_expected.to match(%r{Checking Puppet manifest syntax}i) }
its(:stdout) { is_expected.to match(%r{Error:.*This Name has no effect}i) }
its(:stdout) { is_expected.to match(%r{Error:.*This Type-Name has no effect}i) }
Expand All @@ -69,8 +69,8 @@ class validate_all {
describe command('pdk validate --format junit') do
its(:exit_status) { is_expected.not_to eq(0) }
its(:stderr) { is_expected.to match(%r{Running all available validators}i) }
its(:stderr) { is_expected.to match(%r{Checking metadata syntax \(metadata\.json\)}i) }
its(:stderr) { is_expected.to match(%r{Checking metadata style \(metadata\.json\)}i) }
its(:stderr) { is_expected.to match(%r{Checking metadata syntax}i) }
its(:stderr) { is_expected.to match(%r{Checking module metadata style}i) }
its(:stderr) { is_expected.to match(%r{Checking Puppet manifest syntax}i) }
its(:stderr) { is_expected.not_to match(%r{Checking Puppet manifest style}i) }
its(:stderr) { is_expected.to match(%r{Checking Ruby code style}i) }
Expand Down Expand Up @@ -124,11 +124,10 @@ class pdk_in_gemfile { }
describe command('pdk validate') do
its(:exit_status) { is_expected.to eq(0) }
its(:stderr) { is_expected.to match(%r{Running all available validators}i) }
its(:stderr) { is_expected.to match(%r{Checking metadata syntax \(metadata\.json\)}i) }
its(:stderr) { is_expected.to match(%r{Checking metadata style \(metadata\.json\)}i) }
its(:stderr) { is_expected.to match(%r{Checking metadata syntax}i) }
its(:stderr) { is_expected.to match(%r{Checking module metadata style}i) }
its(:stderr) { is_expected.to match(%r{Checking Puppet manifest syntax}i) }
its(:stderr) { is_expected.to match(%r{Checking Ruby code style}i) }
its(:stdout) { is_expected.to eq('') }
end
end
end
26 changes: 19 additions & 7 deletions spec/support/it_accepts_metadata_json_targets.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,27 @@
subject(:parsed_targets) { described_class.parse_targets(targets: targets) }

let(:module_metadata_json) { File.join(module_root, 'metadata.json') }
let(:glob_pattern) { File.join(module_root, described_class.pattern) }
let(:globbed_files) { [] }
let(:glob_pattern) do
Array(described_class.pattern).flatten.map { |pattern| File.join(module_root, pattern) }
end

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

context 'when given no targets' do
let(:targets) { [] }

context 'and the module contains a metadata.json file' do
let(:globbed_files) { [module_metadata_json] }
before(:each) do
allow(Dir).to receive(:glob).with(module_metadata_json).and_return([module_metadata_json])
end

it 'returns the path to metadata.json in the module' do
expect(parsed_targets.first).to eq(globbed_files)
expect(parsed_targets.first).to eq([module_metadata_json])
end
end

Expand Down Expand Up @@ -47,7 +53,9 @@

context 'when given a specific target directory' do
let(:targets) { [File.join('path', 'to', 'target', 'directory')] }
let(:glob_pattern) { File.join(targets.first, described_class.pattern) }
let(:glob_pattern) do
Array(described_class.pattern).flatten.map { |pattern| File.join(targets.first, pattern) }
end

before(:each) do
targets.each do |target|
Expand All @@ -56,10 +64,14 @@
end

context 'and the directory contains a metadata.json file' do
let(:globbed_files) { [File.join(targets.first, 'metadata.json')] }
let(:metadata_json) { [File.join(targets.first, 'metadata.json')] }

before(:each) do
allow(Dir).to receive(:glob).with(metadata_json.first).and_return(metadata_json)
end

it 'returns the path to the metadata.json file in the target directory' do
expect(parsed_targets.first).to eq(globbed_files)
expect(parsed_targets.first).to eq(metadata_json)
end
end

Expand Down
4 changes: 2 additions & 2 deletions spec/unit/pdk/validate/metadata_json_lint_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
let(:targets) { ['foo/metadata.json'] }

it 'includes the path to the target in the spinner text' do
expect(spinner_text).to match(%r{checking metadata style \(#{Regexp.escape(targets.first)}\)}i)
expect(spinner_text).to match(%r{checking module metadata style \(#{Regexp.escape(targets.first)}\)}i)
end
end

Expand All @@ -41,7 +41,7 @@
end

it 'includes the path to the target relative to the PWD in the spinner text' do
expect(spinner_text).to match(%r{checking metadata style \(metadata\.json\)}i)
expect(spinner_text).to match(%r{checking module metadata style \(metadata\.json\)}i)
end
end
end
Expand Down
4 changes: 4 additions & 0 deletions spec/unit/pdk/validate/metadata_validator_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
describe PDK::Validate::MetadataValidator do
let(:report) { PDK::Report.new }

before(:each) do
allow(PDK::Util).to receive(:module_root).and_return('/path/to/module')
end

describe '.invoke' do
subject(:return_value) { described_class.invoke(report, {}) }

Expand Down

0 comments on commit f418f51

Please sign in to comment.