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

Add Puppet validator for plans #1207

Merged
merged 1 commit into from
Feb 11, 2023
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
1 change: 1 addition & 0 deletions lib/pdk/validate.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ module Puppet
autoload :PuppetEPPValidator, 'pdk/validate/puppet/puppet_epp_validator'
autoload :PuppetLintValidator, 'pdk/validate/puppet/puppet_lint_validator'
autoload :PuppetSyntaxValidator, 'pdk/validate/puppet/puppet_syntax_validator'
autoload :PuppetPlanSyntaxValidator, 'pdk/validate/puppet/puppet_plan_syntax_validator'
autoload :PuppetValidatorGroup, 'pdk/validate/puppet/puppet_validator_group'
end

Expand Down
38 changes: 38 additions & 0 deletions lib/pdk/validate/puppet/puppet_plan_syntax_validator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
require 'pdk'

module PDK
module Validate
module Puppet
class PuppetPlanSyntaxValidator < PuppetSyntaxValidator
def name
'puppet-plan-syntax'
end

def pattern
contextual_pattern('plans/**/*.pp')
end

def pattern_ignore; end

def spinner_text_for_targets(_targets)
_('Checking Puppet plan syntax (%{pattern}).') % { pattern: pattern.join(' ') }
end

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.
['parser', 'validate', '--tasks', '--config', null_file, '--modulepath', validate_tmpdir].concat(targets)
end

def validate_tmpdir
require 'tmpdir'

@validate_tmpdir ||= Dir.mktmpdir('puppet-plan-parser-validate')
end
end
end
end
end
1 change: 1 addition & 0 deletions lib/pdk/validate/puppet/puppet_validator_group.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ def name
def validators
[
PuppetSyntaxValidator,
PuppetPlanSyntaxValidator,
PuppetLintValidator,
PuppetEPPValidator,
].freeze
Expand Down
109 changes: 109 additions & 0 deletions spec/unit/pdk/validate/puppet/puppet_plan_syntax_validator_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
require 'spec_helper'
require 'pdk/validate/puppet/puppet_plan_syntax_validator'

describe PDK::Validate::Puppet::PuppetPlanSyntaxValidator do
subject(:validator) { described_class.new(validator_context, options) }

let(:validator_context) { nil }
let(:options) { {} }
let(:tmpdir) { File.join('/', 'tmp', 'puppet-plan-parser-validate') }

before(:each) do
allow(Dir).to receive(:mktmpdir).with('puppet-plan-parser-validate').and_return(tmpdir)
allow(PDK::Util::Filesystem).to receive(:remove_entry_secure).with(tmpdir)
end

it 'defines the ExternalCommandValidator attributes' do
expect(validator).to have_attributes(
name: 'puppet-plan-syntax',
cmd: 'puppet',
)
expect(validator.spinner_text_for_targets(nil)).to match(%r{puppet plan syntax}i)
end

describe '.pattern' do
it 'only contextually matches puppet plans' do
expect(validator).to receive(:contextual_pattern).with('plans/**/*.pp') # rubocop:disable RSpec/SubjectStub This is fine
validator.pattern
end
end

describe '.pattern_ignore' do
it 'ignores nothing' do
expect(validator).not_to receive(:contextual_pattern)
validator.pattern_ignore
end
end

describe '.invoke' do
context 'when the validator runs correctly' do
before(:each) do
allow(validator).to receive(:parse_targets).and_return([[], [], []]) # rubocop:disable RSpec/SubjectStub
end

it 'cleans up the temp dir after invoking' do
expect(validator).to receive(:remove_validate_tmpdir) # rubocop:disable RSpec/SubjectStub
validator.invoke(PDK::Report.new)
end
end

context 'when the validator raises an exception' do
before(:each) do
allow(validator).to receive(:parse_targets).and_raise(PDK::CLI::FatalError) # rubocop:disable RSpec/SubjectStub
end

it 'cleans up the temp dir after invoking' do
expect(validator).to receive(:remove_validate_tmpdir) # rubocop:disable RSpec/SubjectStub
expect {
validator.invoke(PDK::Report.new)
}.to raise_error(PDK::CLI::FatalError)
end
end
end

describe '.remove_validate_tmpdir' do
after(:each) do
validator.remove_validate_tmpdir
end

context 'when a temp dir has been created' do
before(:each) do
validator.validate_tmpdir
end

context 'and the path is a directory' do
before(:each) do
allow(PDK::Util::Filesystem).to receive(:directory?).with(tmpdir).and_return(true)
end

it 'removes the directory' do
expect(PDK::Util::Filesystem).to receive(:remove_entry_secure).with(tmpdir)
end
end

context 'but the path is not a directory' do
before(:each) do
allow(PDK::Util::Filesystem).to receive(:directory?).with(tmpdir).and_return(false)
end

it 'does not attempt to remove the directory' do
expect(PDK::Util::Filesystem).not_to receive(:remove_entry_secure)
end
end
end
end

describe '.parse_options' do
subject(:command_args) { validator.parse_options(targets) }

let(:targets) { %w[target1 target2.pp] }

before(:each) do
allow(Gem).to receive(:win_platform?).and_return(false)
end

it 'invokes `puppet parser validate --tasks`' do
expect(command_args.first(3)).to eq(%w[parser validate --tasks])
end
end
end