puppet-lint 0.4.0.pre1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. data/.travis.yml +3 -4
  2. data/Gemfile +2 -5
  3. data/README.md +2 -149
  4. data/Rakefile +0 -5
  5. data/lib/puppet-lint.rb +74 -20
  6. data/lib/puppet-lint/bin.rb +20 -85
  7. data/lib/puppet-lint/checkplugin.rb +158 -12
  8. data/lib/puppet-lint/checks.rb +39 -222
  9. data/lib/puppet-lint/configuration.rb +12 -31
  10. data/lib/puppet-lint/data.rb +329 -0
  11. data/lib/puppet-lint/lexer.rb +37 -30
  12. data/lib/puppet-lint/lexer/token.rb +14 -16
  13. data/lib/puppet-lint/monkeypatches/string_prepend.rb +6 -0
  14. data/lib/puppet-lint/optparser.rb +105 -0
  15. data/lib/puppet-lint/plugins.rb +28 -9
  16. data/lib/puppet-lint/plugins/check_classes.rb +162 -238
  17. data/lib/puppet-lint/plugins/check_comments.rb +40 -25
  18. data/lib/puppet-lint/plugins/check_conditionals.rb +16 -20
  19. data/lib/puppet-lint/plugins/check_documentation.rb +14 -20
  20. data/lib/puppet-lint/plugins/check_nodes.rb +23 -0
  21. data/lib/puppet-lint/plugins/check_resources.rb +127 -141
  22. data/lib/puppet-lint/plugins/check_strings.rb +133 -107
  23. data/lib/puppet-lint/plugins/check_variables.rb +11 -11
  24. data/lib/puppet-lint/plugins/check_whitespace.rb +86 -92
  25. data/lib/puppet-lint/tasks/puppet-lint.rb +17 -1
  26. data/lib/puppet-lint/version.rb +1 -1
  27. data/puppet-lint.gemspec +4 -2
  28. data/spec/fixtures/test/manifests/ignore.pp +1 -0
  29. data/spec/fixtures/test/manifests/ignore_reason.pp +1 -0
  30. data/spec/puppet-lint/bin_spec.rb +104 -84
  31. data/spec/puppet-lint/configuration_spec.rb +19 -19
  32. data/spec/puppet-lint/ignore_overrides_spec.rb +97 -0
  33. data/spec/puppet-lint/lexer/token_spec.rb +9 -9
  34. data/spec/puppet-lint/lexer_spec.rb +352 -325
  35. data/spec/puppet-lint/plugins/check_classes/autoloader_layout_spec.rb +77 -23
  36. data/spec/puppet-lint/plugins/check_classes/class_inherits_from_params_class_spec.rb +14 -12
  37. data/spec/puppet-lint/plugins/check_classes/inherits_across_namespaces_spec.rb +18 -14
  38. data/spec/puppet-lint/plugins/check_classes/names_containing_dash_spec.rb +30 -30
  39. data/spec/puppet-lint/plugins/check_classes/nested_classes_or_defines_spec.rb +31 -26
  40. data/spec/puppet-lint/plugins/check_classes/parameter_order_spec.rb +34 -28
  41. data/spec/puppet-lint/plugins/check_classes/right_to_left_relationship_spec.rb +14 -12
  42. data/spec/puppet-lint/plugins/check_classes/variable_scope_spec.rb +74 -30
  43. data/spec/puppet-lint/plugins/check_comments/slash_comments_spec.rb +27 -20
  44. data/spec/puppet-lint/plugins/check_comments/star_comments_spec.rb +78 -13
  45. data/spec/puppet-lint/plugins/check_conditionals/case_without_default_spec.rb +17 -12
  46. data/spec/puppet-lint/plugins/check_conditionals/selector_inside_resource_spec.rb +13 -10
  47. data/spec/puppet-lint/plugins/check_documentation/documentation_spec.rb +21 -16
  48. data/spec/puppet-lint/plugins/check_nodes/unquoted_node_name_spec.rb +69 -0
  49. data/spec/puppet-lint/plugins/check_resources/duplicate_params_spec.rb +42 -38
  50. data/spec/puppet-lint/plugins/check_resources/ensure_first_param_spec.rb +22 -10
  51. data/spec/puppet-lint/plugins/check_resources/ensure_not_symlink_target_spec.rb +81 -18
  52. data/spec/puppet-lint/plugins/check_resources/file_mode_spec.rb +69 -112
  53. data/spec/puppet-lint/plugins/check_resources/unquoted_file_mode_spec.rb +27 -20
  54. data/spec/puppet-lint/plugins/check_resources/unquoted_resource_title_spec.rb +177 -171
  55. data/spec/puppet-lint/plugins/check_strings/double_quoted_strings_spec.rb +165 -88
  56. data/spec/puppet-lint/plugins/check_strings/only_variable_string_spec.rb +97 -22
  57. data/spec/puppet-lint/plugins/check_strings/puppet_url_without_modules_spec.rb +25 -0
  58. data/spec/puppet-lint/plugins/check_strings/quoted_booleans_spec.rb +97 -111
  59. data/spec/puppet-lint/plugins/check_strings/single_quote_string_with_variables_spec.rb +10 -9
  60. data/spec/puppet-lint/plugins/check_strings/variables_not_enclosed_spec.rb +53 -53
  61. data/spec/puppet-lint/plugins/check_variables/variable_contains_dash_spec.rb +26 -14
  62. data/spec/puppet-lint/plugins/check_whitespace/2sp_soft_tabs_spec.rb +10 -9
  63. data/spec/puppet-lint/plugins/check_whitespace/80chars_spec.rb +31 -15
  64. data/spec/puppet-lint/plugins/check_whitespace/arrow_alignment_spec.rb +340 -322
  65. data/spec/puppet-lint/plugins/check_whitespace/hard_tabs_spec.rb +30 -23
  66. data/spec/puppet-lint/plugins/check_whitespace/trailing_whitespace_spec.rb +42 -41
  67. data/spec/puppet-lint_spec.rb +3 -3
  68. data/spec/spec_helper.rb +109 -116
  69. metadata +109 -50
  70. data/spec/puppet-lint/plugins/check_classes/class_parameter_defaults_spec.rb +0 -60
data/.travis.yml CHANGED
@@ -1,11 +1,10 @@
1
+ before_install: gem update --system 2.1.11
1
2
  rvm:
2
3
  - 1.8.7
3
4
  - 1.9.2
4
5
  - 1.9.3
5
- branches:
6
- only:
7
- - master
8
- - dust_bunny
6
+ - 2.0.0
7
+ - 2.1.0
9
8
  notifications:
10
9
  email:
11
10
  - tim@github.com
data/Gemfile CHANGED
@@ -1,6 +1,3 @@
1
- source :rubygems
1
+ source 'https://rubygems.org'
2
2
 
3
- gem 'rake'
4
- gem 'rspec'
5
- gem 'ruby-prof'
6
- gem 'rcov', :platform => :ruby_18
3
+ gemspec
data/README.md CHANGED
@@ -2,12 +2,11 @@
2
2
 
3
3
  [![Build
4
4
  Status](https://secure.travis-ci.org/rodjek/puppet-lint.png)](http://travis-ci.org/rodjek/puppet-lint)
5
- [![Dependency
6
- Status](https://gemnasium.com/rodjek/puppet-lint.png)](http://gemnasium.com/rodjek/puppet-lint)
5
+ [![Inline docs](http://inch-ci.org/github/rodjek/puppet-lint.png?branch=master)](http://inch-ci.org/github/rodjek/puppet-lint)
7
6
 
8
7
  The goal of this project is to implement as many of the recommended Puppet
9
8
  style guidelines from the [Puppet Labs style
10
- guide](http://docs.puppetlabs.com/guides/style_guide.html) as practical.
9
+ guide](http://docs.puppetlabs.com/guides/style_guide.html) as practical. It is not meant to validate syntax. Please use `puppet parser validate` for that.
11
10
 
12
11
  ## Installation
13
12
 
@@ -82,151 +81,6 @@ At the moment, the following tests have been implemented:
82
81
  * When using top-scope variables, including facts, Puppet modules should
83
82
  explicitly specify the empty namespace.
84
83
 
85
- ## Fixing problems
86
-
87
- ### right_to_left_relationship
88
-
89
- ```
90
- WARNING: right-to-left (<-) relationship on line X
91
- ```
92
-
93
- While right to left relationships are perfectly valid, it's highly recommended
94
- that you don't use them as most people think and read from left to right and
95
- this can lead to confusion.
96
-
97
- Bad:
98
-
99
- ```
100
- Service['httpd'] <- Package['httpd']
101
- ```
102
-
103
- Good:
104
-
105
- ```
106
- Package['httpd'] -> Service['httpd']
107
- ```
108
-
109
- ### autoloader_layout
110
-
111
- ```
112
- ERROR: mymodule::myclass not in autoload module layout on line X
113
- ```
114
-
115
- Puppet attempts to autoload only the required manifests for the resources and
116
- classes specified in your manifests. In order to do this, the autoloader
117
- expects your manifests to be laid out on disk in a particular format. For
118
- example, when you use `mymodule::myclass` in your manifests, Puppet will
119
- attempt to read `<modulepath>/mymodule/manifests/myclass.pp`. The only
120
- exception to this is when you reference `mymodule` itself (without any
121
- subclass/subtype) in which case it will read
122
- `<modulepath>/mymodule/manifests/init.pp`.
123
-
124
- ### parameter_order
125
-
126
- ```
127
- WARNING: optional parameter listed before required parameter on line X
128
- ```
129
-
130
- In parameterised class and defined type definitions, parameters that are
131
- required should be listed before optional parameters (those with default
132
- values).
133
-
134
- Bad:
135
-
136
- ```
137
- class foo($bar='baz', $gronk) {
138
- ```
139
-
140
- Good:
141
-
142
- ```
143
- class foo($gronk, $bar='baz') {
144
- ```
145
-
146
- ### inherits_across_namespaces
147
-
148
- Placeholder
149
-
150
- ### nested_classes_or_defines
151
-
152
- Placeholder
153
-
154
- ### variable_scope
155
-
156
- Placeholder
157
-
158
- ### selector_inside_resource
159
-
160
- Placeholder
161
-
162
- ### case_without_default
163
-
164
- Placeholder
165
-
166
- ### unquoted_resource_title
167
-
168
- Placeholder
169
-
170
- ### ensure_first_param
171
-
172
- Placeholder
173
-
174
- ### unquoted_file_mode
175
-
176
- Placeholder
177
-
178
- ### 4digit_file_mode
179
-
180
- Placeholder
181
-
182
- ### ensure_not_symlink_target
183
-
184
- Placeholder
185
-
186
- ### double_quoted_strings
187
-
188
- Placeholder
189
-
190
- ### only_variable_string
191
-
192
- Placeholder
193
-
194
- ### variables_not_enclosed
195
-
196
- Placeholder
197
-
198
- ### single_quote_string_with_variables
199
-
200
- Placeholder
201
-
202
- ### quoted_booleans
203
-
204
- Placeholder
205
-
206
- ### variable_contains_dash
207
-
208
- Placeholder
209
-
210
- ### hard_tabs
211
-
212
- Placeholder
213
-
214
- ### trailing_whitespace
215
-
216
- Placeholder
217
-
218
- ### 80chars
219
-
220
- Placeholder
221
-
222
- ### 2sp_soft_tabs
223
-
224
- Placeholder
225
-
226
- ### arrow_alignment
227
-
228
- Placeholder
229
-
230
84
  ## Disabling checks
231
85
 
232
86
  ### puppet-lint
@@ -254,7 +108,6 @@ For a list of all the flags just type:
254
108
  puppet-lint --help
255
109
  ```
256
110
 
257
-
258
111
  ### Rake task
259
112
 
260
113
  You can also disable checks when running puppet-lint through the supplied Rake
data/Rakefile CHANGED
@@ -4,8 +4,3 @@ require 'rspec/core/rake_task'
4
4
  task :default => :test
5
5
 
6
6
  RSpec::Core::RakeTask.new(:test)
7
-
8
- RSpec::Core::RakeTask.new(:cov) do |t|
9
- t.rcov = true
10
- t.rcov_opts = '--exclude "spec" --xrefs'
11
- end
data/lib/puppet-lint.rb CHANGED
@@ -1,23 +1,52 @@
1
+ require 'set'
1
2
  require 'puppet-lint/version'
2
3
  require 'puppet-lint/lexer'
3
4
  require 'puppet-lint/configuration'
5
+ require 'puppet-lint/data'
4
6
  require 'puppet-lint/checks'
5
7
  require 'puppet-lint/bin'
6
8
  require 'puppet-lint/monkeypatches'
7
9
 
8
10
  class PuppetLint::NoCodeError < StandardError; end
11
+ class PuppetLint::NoFix < StandardError; end
9
12
 
13
+ # Public: The public interface to puppet-lint.
10
14
  class PuppetLint
11
15
  # Public: Gets/Sets the String manifest code to be checked.
12
16
  attr_accessor :code
13
17
 
18
+ # Public: Gets the String manifest with the errors fixed.
14
19
  attr_reader :manifest
15
20
 
21
+ # Public: Returns an Array of Hashes describing the problems found in the
22
+ # manifest.
23
+ #
24
+ # Each Hash will contain *at least*:
25
+ # :check - The Symbol name of the check that generated the problem.
26
+ # :kind - The Symbol kind of the problem (:error, :warning, or
27
+ # :fixed).
28
+ # :line - The Integer line number of the location of the problem in
29
+ # the manifest.
30
+ # :column - The Integer column number of the location of the problem in
31
+ # the manifest.
32
+ # :message - The String message describing the problem that was found.
33
+ attr_reader :problems
34
+
35
+ # Public: Gets/Sets the String path to the manifest to be checked.
36
+ attr_accessor :path
37
+
38
+ # Public: Returns a Hash of linter statistics
39
+ #
40
+ # :error - An Integer count of errors found in the manifest.
41
+ # :warning - An Integer count of warnings found in the manifest.
42
+ # :fixed - An Integer count of problems found in the manifest that were
43
+ # automatically fixed.
44
+ attr_reader :statistics
45
+
16
46
  # Public: Initialise a new PuppetLint object.
17
47
  def initialize
18
48
  @code = nil
19
- @statistics = {:error => 0, :warning => 0, :fixed => 0}
20
- @fileinfo = {:path => ''}
49
+ @statistics = {:error => 0, :warning => 0, :fixed => 0, :ignored => 0}
21
50
  @manifest = ''
22
51
  end
23
52
 
@@ -41,9 +70,7 @@ class PuppetLint
41
70
  # Returns nothing.
42
71
  def file=(path)
43
72
  if File.exist? path
44
- @fileinfo[:path] = path
45
- @fileinfo[:fullpath] = File.expand_path(path)
46
- @fileinfo[:filename] = File.basename(path)
73
+ @path = path
47
74
  @code = File.read(path)
48
75
  end
49
76
  end
@@ -56,7 +83,7 @@ class PuppetLint
56
83
  def log_format
57
84
  if configuration.log_format == ''
58
85
  ## recreate previous old log format as far as thats possible.
59
- format = '%{KIND}: %{message} on line %{linenumber}'
86
+ format = '%{KIND}: %{message} on line %{line}'
60
87
  if configuration.with_filename
61
88
  format.prepend '%{path} - '
62
89
  end
@@ -73,22 +100,22 @@ class PuppetLint
73
100
  def format_message(message)
74
101
  format = log_format
75
102
  puts format % message
103
+ if message[:kind] == :ignored && !message[:reason].nil?
104
+ puts " #{message[:reason]}"
105
+ end
76
106
  end
77
107
 
78
108
  # Internal: Print out the line of the manifest on which the problem was found
79
109
  # as well as a marker pointing to the location on the line.
80
110
  #
81
111
  # message - A Hash containing all the information about a problem.
82
- # linter - The PuppetLint::Checks object that was used to test the manifest.
83
112
  #
84
113
  # Returns nothing.
85
- def print_context(message, linter)
86
- # XXX: I don't really like the way this has been implemented (passing the
87
- # linter object down through layers of functions. Refactor me!
114
+ def print_context(message)
88
115
  return if message[:check] == 'documentation'
89
116
  return if message[:kind] == :fixed
90
- line = linter.manifest_lines[message[:linenumber] - 1]
91
- offset = line.index(/\S/)
117
+ line = PuppetLint::Data.manifest_lines[message[:line] - 1]
118
+ offset = line.index(/\S/) || 1
92
119
  puts "\n #{line.strip}"
93
120
  printf "%#{message[:column] + 2 - offset}s\n\n", '^'
94
121
  end
@@ -97,20 +124,18 @@ class PuppetLint
97
124
  #
98
125
  # problems - An Array of problem Hashes as returned by
99
126
  # PuppetLint::Checks#run.
100
- # linter - The PuppetLint::Checks object that was used to test the
101
- # manifest.
102
127
  #
103
128
  # Returns nothing.
104
- def report(problems, linter)
129
+ def report(problems)
105
130
  problems.each do |message|
106
- @statistics[message[:kind]] += 1
131
+ next if message[:kind] == :ignored && !PuppetLint.configuration.show_ignored
107
132
 
108
- message.merge!(@fileinfo) {|key, v1, v2| v1 }
109
133
  message[:KIND] = message[:kind].to_s.upcase
134
+ message[:linenumber] = message[:line]
110
135
 
111
136
  if message[:kind] == :fixed || [message[:kind], :all].include?(configuration.error_level)
112
137
  format_message message
113
- print_context(message, linter) if configuration.with_context
138
+ print_context(message) if configuration.with_context
114
139
  end
115
140
  end
116
141
  end
@@ -140,11 +165,40 @@ class PuppetLint
140
165
  end
141
166
 
142
167
  linter = PuppetLint::Checks.new
143
- problems = linter.run(@fileinfo, @code)
168
+ @problems = linter.run(@path, @code)
169
+ @problems.each { |problem| @statistics[problem[:kind]] += 1 }
144
170
 
145
171
  @manifest = linter.manifest if PuppetLint.configuration.fix
172
+ end
173
+
174
+ # Public: Print any problems that were found out to stdout.
175
+ #
176
+ # Returns nothing.
177
+ def print_problems
178
+ report @problems
179
+ end
146
180
 
147
- report problems, linter
181
+ # Public: Define a new check.
182
+ #
183
+ # name - A unique name for the check as a Symbol.
184
+ # block - The check logic. This must contain a `check` method and optionally
185
+ # a `fix` method.
186
+ #
187
+ # Returns nothing.
188
+ #
189
+ # Examples
190
+ #
191
+ # PuppetLint.new_check(:foo) do
192
+ # def check
193
+ # end
194
+ # end
195
+ def self.new_check(name, &block)
196
+ class_name = name.to_s.split('_').map(&:capitalize).join
197
+ klass = PuppetLint.const_set("Check#{class_name}", Class.new(PuppetLint::CheckPlugin))
198
+ klass.const_set('NAME', name)
199
+ klass.class_exec(&block)
200
+ PuppetLint.configuration.add_check(name, klass)
201
+ PuppetLint::Data.ignore_overrides[name] ||= {}
148
202
  end
149
203
  end
150
204
 
@@ -1,10 +1,16 @@
1
- require 'optparse'
1
+ require 'puppet-lint/optparser'
2
2
 
3
+ # Internal: The logic of the puppet-lint bin script, contained in a class for
4
+ # ease of testing.
3
5
  class PuppetLint::Bin
4
6
  # Public: Initialise a new PuppetLint::Bin.
5
7
  #
6
8
  # args - An Array of command line argument Strings to be passed to the option
7
9
  # parser.
10
+ #
11
+ # Examples
12
+ #
13
+ # PuppetLint::Bin.new(ARGV).run
8
14
  def initialize(args)
9
15
  @args = args
10
16
  end
@@ -13,88 +19,7 @@ class PuppetLint::Bin
13
19
  #
14
20
  # Returns an Integer exit code to be passed back to the shell.
15
21
  def run
16
- help = <<-EOHELP
17
- Puppet-lint
18
-
19
- Basic Command Line Usage:
20
- puppet-lint [OPTIONS] [PATH]
21
-
22
- PATH The path to the Puppet manifest.
23
-
24
- Options:
25
- EOHELP
26
-
27
- opts = OptionParser.new do |opts|
28
- opts.banner = help
29
-
30
- opts.on("--version", "Display current version.") do
31
- puts "Puppet-lint " + PuppetLint::VERSION
32
- return 0
33
- end
34
-
35
- opts.on('--with-context', 'Show where in the manifest the problem is') do
36
- PuppetLint.configuration.with_context = true
37
- end
38
-
39
- opts.on("--with-filename", "Display the filename before the warning") do
40
- PuppetLint.configuration.with_filename = true
41
- end
42
-
43
- opts.on("--fail-on-warnings", "Return a non-zero exit status for warnings.") do
44
- PuppetLint.configuration.fail_on_warnings = true
45
- end
46
-
47
- opts.on("--error-level LEVEL", [:all, :warning, :error], "The level of error to return.", "(warning, error, all)") do |el|
48
- PuppetLint.configuration.error_level = el
49
- end
50
-
51
- opts.on("-l", '--load FILE', 'Load a file containing custom puppet-lint checks.') do |f|
52
- load f
53
- end
54
-
55
- opts.on('-f', '--fix', 'Attempt to automatically fix errors') do
56
- PuppetLint.configuration.fix = true
57
- end
58
-
59
- opts.on("--log-format FORMAT",
60
- "Change the log format.", "Overrides --with-filename.",
61
- "The following placeholders can be used:",
62
- "%{filename} - Filename without path.",
63
- "%{path} - Path as provided.",
64
- "%{fullpath} - Full path.",
65
- "%{linenumber} - Line number.",
66
- "%{kind} - The kind of message.",
67
- " - (warning, error)",
68
- "%{KIND} - Uppercase version of %{kind}",
69
- "%{check} - Name of the check.",
70
- "%{message} - The message."
71
- ) do |format|
72
- PuppetLint.configuration.log_format = format
73
- end
74
-
75
- opts.separator ""
76
- opts.separator " Disable checks:"
77
-
78
- PuppetLint.configuration.checks.each do |check|
79
- opts.on("--no-#{check}-check", "Skip the #{check} check") do
80
- PuppetLint.configuration.send("disable_#{check}")
81
- end
82
- end
83
-
84
- opts.load('/etc/puppet-lint.rc')
85
-
86
- if ENV['HOME']
87
- opts.load(File.expand_path('~/.puppet-lint.rc'))
88
- if opts.load(File.expand_path('~/.puppet-lintrc'))
89
- $stderr.puts 'Depreciated: Found ~/.puppet-lintrc instead of ~/.puppet-lint.rc'
90
- end
91
- end
92
-
93
- opts.load('.puppet-lint.rc')
94
- if opts.load('.puppet-lintrc')
95
- $stderr.puts 'Depreciated: Read .puppet-lintrc instead of .puppet-lint.rc'
96
- end
97
- end
22
+ opts = PuppetLint::OptParser.build
98
23
 
99
24
  begin
100
25
  opts.parse!(@args)
@@ -104,6 +29,11 @@ class PuppetLint::Bin
104
29
  return 1
105
30
  end
106
31
 
32
+ if PuppetLint.configuration.display_version
33
+ puts "puppet-lint #{PuppetLint::VERSION}"
34
+ return 0
35
+ end
36
+
107
37
  if @args[0].nil?
108
38
  puts "puppet-lint: no file specified"
109
39
  puts "puppet-lint: try 'puppet-lint --help' for more information"
@@ -118,18 +48,23 @@ class PuppetLint::Bin
118
48
  path = @args
119
49
  end
120
50
 
51
+ if path.length > 1
52
+ PuppetLint.configuration.with_filename = true
53
+ end
54
+
121
55
  return_val = 0
122
56
  path.each do |f|
123
57
  l = PuppetLint.new
124
58
  l.file = f
125
59
  l.run
60
+ l.print_problems
126
61
  if l.errors? or (l.warnings? and PuppetLint.configuration.fail_on_warnings)
127
62
  return_val = 1
128
63
  end
129
64
 
130
- if PuppetLint.configuration.fix
65
+ if PuppetLint.configuration.fix && !l.problems.any? { |e| e[:check] == :syntax }
131
66
  File.open(f, 'w') do |fd|
132
- fd.puts l.manifest
67
+ fd.write l.manifest
133
68
  end
134
69
  end
135
70
  end