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
@@ -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