puppet-lint 0.4.0.pre1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
@@ -1,22 +1,168 @@
1
+ # Public: A class that contains and provides information for the puppet-lint
2
+ # checks.
3
+ #
4
+ # This class should not be used directly, but instead should be inherited.
5
+ #
6
+ # Examples
7
+ #
8
+ # class PuppetLint::Plugin::CheckFoo < PuppetLint::CheckPlugin
9
+ # end
1
10
  class PuppetLint::CheckPlugin
2
- # Public: Define a new lint check.
11
+ # Internal: Initialise a new PuppetLint::CheckPlugin.
12
+ def initialize
13
+ @problems = []
14
+ end
15
+
16
+ # Internal: Check the manifest for problems and filter out any problems that
17
+ # should be ignored.
18
+ #
19
+ # Returns an Array of problem Hashes.
20
+ def run
21
+ check
22
+
23
+ @problems.each do |problem|
24
+ if PuppetLint::Data.ignore_overrides[problem[:check]].has_key?(problem[:line])
25
+ problem[:kind] = :ignored
26
+ problem[:reason] = PuppetLint::Data.ignore_overrides[problem[:check]][problem[:line]]
27
+ next
28
+ end
29
+ end
30
+
31
+ @problems
32
+ end
33
+
34
+ # Internal: Fix any problems the check plugin has detected.
3
35
  #
4
- # name - The String name of the check.
5
- # b - The Block implementation of the check.
36
+ # Returns an Array of problem Hashes.
37
+ def fix_problems
38
+ @problems.each do |problem|
39
+ if self.respond_to?(:fix)
40
+ begin
41
+ fix(problem)
42
+ rescue PuppetLint::NoFix
43
+ # noop
44
+ else
45
+ problem[:kind] = :fixed
46
+ end
47
+ end
48
+ end
49
+
50
+ @problems
51
+ end
52
+
53
+ private
54
+
55
+ # Public: Provides the tokenised manifest to the check plugins.
6
56
  #
7
- # Returns nothing.
8
- def self.check(name, &b)
9
- PuppetLint.configuration.add_check(name, &b)
57
+ # Returns an Array of PuppetLint::Lexer::Token objects.
58
+ def tokens
59
+ PuppetLint::Data.tokens
60
+ end
61
+
62
+ # Public: Provides the resource titles to the check plugins.
63
+ #
64
+ # Returns an Array of PuppetLint::Lexer::Token objects.
65
+ def title_tokens
66
+ PuppetLint::Data.title_tokens
67
+ end
68
+
69
+ # Public: Provides positional information for any resource declarations in
70
+ # the tokens array to the check plugins.
71
+ #
72
+ # Returns an Array of Hashes containing the position information.
73
+ def resource_indexes
74
+ PuppetLint::Data.resource_indexes
75
+ end
76
+
77
+ # Public: Provides positional information for any class definitions in the
78
+ # tokens array to the check plugins.
79
+ #
80
+ # Returns an Array of Hashes containing the position information.
81
+ def class_indexes
82
+ PuppetLint::Data.class_indexes
83
+ end
84
+
85
+ # Public: Provides positional information for any defined type definitions in
86
+ # the tokens array to the check plugins.
87
+ #
88
+ # Returns an Array of Hashes containing the position information.
89
+ def defined_type_indexes
90
+ PuppetLint::Data.defined_type_indexes
91
+ end
92
+
93
+ # Public: Provides the expanded path of the file being analysed to check
94
+ # plugins.
95
+ #
96
+ # Returns the String path.
97
+ def fullpath
98
+ PuppetLint::Data.fullpath
99
+ end
100
+
101
+ # Public: Provides the path of the file being analysed as it was provided to
102
+ # puppet-lint to the check plugins.
103
+ #
104
+ # Returns the String path.
105
+ def path
106
+ PuppetLint::Data.path
107
+ end
108
+
109
+ # Public: Provides the name of the file being analysed to the check plugins.
110
+ #
111
+ # Returns the String file name.
112
+ def filename
113
+ PuppetLint::Data.filename
10
114
  end
11
115
 
12
- # Public: Define a new check helper method.
116
+ # Public: Provides a list of formatting tokens to the check plugins.
13
117
  #
14
- # name - The String name of the helper.
15
- # b - The Block implementation of the helper.
118
+ # Returns an Array of Symbol token types.
119
+ def formatting_tokens
120
+ PuppetLint::Data.formatting_tokens
121
+ end
122
+
123
+ # Public: Provides a list of manifest lines to the check plugins.
124
+ #
125
+ # Returns an Array of manifest lines.
126
+ def manifest_lines
127
+ PuppetLint::Data.manifest_lines
128
+ end
129
+
130
+ # Internal: Prepare default problem report information.
131
+ #
132
+ # Returns a Hash of default problem information.
133
+ def default_info
134
+ @default_info ||= {
135
+ :check => self.class.const_get('NAME'),
136
+ :fullpath => fullpath,
137
+ :path => path,
138
+ :filename => filename,
139
+ }
140
+ end
141
+
142
+ # Public: Report a problem with the manifest being checked.
143
+ #
144
+ # kind - The Symbol problem type (:warning or :error).
145
+ # problem - A Hash containing the attributes of the problem
146
+ # :message - The String message describing the problem.
147
+ # :line - The Integer line number of the location of the problem.
148
+ # :column - The Integer column number of the location of the problem.
149
+ # :check - The Symbol name of the check that detected the problem.
16
150
  #
17
151
  # Returns nothing.
18
- def self.helper(name, &b)
19
- PuppetLint.configuration.add_helper(name, &b)
152
+ def notify(kind, problem)
153
+ problem[:kind] = kind
154
+ problem.merge!(default_info) { |key, v1, v2| v1 }
155
+
156
+ unless [:warning, :error, :fixed].include? kind
157
+ raise ArgumentError, "unknown value passed for kind"
158
+ end
159
+
160
+ [:message, :line, :column, :check].each do |attr|
161
+ unless problem.has_key? attr
162
+ raise ArgumentError, "problem hash must contain #{attr.inspect}"
163
+ end
164
+ end
165
+
166
+ @problems << problem
20
167
  end
21
168
  end
22
-
@@ -1,69 +1,42 @@
1
1
  require 'puppet-lint/checkplugin'
2
2
 
3
+ # Internal: Various methods that orchestrate the actions of the puppet-lint
4
+ # check plugins.
3
5
  class PuppetLint::Checks
4
6
  # Public: Get an Array of problem Hashes.
5
- attr_reader :problems
7
+ attr_accessor :problems
6
8
 
7
- # Public: Get an Array of PuppetLint::Lexer::Token objects.
8
- attr_reader :tokens
9
-
10
- # Public: Initialise a new PuppetLint::Checks object and prepare the check
11
- # methods.
9
+ # Public: Initialise a new PuppetLint::Checks object.
12
10
  def initialize
13
11
  @problems = []
14
- @default_info = {:check => 'unknown', :linenumber => 0, :column => 0}
15
-
16
- PuppetLint.configuration.checks.each do |check|
17
- method = PuppetLint.configuration.check_method[check]
18
- self.class.send(:define_method, "lint_check_#{check}", &method)
19
- end
20
-
21
- PuppetLint.configuration.helpers.each do |helper|
22
- method = PuppetLint.configuration.helper_method[helper]
23
- self.class.send(:define_method, helper, &method)
24
- end
25
- end
26
-
27
- # Public: Add a message to the problems array.
28
- #
29
- # kind - The kind of problem as a Symbol (:warning, :error).
30
- # problem - A Hash containing the attributes of the problem.
31
- # :message - The String message describing the problem.
32
- # :linenumber - The Integer line number of the location of the problem.
33
- # :check - The String name of the check that the problem came from.
34
- # :column - The Integer column number of the location of the problem.
35
- #
36
- # Returns nothing.
37
- def notify(kind, problem)
38
- problem[:kind] = kind
39
- problem.merge!(@default_info) {|key, v1, v2| v1 }
40
- @problems << problem
41
12
  end
42
13
 
43
14
  # Internal: Tokenise the manifest code and prepare it for checking.
44
15
  #
45
- # fileinfo - A Hash containing the following:
46
- # :fullpath - The expanded path to the file as a String.
47
- # :filename - The name of the file as a String.
48
- # :path - The original path to the file as passed to puppet-lint as
49
- # a String.
50
- # data - The String manifest code to be checked.
16
+ # path - The path to the file as passed to puppet-lint as a String.
17
+ # content - The String manifest code to be checked.
51
18
  #
52
19
  # Returns nothing.
53
- def load_data(fileinfo, data)
20
+ def load_data(path, content)
54
21
  lexer = PuppetLint::Lexer.new
22
+ PuppetLint::Data.path = path
23
+ PuppetLint::Data.manifest_lines = content.split("\n")
55
24
  begin
56
- @tokens = lexer.tokenise(data)
25
+ PuppetLint::Data.tokens = lexer.tokenise(content)
26
+ PuppetLint::Data.parse_control_comments
57
27
  rescue PuppetLint::LexerError => e
58
- notify :error, {
59
- :message => 'Syntax error (try running `puppet parser validate <file>`)',
60
- :linenumber => e.line_no,
61
- :column => e.column,
28
+ problems << {
29
+ :kind => :error,
30
+ :check => :syntax,
31
+ :message => 'Syntax error (try running `puppet parser validate <file>`)',
32
+ :line => e.line_no,
33
+ :column => e.column,
34
+ :fullpath => PuppetLint::Data.fullpath,
35
+ :path => PuppetLint::Data.path,
36
+ :filename => PuppetLint::Data.filename,
62
37
  }
63
- @tokens = []
38
+ PuppetLint::Data.tokens = []
64
39
  end
65
- @fileinfo = fileinfo
66
- @data = data
67
40
  end
68
41
 
69
42
  # Internal: Run the lint checks over the manifest code.
@@ -79,9 +52,20 @@ class PuppetLint::Checks
79
52
  def run(fileinfo, data)
80
53
  load_data(fileinfo, data)
81
54
 
55
+ checks_run = []
82
56
  enabled_checks.each do |check|
83
- @default_info[:check] = check
84
- self.send("lint_check_#{check}")
57
+ klass = PuppetLint.configuration.check_object[check].new
58
+ problems = klass.run
59
+
60
+ if PuppetLint.configuration.fix
61
+ checks_run << klass
62
+ else
63
+ @problems.concat(problems)
64
+ end
65
+ end
66
+
67
+ checks_run.each do |check|
68
+ @problems.concat(check.fix_problems)
85
69
  end
86
70
 
87
71
  @problems
@@ -92,183 +76,16 @@ class PuppetLint::Checks
92
76
  # Returns an Array of String check names.
93
77
  def enabled_checks
94
78
  @enabled_checks ||= Proc.new do
95
- self.public_methods.select { |method|
96
- method.to_s.start_with? 'lint_check_'
97
- }.map { |method|
98
- method.to_s[11..-1]
99
- }.select { |name|
100
- PuppetLint.configuration.send("#{name}_enabled?")
79
+ PuppetLint.configuration.checks.select { |check|
80
+ PuppetLint.configuration.send("#{check}_enabled?")
101
81
  }
102
82
  end.call
103
83
  end
104
84
 
105
- # Public: Get the full expanded path to the file being checked.
106
- #
107
- # Returns a String path.
108
- def fullpath
109
- @fileinfo[:fullpath]
110
- end
111
-
112
- # Public: Retrieve a list of tokens that represent resource titles.
113
- #
114
- # Returns an Array of PuppetLint::Lexer::Token objects.
115
- def title_tokens
116
- @title_tokens ||= Proc.new do
117
- result = []
118
- tokens.each_index do |token_idx|
119
- if tokens[token_idx].type == :COLON
120
- # gather a list of tokens that are resource titles
121
- if tokens[token_idx-1].type == :RBRACK
122
- array_start_idx = tokens.rindex { |r|
123
- r.type == :LBRACK
124
- }
125
- title_array_tokens = tokens[(array_start_idx + 1)..(token_idx - 2)]
126
- result += title_array_tokens.select { |token|
127
- {:STRING => true, :NAME => true}.include? token.type
128
- }
129
- else
130
- next_token = tokens[token_idx].next_code_token
131
- if next_token.type != :LBRACE
132
- result << tokens[token_idx - 1]
133
- end
134
- end
135
- end
136
- end
137
- result
138
- end.call
139
- end
140
-
141
- # Public: Calculate the positions of all resource declarations within the
142
- # tokenised manifest. These positions only point to the content of the
143
- # resource declaration, they do not include resource types or
144
- # titles/namevars.
145
- #
146
- # Returns an Array of Hashes, each containing:
147
- # :start - An Integer position in the `tokens` Array pointing to the first
148
- # Token of a resource declaration parameters (type :NAME).
149
- # :end - An Integer position in the `tokens` Array pointing to the last
150
- # Token of a resource declaration parameters (type :RBRACE).
151
- def resource_indexes
152
- @resource_indexes ||= Proc.new do
153
- result = []
154
- tokens.each_index do |token_idx|
155
- if tokens[token_idx].type == :COLON
156
- next_token = tokens[token_idx].next_code_token
157
- depth = 1
158
- if next_token.type != :LBRACE
159
- tokens[(token_idx + 1)..-1].each_index do |idx|
160
- real_idx = token_idx + idx + 1
161
- if tokens[real_idx].type == :LBRACE
162
- depth += 1
163
- elsif {:SEMIC => true, :RBRACE => true}.include? tokens[real_idx].type
164
- unless tokens[real_idx].type == :SEMIC && depth > 1
165
- depth -= 1
166
- if depth == 0
167
- result << {:start => token_idx + 1, :end => real_idx}
168
- break
169
- end
170
- end
171
- end
172
- end
173
- end
174
- end
175
- end
176
- result
177
- end.call
178
- end
179
-
180
- # Public: Calculate the positions of all class definitions within the
181
- # tokenised manifest.
182
- #
183
- # Returns an Array of Hashes, each containing:
184
- # :start - An Integer position in the `tokens` Array pointing to the first
185
- # token of a class (type :CLASS).
186
- # :end - An Integer position in the `tokens` Array pointing to the last
187
- # token of a class (type :RBRACE).
188
- def class_indexes
189
- @class_indexes ||= Proc.new do
190
- result = []
191
- tokens.each_index do |token_idx|
192
- if tokens[token_idx].type == :CLASS
193
- depth = 0
194
- in_params = false
195
- tokens[token_idx+1..-1].each_index do |class_token_idx|
196
- idx = class_token_idx + token_idx + 1
197
- if tokens[idx].type == :LPAREN
198
- in_params = true
199
- elsif tokens[idx].type == :RPAREN
200
- in_params = false
201
- elsif tokens[idx].type == :LBRACE
202
- depth += 1 unless in_params
203
- elsif tokens[idx].type == :RBRACE
204
- depth -= 1 unless in_params
205
- if depth == 0 && ! in_params
206
- if tokens[token_idx].next_code_token.type != :LBRACE
207
- result << {:start => token_idx, :end => idx}
208
- end
209
- break
210
- end
211
- end
212
- end
213
- end
214
- end
215
- result
216
- end.call
217
- end
218
-
219
- # Public: Calculate the positions of all defined type definitions within
220
- # the tokenised manifest.
221
- #
222
- # Returns an Array of Hashes, each containing:
223
- # :start - An Integer position in the `tokens` Array pointing to the first
224
- # token of a defined type (type :DEFINE).
225
- # :end - An Integer position in the `tokens` Array pointing to the last
226
- # token of a defined type (type :RBRACE).
227
- def defined_type_indexes
228
- @defined_type_indexes ||= Proc.new do
229
- result = []
230
- tokens.each_index do |token_idx|
231
- if tokens[token_idx].type == :DEFINE
232
- depth = 0
233
- in_params = false
234
- tokens[token_idx+1..-1].each_index do |define_token_idx|
235
- idx = define_token_idx + token_idx + 1
236
- if tokens[idx].type == :LPAREN
237
- in_params = true
238
- elsif tokens[idx].type == :RPAREN
239
- in_params = false
240
- elsif tokens[idx].type == :LBRACE
241
- depth += 1 unless in_params
242
- elsif tokens[idx].type == :RBRACE
243
- depth -= 1 unless in_params
244
- if depth == 0 && ! in_params
245
- result << {:start => token_idx, :end => idx}
246
- break
247
- end
248
- end
249
- end
250
- end
251
- end
252
- result
253
- end.call
254
- end
255
-
256
- # Public: Retrieves a list of token types that are considered to be
257
- # formatting tokens (ie whitespace, newlines, etc).
258
- #
259
- # Returns an Array of Symbols.
260
- def formatting_tokens
261
- @formatting_tokens ||= PuppetLint::Lexer::FORMATTING_TOKENS
262
- end
263
-
264
- # Public: Access the lines of the manifest that is being checked.
85
+ # Internal: Render the fixed manifest.
265
86
  #
266
- # Returns an Array of Strings.
267
- def manifest_lines
268
- @manifest_lines ||= @data.split("\n")
269
- end
270
-
87
+ # Returns the manifest as a String.
271
88
  def manifest
272
- tokens.map { |t| t.to_manifest }.join('')
89
+ PuppetLint::Data.tokens.map { |t| t.to_manifest }.join('')
273
90
  end
274
91
  end