puppet-check 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9ef6e25a3e4df73cbaddd5f509626cc853b4cb9d
4
- data.tar.gz: bbfa05df7d4d1d92f27a0b270d102bf2434c0ecb
3
+ metadata.gz: 67168965abee351700873ebf5c19daeb0b48bb6f
4
+ data.tar.gz: e06ae047c9365b3d6595770e1eed47cccac99c5e
5
5
  SHA512:
6
- metadata.gz: 791c901be64ebca7dc49db9f5aa99940b1e138be58e5fd5605b881b32c97b36819c5bd7d2f353914bd2756c6a0c75f6cfc455de7429d27b20eca099a1a6498d5
7
- data.tar.gz: 1e2f6c6c65ee1af874689f9fe2aab3fb7d4865c4047294de7808ed81d7c6541b16c2b2d9e749dac3bf01f16df2b3059f0875533e65e426e1220cc0250a069803
6
+ metadata.gz: 9b72f7b8da7f5f541d45051ae2aa7bb695e7787973056da53b5541038795fbc5788f823c2c6b235ef7fe6d2dd844b37ae2ee6c6357f3c4d1a88292070b9a7458
7
+ data.tar.gz: 886bec5a3f9b876aab8a8c6aa2b6724a6d6797fed63103b22d7c872d6b07805e86a0f2a3adecd04d499dd68561bf4959915d9c0d7b8f4515f98375d17948869f
data/CHANGELOG.md CHANGED
@@ -1,15 +1,30 @@
1
- ### 1.3.0 (Roadmap)
1
+ ### 1.4.0 (Roadmap)
2
2
  - minimum puppet version bump to 3.5 and future parser enabled by force for version < 4 (search code on 'future')
3
- - minimum ruby version bump to 2.0.0 (switch vagrant to centos7, remove 1.9.3 from travis.yml, add 2.3.x to travis.yml, update readme, remove psych::syntaxerror from dataparser.yaml, and remove 1.9.3 test from rubyparser.template style spec)
4
3
 
5
- ### 1.2.0 (Roadmap)
4
+ ### 1.3.0 (Roadmap)
5
+ - minimum ruby version bump to 2.0.0 (switch vagrant to centos7, remove 1.9.3 from travis.yml, add 2.3.x to travis.yml, update readme, remove psych::syntaxerror from dataparser.yaml, and remove 1.9.3 test from rubyparser.template style spec)
6
+ - rakefile interface with puppet-lint, rubocop, reek
6
7
  - json and yaml output formats support (error_files becomes hash with file keys and array of issues; refactor output_results)
7
- - rspec-puppet external dependencies support
8
- - add additional hiera checks, including nested hash parsing
9
- - explore puppet-catalog-test integration
8
+ - rudimentary catalog compilation testing?
9
+
10
+ ### 1.2.1 (Roadmap)
11
+ - move rspec_puppet support to separate class
12
+ - improve rspec_puppet_git/forge/hg (check librarian puppet, git man, hg man, forge docs for ideas)
13
+ - direct interface to rubocop and reek in rubyparser
14
+ - add additional hiera checks,
15
+
16
+ ### 1.2.0
17
+ - Support for external module dependencies with RSpecPuppet.
18
+ - Support for nested hash parsing in Hieradata checks.
19
+ - Support for `.puppet-lint.rc` config files in manually specified paths.
20
+ - A few bug fixes for RSpecPuppet support.
21
+
22
+ ### 1.1.1 (yanked from rubygems.org)
23
+ - Rewrote and optimized RSpecPuppet module support.
24
+ - A variety of minor fixes, cleanup, and improvements (e.g. ignored files now outputs in cyan and not blue)
10
25
 
11
26
  ### 1.1.0
12
- - Support for RSpec, RSpec-Puppet, and Beaker.
27
+ - Support for RSpec, RSpecPuppet, and Beaker.
13
28
  - Empty hieradata file bug fix.
14
29
 
15
30
  ### 1.0.0
data/README.md CHANGED
@@ -1,6 +1,14 @@
1
1
  # Puppet Check
2
2
  [![Build Status](https://travis-ci.org/mschuchard/puppet-check.svg?branch=master)](https://travis-ci.org/mschuchard/puppet-check)
3
3
 
4
+ - [Description](#description)
5
+ - [Usage](#usage)
6
+ - [CLI](#cli)
7
+ - [Rake](#rake)
8
+ - [Exit Codes](#exit-codes)
9
+ - [Optional Dependencies](#optional-dependencies)
10
+ - [Contributing](#contributing)
11
+
4
12
  ## Description
5
13
  Puppet Check is a gem that provides a comprehensive, streamlined, and efficient analysis of the syntax, style, and validity of your entire Puppet code and data.
6
14
 
@@ -71,7 +79,8 @@ double quoted string containing no variables at line 2, column 45
71
79
  2: previous definition of TEMPLATE was here
72
80
 
73
81
  -- hieradata/style.yaml:
74
- Values missing in key 'value'.
82
+ Value(s) missing in key 'value'.
83
+ Value(s) missing in key 'and'.
75
84
 
76
85
  -- metadata_style/metadata.json:
77
86
  License identifier 'Imaginary' is not in the SPDX list: http://spdx.org/licenses/
@@ -101,11 +110,12 @@ The following files have unrecognized formats and therefore were not processed:
101
110
  - Puppetlabs Spec Helper does not allow interfacing through it to the gems executing the checks.
102
111
  - Puppetlabs Spec Helper has no CLI.
103
112
  - Puppetlabs Spec Helper intrinsically only executes spec tests against one module at a time.
113
+ - Puppetlabs Spec Helper requires an additional config file for RSpec Puppet support.
104
114
 
105
- It is worth nothing that there is no current development objective for Puppet Check to achieve the same advanced level of robustness for spec testing that Puppetlabs Spec Helper enables. If you are performing standard spec testing on your Puppet code and data, then Puppet Check's spec testing is a fantastic lightweight and faster alternative to Puppetlabs Spec Helper. If you require advanced and intricate capabilities in your spec testing (e.g. direct interfacing to the `Puppet::Parser::Scope` API), you will likely prefer Puppetlabs Spec Helper's spec testing in conjunction with Puppet Check's file validation. Also, Puppet Check currently has no intrinsic support for external dependencies during spec testing, so you will need Puppetlabs Spec Helper or Librarian Puppet for that.
115
+ It is worth nothing that there is no current development objective for Puppet Check to achieve the same advanced level of robustness for spec testing that Puppetlabs Spec Helper enables. If you are performing standard spec testing on your Puppet code and data, then Puppet Check's spec testing is a fantastic lightweight and faster alternative to Puppetlabs Spec Helper. If you require advanced and intricate capabilities in your spec testing (e.g. direct interfacing to the `Puppet::Parser::Scope` API), you will likely prefer Puppetlabs Spec Helper's spec testing in conjunction with Puppet Check's file validation.
106
116
 
107
117
  ## Usage
108
- Puppet Check requires `ruby >= 1.9.3`, `puppet >= 3.2`, and `puppet-lint >= 1.1.0`. All other dependencies should be fine with various versions. Puppet Check can be used either with a CLI or Rake tasks. Please note both interfaces will ignore any directories named `fixtures` during file checks.
118
+ Puppet Check requires `ruby >= 1.9.3`, `puppet >= 3.2`, and `puppet-lint >= 1.1.0`. All other dependencies should be fine with various versions. Puppet Check can be used either with a CLI or Rake tasks. Please note both interfaces will ignore any directories named `fixtures` or specified paths with that directory during file checks.
109
119
 
110
120
  ### CLI
111
121
  ```
@@ -114,13 +124,14 @@ usage: puppet-check [options] paths
114
124
  -s, --style Enable style checks
115
125
  --puppet-lint arg_one,arg_two
116
126
  Arguments for PuppetLint ignored checks
127
+ -c, --config file Load PuppetLint options from file.
117
128
  --rubocop arg_one,arg_two Arguments for Rubocop disabled cops
118
129
  ```
119
130
 
120
- The command line interface enables the ability to select the Puppet future parser, additional style checks besides the syntax checks, and to specify PuppetLint and Rubocop checks to ignore. It should be noted that your `.puppet-lint.rc`, `.rubocop.yml`, and `*.reek` files should still be automatically respected by the individual style checkers if you prefer those to a simplified CLI.
131
+ The command line interface enables the ability to select the Puppet future parser, additional style checks besides the syntax checks, and to specify PuppetLint and Rubocop checks to ignore. If you require a more robust interface to PuppetLint, Rubocop, and Reek, then please use `.puppet-lint.rc`, `.rubocop.yml` and `*.reek` config files. The `.puppet-lint.rc` can be specified with the `-c` argument. If it is not specified, then PuppetLint will automatically load one from `.puppet-lint.rc`, `~/.puppet-lint.rc`, or `/etc/puppet-lint.rc`, in that order of preference. The nearest `.rubocop.yml` and `*.reek` will be automatically respected.
121
132
 
122
- ```
123
133
  Example:
134
+ ```
124
135
  puppet-check -s --puppet-lint no-hard_tabs-check,no-80chars-check --rubocop Metrics/LineLength,Style/Encoding path/to/code_and_data
125
136
  ```
126
137
 
@@ -142,14 +153,48 @@ PuppetCheck.style_check = true
142
153
  PuppetCheck.future_parser = true
143
154
  ```
144
155
 
145
- The style checks from within `rake puppetcheck:file` are directly interfaced to `puppet-lint`, `rubocop`, and `reek`. This means that all arguments and options should be specified from within your `.puppet-lint.rc`, `.rubocop.yml`, and `*.reek`. However, `puppet-lint` can still be interfaced with from within the `Rakefile` with the normal method of `PuppetLint.configuration.send('foo')` after the require. The capability to pass ruby style arguments and options from within the `Rakefile` task block will be considered for future versions.
156
+ The style checks from within `rake puppetcheck:file` are directly interfaced to `puppet-lint`, `rubocop`, and `reek`. This means that all arguments and options should be specified from within your `.puppet-lint.rc`, `.rubocop.yml`, and `*.reek`. The capability to pass style arguments and options from within the `Rakefile` task block will be considered for future versions.
146
157
 
147
158
  #### puppetcheck:spec
148
159
  The spec tests will be executed against everything that matches the pattern `**/{classes, defines, facter, functions, hosts, puppet, unit, types}/**/*_spec.rb`. This means everything in the current path that appears to be a Puppet module spec test will be regarded as such and executed during this rake task.
149
160
 
150
- Please note it is perfectly acceptable to only execute standard RSpec tests in your modules and not use the extended RSpec Puppet matchers. If RSpec Puppet is not installed, then no RSpec Puppet related actions (including those described below) will be performed.
161
+ Please note it is perfectly acceptable to only execute standard RSpec tests in your modules and not use the extended RSpec Puppet matchers. If no Puppet module directories are identified during directory parsing, then no RSpec Puppet related actions (including those described below) will be performed.
162
+
163
+ Prior to executing the spec tests, Puppet Check will parse everything in the current path and identify all `spec` directories not within `fixtures` directories. It will then execute RSpec Puppet setup actions inside all directories one level above that contain a `manifests` directory. This is assumed to be a Puppet module directory. These setup actions include creating all of the necessary directories inside of `spec/fixtures`, creating a blank `site.pp` if it is missing, symlinking everything from the module that is needed into fixtures (automatically replaces functionality of self module symlink in `.fixtures.yaml` from Puppetlabs Spec Helper), and creates the `spec_helper.rb` if it is missing.
164
+
165
+ Puppet Check will also automatically download specified external module dependencies for and during RSpec Puppet testing. Currently `git`, `puppet forge`, and `hg` commands are supported. They can be implemented in the following way in your modules' `metadata.json`:
166
+
167
+ ```json
168
+ "dependencies": [
169
+ {
170
+ "name": "module-name",
171
+ "forge": "forge-name"
172
+ },
173
+ {
174
+ "name": "module-name",
175
+ "git": "git-url"
176
+ },
177
+ {
178
+ "name": "module-name",
179
+ "hg": "hg-url"
180
+ }
181
+ ]
182
+ ```
151
183
 
152
- Prior to executing the spec tests, Puppet Check will parse everything in the current path and identify all `spec` directories. It will then execute `RSpec::Puppet::Setup` inside each assumed module directory containing these `spec` directories. This ensures any missing configuration items or non-current symlinks are created without altering your current configuration items, directories, or symlinks. The drawback to this is that your modules will be populated with useless `Rakefiles` if they do not already exist.
184
+ Example:
185
+
186
+ ```json
187
+ "dependencies": [
188
+ {
189
+ "name": "puppetlabs/stdlib",
190
+ "forge": "puppetlabs-stdlib"
191
+ },
192
+ {
193
+ "name": "puppetlabs/lvm",
194
+ "git": "https://github.com/puppetlabs/puppetlabs-lvm.git"
195
+ }
196
+ ]
197
+ ```
153
198
 
154
199
  #### puppetcheck:beaker
155
200
  The spec tests will be executed against everything that matches the pattern `**/acceptance`. This means everything in the current path that appears to be a Puppet module acceptance test will be regarded as such and executed during this rake task.
@@ -162,15 +207,17 @@ Please note this is merely a frontend to Beaker and that Beaker itself has a sel
162
207
  - 2: PuppetCheck exited with errors in your Puppet code and data.
163
208
 
164
209
  ### Optional dependencies
165
- - **reek**: will automatically be installed as a dependency and checks enabled during style checks if your Ruby version is `>= 2.1.0`.
210
+ - **reek**: will automatically (with `bundler`, otherwise manually) be installed as a dependency and checks enabled during style checks if your Ruby version is `>= 2.1.0`.
166
211
  - **rake**: install this if you want to use Puppet Check with `rake` tasks in addition to the CLI.
167
212
  - **rspec**: install this if you want to use Puppet Check to execute the spec tests for your ruby files during `rake`.
168
213
  - **rspec-puppet**: install this if you want to use Puppet Check to execute the spec tests for your Puppet files during `rake`.
169
214
  - **beaker**: install this if you want to use Puppet Check to execute the acceptance tests during `rake`.
215
+ - **git**: install this if you want to use Puppet Check to download external module dependencies with `git` commands during RSpec Puppet testing.
216
+ - **mercurial**: install this if you want to use Puppet Check to download external module dependencies with `hg` commands during RSpec Puppet testing.
170
217
 
171
218
  ## Contributing
172
219
  Code should pass all spec tests. New features should involve new spec tests. Adherence to Rubocop and Reek is expected where not overly onerous or where the check is of dubious cost/benefit.
173
220
 
174
- A `Dockerfile` is provided for easy `rake` testing. A `Vagrantfile` is provided for easy gem building, installation, and post-installation testing.
221
+ A [Dockerfile](Dockerfile) is provided for easy rake testing. A [Vagrantfile](Vagrantfile) is provided for easy gem building, installation, and post-installation testing.
175
222
 
176
- Please consult the `CHANGELOG` for the current development roadmap.
223
+ Please consult the [CHANGELOG](CHANGELOG.md) for the current development roadmap.
data/lib/puppet-check.rb CHANGED
@@ -18,7 +18,7 @@ class PuppetCheck
18
18
  @puppetlint_args = []
19
19
  @rubocop_args = []
20
20
 
21
- # let the parser methods read user options and append to the file arrays; let CLI and tasks write to user options
21
+ # allow the parser methods read user options and append to the file arrays; allow CLI and tasks write to user options
22
22
  class << self
23
23
  attr_accessor :future_parser, :style_check, :error_files, :warning_files, :clean_files, :ignored_files, :puppetlint_args, :rubocop_args
24
24
  end
@@ -42,7 +42,7 @@ class PuppetCheck
42
42
  def parse_paths(paths)
43
43
  files = []
44
44
 
45
- # traverse the unique paths, return all files, and replace // with /
45
+ # traverse the unique paths and return all files
46
46
  paths.uniq.each do |path|
47
47
  if File.directory?(path)
48
48
  files.concat(Dir.glob("#{path}/**/*").select { |subpath| File.file? subpath })
@@ -54,7 +54,7 @@ class PuppetCheck
54
54
  files.reject! { |file| file =~ /fixtures/ }
55
55
 
56
56
  # check that at least one file was found, remove double slashes, and return unique files
57
- raise "No files found in supplied paths #{paths.join(', ')}." if files.empty?
57
+ raise "puppet-check: no files found in supplied paths #{paths.join(', ')}." if files.empty?
58
58
  files.map! { |file| file.gsub('//', '/') }
59
59
  files.uniq
60
60
  end
@@ -69,12 +69,12 @@ class PuppetCheck
69
69
  files.reject! { |file| File.extname(file) == '.rb' }
70
70
  RubyParser.template(files.select { |file| File.extname(file) == '.erb' })
71
71
  files.reject! { |file| File.extname(file) == '.erb' }
72
- DataParser.yaml(files.select { |file| file =~ /.*\.ya?ml$/ })
73
- files.reject! { |file| file =~ /.*\.ya?ml$/ }
72
+ DataParser.yaml(files.select { |file| File.extname(file) =~ /\.ya?ml$/ })
73
+ files.reject! { |file| File.extname(file) =~ /\.ya?ml$/ }
74
74
  DataParser.json(files.select { |file| File.extname(file) == '.json' })
75
75
  files.reject! { |file| File.extname(file) == '.json' }
76
- RubyParser.librarian(files.select { |file| file =~ /.*(Puppet|Module|Rake|Gem)file$/ })
77
- files.reject! { |file| file =~ /.*(?:Puppet|Module|Rake|Gem)file$/ }
76
+ RubyParser.librarian(files.select { |file| File.basename(file) =~ /(?:Puppet|Module|Rake|Gem)file$/ })
77
+ files.reject! { |file| File.basename(file) =~ /(?:Puppet|Module|Rake|Gem)file$/ }
78
78
  files.each { |file| self.class.ignored_files.push("-- #{file}") }
79
79
  end
80
80
 
@@ -83,6 +83,6 @@ class PuppetCheck
83
83
  puts "\033[31mThe following files have errors:\033[0m", error_files.join("\n\n") unless error_files.empty?
84
84
  puts "\n\033[33mThe following files have warnings:\033[0m", warning_files.join("\n\n") unless warning_files.empty?
85
85
  puts "\n\033[32mThe following files have no errors or warnings:\033[0m", clean_files unless clean_files.empty?
86
- puts "\n\033[34mThe following files have unrecognized formats and therefore were not processed:\033[0m", ignored_files unless ignored_files.empty?
86
+ puts "\n\033[36mThe following files have unrecognized formats and therefore were not processed:\033[0m", ignored_files unless ignored_files.empty?
87
87
  end
88
88
  end
@@ -23,7 +23,10 @@ class PuppetCheck::CLI
23
23
  opts.on('-s', '--style', 'Enable style checks') { PuppetCheck.style_check = true }
24
24
  # arguments to style checkers
25
25
  opts.on('--puppet-lint arg_one,arg_two', Array, 'Arguments for PuppetLint ignored checks') do |puppetlint_args|
26
- PuppetCheck.puppetlint_args = puppetlint_args.map { |arg| "--#{arg}" }
26
+ PuppetCheck.puppetlint_args += puppetlint_args.map { |arg| "--#{arg}" }
27
+ end
28
+ opts.on('-c', '--config file', 'Load PuppetLint options from file.') do |file|
29
+ PuppetCheck.puppetlint_args += File.read(file).split("\n")
27
30
  end
28
31
  opts.on('--rubocop arg_one,arg_two', String, 'Arguments for Rubocop disabled cops') { |arg| PuppetCheck.rubocop_args = ['--except', arg] }
29
32
  end
@@ -35,8 +35,8 @@ class DataParser
35
35
  warnings = []
36
36
 
37
37
  # check metadata.json
38
- if file =~ /.*metadata\.json$/
39
- # metadata-json-lint has issues and is essentially no longer maintained so here is an improved and leaner version of it
38
+ if File.basename(file) == 'metadata.json'
39
+ # metadata-json-lint has issues and is essentially no longer maintained, so here is an improved and leaner version of it
40
40
  require 'spdx-licenses'
41
41
 
42
42
  # check for errors
@@ -44,7 +44,7 @@ class DataParser
44
44
 
45
45
  # check for required keys
46
46
  %w(name version author license summary source dependencies).each do |key|
47
- errors.push("Required field '#{key}' not found in metadata.json.") unless parsed.key?(key)
47
+ errors.push("Required field '#{key}' not found.") unless parsed.key?(key)
48
48
  end
49
49
 
50
50
  # check for duplicate dependencies and requirements
@@ -73,6 +73,7 @@ class DataParser
73
73
  if parsed.key?('license') && !SpdxLicenses.exist?(parsed['license']) && parsed['license'] !~ /[pP]roprietary/
74
74
  warnings.push("License identifier '#{parsed['license']}' is not in the SPDX list: http://spdx.org/licenses/")
75
75
  end
76
+ # assume this is hieradata
76
77
  else
77
78
  # perform some rudimentary hiera checks if data exists
78
79
  warnings = hiera(parsed) unless parsed.class.to_s == 'NilClass'
@@ -87,7 +88,10 @@ class DataParser
87
88
  def self.hiera(data)
88
89
  warnings = []
89
90
  data.each do |key, value|
90
- warnings.push("Values missing in key '#{key}'.") if value.class.to_s == 'NilClass'
91
+ # check for nil values in the data (nil keys are fine)
92
+ if (value.is_a?(Hash) && value.values.any?(&:nil?)) || (value.class.to_s == 'NilClass')
93
+ warnings.push("Value(s) missing in key '#{key}'.")
94
+ end
91
95
  end
92
96
  warnings
93
97
  end
@@ -47,7 +47,7 @@ class PuppetParser
47
47
 
48
48
  # collect the warnings
49
49
  if puppet_lint.warnings?
50
- puppet_lint.problems.each { |values| warnings += "\n#{values[:message]} at line #{values[:line]}, column #{values[:column]}" }
50
+ puppet_lint.problems.each { |values| warnings += "\n#{values[:line]}:#{values[:column]}: #{values[:message]}" }
51
51
  end
52
52
  end
53
53
  next PuppetCheck.warning_files.push(warnings) unless warnings == "-- #{file}:"
@@ -61,7 +61,7 @@ class PuppetParser
61
61
 
62
62
  files.each do |file|
63
63
  # puppet before version 4 cannot check template syntax
64
- next PuppetCheck.ignored_files.push("-- #{file}: ignored due to Puppet Agent < 4.0.0") if Puppet::PUPPETVERSION.to_i < 4
64
+ next PuppetCheck.ignored_files.push("-- #{file}: ignored due to Puppet < 4.0.0") if Puppet::PUPPETVERSION.to_i < 4
65
65
 
66
66
  # check puppet template syntax
67
67
  begin
@@ -8,6 +8,7 @@ class RubyParser
8
8
  files.each do |file|
9
9
  # check ruby syntax
10
10
  begin
11
+ # prevents ruby code from actually executing
11
12
  catch(:good) { instance_eval("BEGIN {throw :good}; #{File.read(file)}") }
12
13
  rescue ScriptError, StandardError => err
13
14
  PuppetCheck.error_files.push("-- #{file}:\n#{err}")
@@ -20,7 +21,7 @@ class RubyParser
20
21
  rubocop_warnings = Utils.capture_stdout { RuboCop::CLI.new.run(PuppetCheck.rubocop_args + ['--format', 'emacs', file]) }
21
22
  warnings = rubocop_warnings == '' ? '' : rubocop_warnings.split("#{File.absolute_path(file)}:").join('')
22
23
 
23
- # check Reek
24
+ # check Reek and collect warnings
24
25
  if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.1.0')
25
26
  require 'reek'
26
27
  require 'reek/cli/application'
@@ -62,19 +63,20 @@ class RubyParser
62
63
  # checks librarian puppet (Puppetfile/Modulefile) and misc ruby (Rakefile/Gemfile)
63
64
  def self.librarian(files)
64
65
  files.each do |file|
66
+ # check librarian puppet syntax
65
67
  begin
66
- # check librarian puppet syntax
68
+ # prevents ruby code from actually executing
67
69
  catch(:good) { instance_eval("BEGIN {throw :good}; #{File.read(file)}") }
68
70
  rescue SyntaxError, LoadError, ArgumentError => err
69
71
  PuppetCheck.error_files.push("-- #{file}:\n#{err}")
72
+ # check librarian puppet style
70
73
  else
71
- # check librarian puppet style
72
74
  if PuppetCheck.style_check
73
75
  require 'rubocop'
74
76
 
75
77
  # check Rubocop
76
78
  rubocop_args = PuppetCheck.rubocop_args.clone
77
- # RuboCop is confused about the first 'mod' argument in librarian puppet (and Rakefiles and Gemfiles) so disable the Style/FileName check
79
+ # RuboCop is confused about the first 'mod' argument in librarian puppet (and first requires in Rakefiles and Gemfiles) so disable the Style/FileName check
78
80
  rubocop_args.include?('--except') ? rubocop_args[rubocop_args.index('--except') + 1] = "#{rubocop_args[rubocop_args.index('--except') + 1]},Style/FileName" : rubocop_args.concat(['--except', 'Style/FileName'])
79
81
  warnings = Utils.capture_stdout { RuboCop::CLI.new.run(rubocop_args + ['--format', 'emacs', file]) }
80
82
 
@@ -21,33 +21,105 @@ class PuppetCheck::Tasks < ::Rake::TaskLib
21
21
 
22
22
  desc 'Execute RSpec and RSpec-Puppet tests'
23
23
  RSpec::Core::RakeTask.new(:spec) do |task|
24
- rspec_puppet_setup
25
- # generate tasks for all recognized directories inside of spec directories
26
- task.pattern = '**/{classes, defines, facter, functions, hosts, puppet, unit, types}/**/*_spec.rb'
24
+ self.class.rspec_puppet_setup
25
+ # generate tasks for all recognized directories and ensure spec tests inside module dependencies are ignored
26
+ spec_dirs = Dir.glob('**/{classes,defines,facter,functions,hosts,puppet,unit,types}/**/*_spec.rb').reject { |dir| dir =~ /fixtures/ }
27
+ task.pattern = spec_dirs.empty? ? 'skip_rspec' : spec_dirs
27
28
  end
28
29
 
29
30
  desc 'Execute Beaker acceptance tests'
30
31
  RSpec::Core::RakeTask.new(:beaker) do |task|
31
- task.pattern = '**/acceptance'
32
+ # generate tasks for all recognized directories and ensure acceptance tests inside module dependencies are ignored
33
+ acceptance_dirs = Dir.glob('**/acceptance').reject { |dir| dir =~ /fixtures/ }
34
+ task.pattern = acceptance_dirs.empty? ? 'skip_beaker' : acceptance_dirs
32
35
  end
33
36
  end
34
37
  end
35
38
 
36
- # prepare the directories for rspec-puppet testing
37
- def rspec_puppet_setup
38
- # leave method immediately if there is no rspec-puppet installed
39
- begin
40
- require 'rspec-puppet/setup'
41
- rescue LoadError
42
- return
43
- end
39
+ # code diagram for rspec-puppet support:
40
+ # puppetcheck:spec task invokes rspec_puppet_setup
41
+ # rspec_puppet_setup invokes rspec_puppet_file_setup always and rspec_puppet_dependency_setup if metadata.json exists
42
+ # rspec_puppet_dependency_setup invokes rspec_puppet_git/forge/hg if git/forge/hg is download option and dependencies exist
43
+
44
+ # prepare the spec fixtures directory for rspec-puppet testing
45
+ def self.rspec_puppet_setup
46
+ # ensure this method does not do anything inside module dependencies
47
+ specdirs = Dir.glob('**/spec').reject { |dir| dir =~ /fixtures/ }
48
+ return if specdirs.class.to_s == 'NilClass'
49
+
50
+ # setup fixtures for rspec-puppet testing
51
+ specdirs.each do |specdir|
52
+ # skip to next specdir if it does not seem like a puppet module
53
+ next unless File.directory?(specdir + '/../manifests')
44
54
 
45
- # executes rspec::puppet::setup in every module directory to ensure module spec directories are configured correctly
46
- Dir.glob('**/spec').each do |specdir|
55
+ # move up to module directory
47
56
  Dir.chdir(specdir + '/..')
48
- RSpec::Puppet::Setup.run
57
+
58
+ # grab the module name from the directory name of the module to pass to rspec_puppet_file_setup
59
+ rspec_puppet_file_setup(File.basename(Dir.pwd))
60
+
61
+ # invoke rspec_puppet_dependency_setup for module dependencies if metadata.json present
62
+ rspec_puppet_dependency_setup if File.file?('metadata.json')
63
+ end
64
+ end
65
+
66
+ # setup the files, directories, and symlinks for rspec-puppet testing
67
+ def self.rspec_puppet_file_setup(module_name)
68
+ # create all the necessary fixture dirs that are missing
69
+ ['spec/fixtures', 'spec/fixtures/manifests', 'spec/fixtures/modules', "spec/fixtures/modules/#{module_name}"].each do |dir|
70
+ FileUtils.mkdir(dir) unless File.directory?(dir)
71
+ end
72
+
73
+ # create empty site.pp if missing
74
+ FileUtils.touch('spec/fixtures/manifests/site.pp') unless File.file?('spec/fixtures/manifests/site.pp')
75
+
76
+ # symlink over everything the module needs for compilation
77
+ %w(hiera.yaml data hieradata functions manifests lib files templates).each do |file|
78
+ FileUtils.ln_s("../../../../#{file}", "spec/fixtures/modules/#{module_name}/#{file}") if File.exist?(file) && !File.exist?("spec/fixtures/modules/#{module_name}/#{file}")
79
+ end
80
+
81
+ # create spec_helper if missing
82
+ unless File.file?('spec/spec_helper.rb')
83
+ File.open('spec/spec_helper.rb', 'w') { |file| file.puts "require 'rspec-puppet/spec_helper'\n" }
84
+ end
85
+ end
86
+
87
+ # setup the module dependencies for rspec-puppet testing
88
+ def self.rspec_puppet_dependency_setup
89
+ # parse the metadata.json (assumes PuppetCheck file checks have already given it a pass)
90
+ parsed = JSON.parse(File.read('metadata.json'))
91
+
92
+ # grab dependencies if they exist
93
+ unless parsed['dependencies'].empty?
94
+ parsed['dependencies'].each do |dependency_hash|
95
+ # determine how the user wants to download the module dependency
96
+ if dependency_hash.key?('git')
97
+ rspec_puppet_git(dependency_hash['git'])
98
+ elsif dependency_hash.key?('forge')
99
+ rspec_puppet_forge(dependency_hash['forge'])
100
+ elsif dependency_hash.key?('hg')
101
+ rspec_puppet_hg(dependency_hash['hg'])
102
+ else
103
+ warn "#{dependency_hash['name']} has an unspecified, or specified but unsupported, download method."
104
+ end
105
+ end
49
106
  end
50
107
  end
108
+
109
+ # download external module dependency with git
110
+ def self.rspec_puppet_git(git_url)
111
+ system("git -C spec/fixtures/modules/ clone #{git_url}")
112
+ end
113
+
114
+ # download external module dependency with forge
115
+ def self.rspec_puppet_forge(forge_name)
116
+ system("puppet module install #{forge_name} --modulepath spec/fixtures/modules/ --force")
117
+ end
118
+
119
+ # download external module dependency with hg
120
+ def self.rspec_puppet_hg(hg_url)
121
+ system("hg --cwd spec/fixtures/modules/ clone #{hg_url}")
122
+ end
51
123
  end
52
124
 
53
125
  PuppetCheck::Tasks.new
@@ -1,4 +1 @@
1
- # class is for rspec-puppet to generate module name for testing
2
- class fixtures::good {
3
- notify { 'i am a good manifest': }
4
- }
1
+ notify { 'i am a good manifest': }
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "puppetlabs-awesomesauce",
3
+ "version": "1.1.1",
4
+ "author": "puppetlabs",
5
+ "summary": "Makes sauce that is awesome.",
6
+ "license": "Proprietary",
7
+ "source": "https://github.com/puppetlabs/puppetlabs-awesomesauce",
8
+ "project_page": "https://github.com/puppetlabs/puppetlabs-awesomesauce",
9
+ "issues_url": "https://tickets.puppetlabs.com/browse/MODULES",
10
+ "operatingsystem_support": [
11
+ {
12
+ "operatingsystem": "RedHat",
13
+ "operatingsystemrelease": [
14
+ "100",
15
+ "5",
16
+ "6",
17
+ "7"
18
+ ]
19
+ }
20
+ ],
21
+ "requirements": [
22
+ {
23
+ "name": "pe",
24
+ "version_requirement": ">= 3.0.0 < 2035.1.0"
25
+ },
26
+ {
27
+ "name": "puppet",
28
+ "version_requirement": ">=2.7.20 <5.0.0"
29
+ }
30
+ ],
31
+ "description": "Makes sauce that is awesome. What part of that is confusing?",
32
+ "dependencies": [
33
+ {
34
+ "name": "puppetlabs/stdlib",
35
+ "version_requirement": ">= 4.1.0 < 5.0.0",
36
+ "forge": "puppetlabs-stdlib"
37
+ },
38
+ {
39
+ "name": "puppetlabs/lvm",
40
+ "version_requirement": ">= 0.5.0 < 1.0.0",
41
+ "git": "https://github.com/puppetlabs/puppetlabs-lvm.git"
42
+ },
43
+ {
44
+ "name": "puppetlabs/gruntmaster",
45
+ "version_requirement": ">= 6000 < 9000",
46
+ "software": "upgradeable"
47
+ }
48
+ ]
49
+ }
@@ -27,6 +27,12 @@ describe PuppetCheck::CLI do
27
27
  expect(PuppetCheck.puppetlint_args).to eql(['--puppetlint-arg-one', '--puppetlint-arg-two'])
28
28
  end
29
29
 
30
+ it 'correctly loads a .puppet-lint.rc' do
31
+ PuppetCheck.puppetlint_args = []
32
+ PuppetCheck::CLI.parse(%W(-c #{fixtures_dir}/manifests/.puppet-lint.rc))
33
+ expect(PuppetCheck.puppetlint_args).to eql(['--puppetlint-arg-one', '--puppetlint-arg-two'])
34
+ end
35
+
30
36
  it 'correctly parses Rubocop arguments' do
31
37
  PuppetCheck.rubocop_args = []
32
38
  PuppetCheck::CLI.parse(%w(--rubocop rubocop-arg-one,rubocop-arg-two foo))
@@ -18,7 +18,7 @@ describe DataParser do
18
18
  it 'puts a good yaml file with potential hiera issues in the warning files array' do
19
19
  DataParser.yaml([fixtures_dir + 'hieradata/style.yaml'])
20
20
  expect(PuppetCheck.error_files).to eql([])
21
- expect(PuppetCheck.warning_files[0]).to match(%r{^\-\- #{fixtures_dir}hieradata/style.yaml:\nValues missing in key})
21
+ expect(PuppetCheck.warning_files[0]).to match(%r{^\-\- #{fixtures_dir}hieradata/style.yaml:\nValue\(s\) missing in key.*\nValue\(s\) missing in key})
22
22
  expect(PuppetCheck.clean_files).to eql([])
23
23
  end
24
24
  it 'puts a good yaml file in the clean files array' do
@@ -23,14 +23,14 @@ describe PuppetParser do
23
23
  PuppetCheck.style_check = true
24
24
  PuppetParser.manifest([fixtures_dir + 'manifests/style_parser.pp'])
25
25
  expect(PuppetCheck.error_files).to eql([])
26
- expect(PuppetCheck.warning_files[0]).to match(%r{^\-\- #{fixtures_dir}manifests/style_parser.pp:\nUnrecognized escape sequence.*\nUnrecognized escape sequence.*\ndouble quoted string containing})
26
+ expect(PuppetCheck.warning_files[0]).to match(%r{^\-\- #{fixtures_dir}manifests/style_parser.pp:\nUnrecognized escape sequence.*\nUnrecognized escape sequence.*\n.*double quoted string containing})
27
27
  expect(PuppetCheck.clean_files).to eql([])
28
28
  end
29
29
  it 'puts a bad lint style Puppet manifest in the warning files array' do
30
30
  PuppetCheck.style_check = true
31
31
  PuppetParser.manifest([fixtures_dir + 'manifests/style_lint.pp'])
32
32
  expect(PuppetCheck.error_files).to eql([])
33
- expect(PuppetCheck.warning_files[0]).to match(%r{^\-\- #{fixtures_dir}manifests/style_lint.pp:\ndouble quoted string containing.*\nindentation of})
33
+ expect(PuppetCheck.warning_files[0]).to match(%r{^\-\- #{fixtures_dir}manifests/style_lint.pp:\n.*double quoted string containing.*\n.*indentation of})
34
34
  expect(PuppetCheck.clean_files).to eql([])
35
35
  end
36
36
  it 'puts a bad style Puppet manifest in the clean files array when puppetlint_args ignores its warnings' do
@@ -10,22 +10,50 @@ describe PuppetCheck::Tasks do
10
10
  Dir.chdir(fixtures_dir)
11
11
 
12
12
  # rspec task executed
13
- expect { spec_tasks }.to output(/ruby.*rspec/).to_stdout
13
+ expect { spec_tasks }.to output(%r{spec/facter/facter_spec.rb}).to_stdout
14
14
  # if this is first then the stdout is not captured for testing
15
15
  expect { spec_tasks }.not_to raise_exception
16
- # rspec-puppet setup executed
17
- expect(File.directory?('spec/fixtures/modules/fixtures')).to be true
18
16
 
19
- # cleanup rspec-puppet setup
20
- %w(Rakefile spec/spec_helper.rb).each { |file| File.delete(file) }
17
+ # cleanup rspec_puppet_setup
18
+ %w(spec/spec_helper.rb).each { |file| File.delete(file) }
21
19
  %w(manifests modules).each { |dir| FileUtils.rm_r('spec/fixtures/' + dir) }
22
20
  end
23
21
  end
24
22
 
25
23
  context 'puppetcheck:beaker' do
24
+ let(:beaker_tasks) { Rake::Task['puppetcheck:beaker'.to_sym].invoke }
25
+
26
26
  it 'verifies the Beaker task exists' do
27
27
  Dir.chdir(fixtures_dir)
28
- expect { Rake::Task['puppetcheck:spec'.to_sym].invoke }.not_to raise_exception
28
+
29
+ # beaker task executed
30
+ expect { beaker_tasks }.to output(%r{spec/acceptance}).to_stdout
31
+ expect { beaker_tasks }.not_to raise_exception
32
+ end
33
+ end
34
+
35
+ context '.rspec_puppet_setup' do
36
+ let(:rspec_puppet_setup) { PuppetCheck::Tasks.rspec_puppet_setup }
37
+ before(:each) { Dir.chdir(fixtures_dir) }
38
+
39
+ it 'creates missing directories, missing site.pp, missing symlinks, and a missing spec_helper' do
40
+ expect { rspec_puppet_setup }.to output("puppetlabs/gruntmaster has an unspecified, or specified but unsupported, download method.\n").to_stderr
41
+
42
+ expect(File.directory?('spec/fixtures/manifests')).to be true
43
+ expect(File.directory?('spec/fixtures/modules/fixtures')).to be true
44
+ expect(File.file?('spec/fixtures/manifests/site.pp')).to be true
45
+ expect(File.symlink?('spec/fixtures/modules/fixtures/hieradata')).to be true
46
+ expect(File.symlink?('spec/fixtures/modules/fixtures/manifests')).to be true
47
+ expect(File.symlink?('spec/fixtures/modules/fixtures/lib')).to be true
48
+ expect(File.symlink?('spec/fixtures/modules/fixtures/templates')).to be true
49
+ expect(File.file?('spec/spec_helper.rb')).to be true
50
+
51
+ expect(File.directory?('spec/fixtures/modules/puppetlabs-lvm')).to be true
52
+ expect(File.directory?('spec/fixtures/modules/stdlib')).to be true
53
+
54
+ # cleanup rspec_puppet_setup
55
+ %w(spec/spec_helper.rb).each { |file| File.delete(file) }
56
+ %w(manifests modules).each { |dir| FileUtils.rm_r('spec/fixtures/' + dir) }
29
57
  end
30
58
  end
31
59
  end
@@ -4,7 +4,7 @@ require_relative '../lib/puppet-check'
4
4
  describe PuppetCheck do
5
5
  let(:puppetcheck) { PuppetCheck.new }
6
6
 
7
- context 'initializes and' do
7
+ context 'self' do
8
8
  it 'future parser can be altered' do
9
9
  PuppetCheck.future_parser = true
10
10
  expect(PuppetCheck.future_parser).to eql(true)
@@ -33,7 +33,7 @@ describe PuppetCheck do
33
33
  let(:repeats) { puppetcheck.parse_paths(['hieradata', 'hieradata', 'lib', 'hieradata/good.json', 'manifests/good.pp', 'manifests/good.pp']) }
34
34
 
35
35
  it 'raises an error if no files were found' do
36
- expect { no_files }.to raise_error(RuntimeError, 'No files found in supplied paths foo, bar, baz.')
36
+ expect { no_files }.to raise_error(RuntimeError, 'puppet-check: no files found in supplied paths foo, bar, baz.')
37
37
  end
38
38
 
39
39
  it 'correctly parses one file and returns it' do
@@ -42,7 +42,7 @@ describe PuppetCheck do
42
42
 
43
43
  it 'correctly parses one directory and returns all of its files' do
44
44
  dir.each { |file| expect(File.file?(file)).to be true }
45
- expect(dir.length).to eql(27)
45
+ expect(dir.length).to eql(28)
46
46
  end
47
47
 
48
48
  it 'correctly parses multiple directories and returns all of their files' do
@@ -78,7 +78,7 @@ describe PuppetCheck do
78
78
  end
79
79
  it 'outputs files that were not processed' do
80
80
  PuppetCheck.ignored_files = ['-- foo: who knows what i am']
81
- expect { PuppetCheck.output_results }.to output("\n\033[34mThe following files have unrecognized formats and therefore were not processed:\033[0m\n-- foo: who knows what i am\n").to_stdout
81
+ expect { PuppetCheck.output_results }.to output("\n\033[36mThe following files have unrecognized formats and therefore were not processed:\033[0m\n-- foo: who knows what i am\n").to_stdout
82
82
  end
83
83
  end
84
84
  end
@@ -14,7 +14,7 @@ describe 'PuppetCheck' do
14
14
  expect { cli }.not_to raise_exception
15
15
  expect(PuppetCheck.error_files.length).to eql(8)
16
16
  expect(PuppetCheck.warning_files.length).to eql(8)
17
- expect(PuppetCheck.clean_files.length).to eql(10)
17
+ expect(PuppetCheck.clean_files.length).to eql(11)
18
18
  expect(PuppetCheck.ignored_files.length).to eql(1)
19
19
  end
20
20
  end
@@ -35,7 +35,7 @@ describe 'PuppetCheck' do
35
35
  expect { tasks }.not_to raise_exception
36
36
  expect(PuppetCheck.error_files.length).to eql(8)
37
37
  expect(PuppetCheck.warning_files.length).to eql(8)
38
- expect(PuppetCheck.clean_files.length).to eql(10)
38
+ expect(PuppetCheck.clean_files.length).to eql(11)
39
39
  expect(PuppetCheck.ignored_files.length).to eql(1)
40
40
  end
41
41
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puppet-check
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Schuchard
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-05-22 00:00:00.000000000 Z
11
+ date: 2016-06-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: puppet
@@ -106,20 +106,6 @@ dependencies:
106
106
  - - "<"
107
107
  - !ruby/object:Gem::Version
108
108
  version: '12'
109
- - !ruby/object:Gem::Dependency
110
- name: rspec-puppet
111
- requirement: !ruby/object:Gem::Requirement
112
- requirements:
113
- - - "~>"
114
- - !ruby/object:Gem::Version
115
- version: '2.0'
116
- type: :development
117
- prerelease: false
118
- version_requirements: !ruby/object:Gem::Requirement
119
- requirements:
120
- - - "~>"
121
- - !ruby/object:Gem::Version
122
- version: '2.0'
123
109
  description: Puppet Check is a gem that provides a comprehensive, streamlined, and
124
110
  efficient analysis of the syntax, style, and validity of your entire Puppet code
125
111
  and data.
@@ -157,6 +143,7 @@ files:
157
143
  - spec/fixtures/manifests/style_lint.pp
158
144
  - spec/fixtures/manifests/style_parser.pp
159
145
  - spec/fixtures/manifests/syntax.pp
146
+ - spec/fixtures/metadata.json
160
147
  - spec/fixtures/metadata_good/metadata.json
161
148
  - spec/fixtures/metadata_style/metadata.json
162
149
  - spec/fixtures/metadata_syntax/metadata.json
@@ -168,7 +155,6 @@ files:
168
155
  - spec/fixtures/templates/style.erb
169
156
  - spec/fixtures/templates/syntax.epp
170
157
  - spec/fixtures/templates/syntax.erb
171
- - spec/integration/integration_spec.rb
172
158
  - spec/puppet-check/cli_spec.rb
173
159
  - spec/puppet-check/data_parser_spec.rb
174
160
  - spec/puppet-check/puppet_parser_spec.rb
@@ -177,6 +163,7 @@ files:
177
163
  - spec/puppet-check/utils_spec.rb
178
164
  - spec/puppet-check_spec.rb
179
165
  - spec/spec_helper.rb
166
+ - spec/system/system_spec.rb
180
167
  homepage: https://www.github.com/mschuchard/puppet-check
181
168
  licenses:
182
169
  - MIT
@@ -220,6 +207,7 @@ test_files:
220
207
  - spec/fixtures/manifests/style_lint.pp
221
208
  - spec/fixtures/manifests/style_parser.pp
222
209
  - spec/fixtures/manifests/syntax.pp
210
+ - spec/fixtures/metadata.json
223
211
  - spec/fixtures/metadata_good/metadata.json
224
212
  - spec/fixtures/metadata_style/metadata.json
225
213
  - spec/fixtures/metadata_syntax/metadata.json
@@ -231,7 +219,6 @@ test_files:
231
219
  - spec/fixtures/templates/style.erb
232
220
  - spec/fixtures/templates/syntax.epp
233
221
  - spec/fixtures/templates/syntax.erb
234
- - spec/integration/integration_spec.rb
235
222
  - spec/puppet-check/cli_spec.rb
236
223
  - spec/puppet-check/data_parser_spec.rb
237
224
  - spec/puppet-check/puppet_parser_spec.rb
@@ -240,3 +227,4 @@ test_files:
240
227
  - spec/puppet-check/utils_spec.rb
241
228
  - spec/puppet-check_spec.rb
242
229
  - spec/spec_helper.rb
230
+ - spec/system/system_spec.rb