puppet-lint 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +34 -0
- data/lib/puppet-lint/data.rb +29 -16
- data/lib/puppet-lint/lexer.rb +60 -67
- data/lib/puppet-lint/plugins/check_classes.rb +11 -0
- data/lib/puppet-lint/plugins/check_nodes.rb +16 -11
- data/lib/puppet-lint/plugins/check_whitespace.rb +29 -8
- data/lib/puppet-lint/tasks/puppet-lint.rb +41 -7
- data/lib/puppet-lint/version.rb +1 -1
- data/spec/fixtures/test/manifests/ignore_multiple_block.pp +6 -0
- data/spec/fixtures/test/manifests/ignore_multiple_line.pp +2 -0
- data/spec/puppet-lint/bin_spec.rb +17 -0
- data/spec/puppet-lint/ignore_overrides_spec.rb +12 -0
- data/spec/puppet-lint/lexer_spec.rb +9 -5
- data/spec/puppet-lint/plugins/check_classes/variable_scope_spec.rb +14 -0
- data/spec/puppet-lint/plugins/check_nodes/unquoted_node_name_spec.rb +64 -0
- data/spec/puppet-lint/plugins/check_whitespace/arrow_alignment_spec.rb +107 -0
- metadata +8 -4
data/README.md
CHANGED
@@ -27,6 +27,40 @@ If you want to test your entire Puppet manifest directory, you can add
|
|
27
27
|
|
28
28
|
rake lint
|
29
29
|
|
30
|
+
If you want to modify the default behaviour of the rake task, you can modify
|
31
|
+
the PuppetLint configuration by defining the task yourself.
|
32
|
+
|
33
|
+
PuppetLint::RakeTask.new :lint do |config|
|
34
|
+
# Pattern of files to check, defaults to `**/*.pp`
|
35
|
+
config.pattern = 'modules'
|
36
|
+
|
37
|
+
# Pattern of files to ignore
|
38
|
+
config.ignore_paths = ['modules/apt', 'modules/stdlib']
|
39
|
+
|
40
|
+
# List of checks to disable
|
41
|
+
config.disable_checks = ['documentation', '80chars']
|
42
|
+
|
43
|
+
# Should puppet-lint prefix it's output with the file being checked,
|
44
|
+
# defaults to true
|
45
|
+
config.with_filename = false
|
46
|
+
|
47
|
+
# Should the task fail if there were any warnings, defaults to false
|
48
|
+
config.fail_on_warnings = true
|
49
|
+
|
50
|
+
# Format string for puppet-lint's output (see the puppet-lint help output
|
51
|
+
# for details
|
52
|
+
config.log_format = '%{filename} - %{message}'
|
53
|
+
|
54
|
+
# Print out the context for the problem, defaults to false
|
55
|
+
config.with_context = true
|
56
|
+
|
57
|
+
# Enable automatic fixing of problems, defaults to false
|
58
|
+
config.fix = true
|
59
|
+
|
60
|
+
# Show ignored problems in the output, defaults to false
|
61
|
+
config.show_ignored = true
|
62
|
+
end
|
63
|
+
|
30
64
|
## Implemented tests
|
31
65
|
|
32
66
|
At the moment, the following tests have been implemented:
|
data/lib/puppet-lint/data.rb
CHANGED
@@ -255,6 +255,9 @@ class PuppetLint::Data
|
|
255
255
|
rparen_idx = i
|
256
256
|
break
|
257
257
|
end
|
258
|
+
elsif token.type == :LBRACE && depth == 0
|
259
|
+
# no parameters
|
260
|
+
break
|
258
261
|
end
|
259
262
|
end
|
260
263
|
|
@@ -289,6 +292,7 @@ class PuppetLint::Data
|
|
289
292
|
# Returns nothing.
|
290
293
|
def parse_control_comments
|
291
294
|
@ignore_overrides.each_key { |check| @ignore_overrides[check].clear }
|
295
|
+
control_re = /\A(lint:\S+)(\s+lint:\S+)*(.*)/
|
292
296
|
|
293
297
|
comment_token_types = Set[:COMMENT, :MLCOMMENT, :SLASH_COMMENT]
|
294
298
|
|
@@ -301,28 +305,37 @@ class PuppetLint::Data
|
|
301
305
|
|
302
306
|
stack = []
|
303
307
|
control_comment_tokens.each do |token|
|
304
|
-
|
305
|
-
|
306
|
-
|
308
|
+
comment_data = control_re.match(token.value.strip).to_a[1..-1].compact.map(&:strip)
|
309
|
+
if comment_data.last =~ /\Alint:(ignore|endignore)/
|
310
|
+
comment_data << ''
|
311
|
+
end
|
312
|
+
reason = comment_data.pop
|
313
|
+
stack_add = []
|
314
|
+
comment_data.each do |control|
|
315
|
+
split_control = control.split(':')
|
316
|
+
command = split_control[1]
|
307
317
|
|
308
|
-
|
309
|
-
|
318
|
+
if command == 'ignore'
|
319
|
+
check = split_control[2].to_sym
|
310
320
|
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
321
|
+
if token.prev_token && !Set[:NEWLINE, :INDENT].include?(token.prev_token.type)
|
322
|
+
# control comment at the end of the line, override applies to
|
323
|
+
# a single line only
|
324
|
+
(ignore_overrides[check] ||= {})[token.line] = reason
|
325
|
+
else
|
326
|
+
stack_add << [token.line, reason, check]
|
327
|
+
end
|
315
328
|
else
|
316
|
-
stack
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
(ignore_overrides[start[2]] ||= {})[i] = start[1]
|
329
|
+
stack.pop.each do |start|
|
330
|
+
unless start.nil?
|
331
|
+
(start[0]..token.line).each do |i|
|
332
|
+
(ignore_overrides[start[2]] ||= {})[i] = start[1]
|
333
|
+
end
|
334
|
+
end
|
323
335
|
end
|
324
336
|
end
|
325
337
|
end
|
338
|
+
stack << stack_add unless stack_add.empty?
|
326
339
|
end
|
327
340
|
end
|
328
341
|
end
|
data/lib/puppet-lint/lexer.rb
CHANGED
@@ -15,24 +15,22 @@ class PuppetLint
|
|
15
15
|
|
16
16
|
# Internal: Initialise a new PuppetLint::LexerError object.
|
17
17
|
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
@line_no = chunk.scan(/(\r\n|\r|\n)/).size + 1
|
24
|
-
if @line_no == 1
|
25
|
-
@column = chunk.length
|
26
|
-
else
|
27
|
-
@column = chunk.length - chunk.rindex(/(\r\n|\r|\n)/) - 1
|
28
|
-
end
|
29
|
-
@column = 1 if @column == 0
|
18
|
+
# line_no - The Integer line number of the location of the error.
|
19
|
+
# column - The Integer column number of the location of the error.
|
20
|
+
def initialize(line_no, column)
|
21
|
+
@line_no = line_no
|
22
|
+
@column = column
|
30
23
|
end
|
31
24
|
end
|
32
25
|
|
33
26
|
# Internal: The puppet-lint lexer. Converts your manifest into its tokenised
|
34
27
|
# form.
|
35
28
|
class Lexer
|
29
|
+
def initialize
|
30
|
+
@line_no = 1
|
31
|
+
@column = 1
|
32
|
+
end
|
33
|
+
|
36
34
|
# Internal: A Hash whose keys are Strings representing reserved keywords in
|
37
35
|
# the Puppet DSL.
|
38
36
|
KEYWORDS = {
|
@@ -153,16 +151,17 @@ class PuppetLint
|
|
153
151
|
|
154
152
|
KNOWN_TOKENS.each do |type, regex|
|
155
153
|
if value = chunk[regex, 1]
|
154
|
+
length = value.size
|
156
155
|
if type == :NAME
|
157
156
|
if KEYWORDS.include? value
|
158
|
-
tokens << new_token(value.upcase.to_sym, value,
|
157
|
+
tokens << new_token(value.upcase.to_sym, value, length)
|
159
158
|
else
|
160
|
-
tokens << new_token(type, value,
|
159
|
+
tokens << new_token(type, value, length)
|
161
160
|
end
|
162
161
|
else
|
163
|
-
tokens << new_token(type, value,
|
162
|
+
tokens << new_token(type, value, length)
|
164
163
|
end
|
165
|
-
i +=
|
164
|
+
i += length
|
166
165
|
found = true
|
167
166
|
break
|
168
167
|
end
|
@@ -170,68 +169,67 @@ class PuppetLint
|
|
170
169
|
|
171
170
|
unless found
|
172
171
|
if var_name = chunk[/\A\$((::)?([\w-]+::)*[\w-]+(\[.+?\])*)/, 1]
|
173
|
-
|
174
|
-
|
172
|
+
length = var_name.size + 1
|
173
|
+
tokens << new_token(:VARIABLE, var_name, length)
|
175
174
|
|
176
175
|
elsif chunk.match(/\A'(.*?)'/m)
|
177
176
|
str_content = StringScanner.new(code[i+1..-1]).scan_until(/(\A|[^\\])(\\\\)*'/m)
|
178
|
-
|
179
|
-
|
177
|
+
length = str_content.size + 1
|
178
|
+
tokens << new_token(:SSTRING, str_content[0..-2], length)
|
180
179
|
|
181
180
|
elsif chunk.match(/\A"/)
|
182
181
|
str_contents = StringScanner.new(code[i+1..-1]).scan_until(/(\A|[^\\])(\\\\)*"/m)
|
183
182
|
_ = code[0..i].split("\n")
|
184
183
|
interpolate_string(str_contents, _.count, _.last.length)
|
185
|
-
|
184
|
+
length = str_contents.size + 1
|
186
185
|
|
187
186
|
elsif comment = chunk[/\A(#.*)/, 1]
|
188
|
-
|
187
|
+
length = comment.size
|
189
188
|
comment.sub!(/#/, '')
|
190
|
-
tokens << new_token(:COMMENT, comment,
|
191
|
-
i += comment_size
|
189
|
+
tokens << new_token(:COMMENT, comment, length)
|
192
190
|
|
193
191
|
elsif slash_comment = chunk[/\A(\/\/.*)/, 1]
|
194
|
-
|
192
|
+
length = slash_comment.size
|
195
193
|
slash_comment.sub!(/\/\//, '')
|
196
|
-
tokens << new_token(:SLASH_COMMENT, slash_comment,
|
197
|
-
i += slash_comment_size
|
194
|
+
tokens << new_token(:SLASH_COMMENT, slash_comment, length)
|
198
195
|
|
199
196
|
elsif mlcomment = chunk[/\A(\/\*.*?\*\/)/m, 1]
|
200
|
-
|
197
|
+
length = mlcomment.size
|
201
198
|
mlcomment.sub!(/\A\/\* ?/, '')
|
202
199
|
mlcomment.sub!(/ ?\*\/\Z/, '')
|
203
200
|
mlcomment.gsub!(/ *\* ?/, '')
|
204
201
|
mlcomment.strip!
|
205
|
-
tokens << new_token(:MLCOMMENT, mlcomment,
|
206
|
-
i += mlcomment_size
|
202
|
+
tokens << new_token(:MLCOMMENT, mlcomment, length)
|
207
203
|
|
208
204
|
elsif chunk.match(/\A\/.*?\//) && possible_regex?
|
209
205
|
str_content = StringScanner.new(code[i+1..-1]).scan_until(/(\A|[^\\])(\\\\)*\//m)
|
210
|
-
|
211
|
-
|
206
|
+
length = str_content.size + 1
|
207
|
+
tokens << new_token(:REGEX, str_content[0..-2], length)
|
212
208
|
|
213
209
|
elsif eolindent = chunk[/\A((\r\n|\r|\n)[ \t]+)/m, 1]
|
214
210
|
eol = eolindent[/\A([\r\n]+)/m, 1]
|
215
211
|
indent = eolindent[/\A[\r\n]+([ \t]+)/m, 1]
|
216
|
-
tokens << new_token(:NEWLINE, eol,
|
217
|
-
tokens << new_token(:INDENT, indent,
|
218
|
-
|
212
|
+
tokens << new_token(:NEWLINE, eol, eol.size)
|
213
|
+
tokens << new_token(:INDENT, indent, indent.size)
|
214
|
+
length = indent.size + eol.size
|
219
215
|
|
220
216
|
elsif whitespace = chunk[/\A([ \t]+)/, 1]
|
221
|
-
|
222
|
-
|
217
|
+
length = whitespace.size
|
218
|
+
tokens << new_token(:WHITESPACE, whitespace, length)
|
223
219
|
|
224
220
|
elsif eol = chunk[/\A(\r\n|\r|\n)/, 1]
|
225
|
-
|
226
|
-
|
221
|
+
length = eol.size
|
222
|
+
tokens << new_token(:NEWLINE, eol, length)
|
227
223
|
|
228
224
|
elsif chunk.match(/\A\//)
|
229
|
-
|
230
|
-
|
225
|
+
length = 1
|
226
|
+
tokens << new_token(:DIV, '/', length)
|
231
227
|
|
232
228
|
else
|
233
|
-
raise PuppetLint::LexerError.new(
|
229
|
+
raise PuppetLint::LexerError.new(@line_no, @column)
|
234
230
|
end
|
231
|
+
|
232
|
+
i += length
|
235
233
|
end
|
236
234
|
end
|
237
235
|
|
@@ -259,29 +257,18 @@ class PuppetLint
|
|
259
257
|
# Internal: Create a new PuppetLint::Lexer::Token object, calculate its
|
260
258
|
# line number and column and then add it to the Linked List of tokens.
|
261
259
|
#
|
262
|
-
# type
|
263
|
-
# value
|
264
|
-
#
|
260
|
+
# type - The Symbol token type.
|
261
|
+
# value - The token value.
|
262
|
+
# length - The Integer length of the token's value.
|
263
|
+
# opts - A Hash of additional values required to determine line number and
|
265
264
|
# column:
|
266
|
-
# :chunk - The String chunk of the manifest that has been tokenised so
|
267
|
-
# far.
|
268
265
|
# :line - The Integer line number if calculated externally.
|
269
266
|
# :column - The Integer column number if calculated externally.
|
270
267
|
#
|
271
268
|
# Returns the instantiated PuppetLint::Lexer::Token object.
|
272
|
-
def new_token(type, value, opts = {})
|
273
|
-
|
274
|
-
|
275
|
-
if line_no == 1
|
276
|
-
column = opts[:chunk].length
|
277
|
-
else
|
278
|
-
column = opts[:chunk].length - opts[:chunk].rindex(/(\r\n|\r|\n)/) - 1
|
279
|
-
end
|
280
|
-
column += 1 if column == 0
|
281
|
-
else
|
282
|
-
column = opts[:column]
|
283
|
-
line_no = opts[:line]
|
284
|
-
end
|
269
|
+
def new_token(type, value, length, opts = {})
|
270
|
+
column = opts[:column] || @column
|
271
|
+
line_no = opts[:line] || @line_no
|
285
272
|
|
286
273
|
token = Token.new(type, value, line_no, column)
|
287
274
|
unless tokens.last.nil?
|
@@ -298,6 +285,12 @@ class PuppetLint
|
|
298
285
|
end
|
299
286
|
end
|
300
287
|
|
288
|
+
@column += length
|
289
|
+
if type == :NEWLINE
|
290
|
+
@line_no += 1
|
291
|
+
@column = 1
|
292
|
+
end
|
293
|
+
|
301
294
|
token
|
302
295
|
end
|
303
296
|
|
@@ -333,30 +326,30 @@ class PuppetLint
|
|
333
326
|
until value.nil?
|
334
327
|
if terminator == "\""
|
335
328
|
if first
|
336
|
-
tokens << new_token(:STRING, value, :line => line, :column => column)
|
329
|
+
tokens << new_token(:STRING, value, value.size + 2, :line => line, :column => column)
|
337
330
|
first = false
|
338
331
|
else
|
339
332
|
line += value.scan(/(\r\n|\r|\n)/).size
|
340
333
|
token_column = column + (ss.pos - value.size)
|
341
|
-
tokens << new_token(:DQPOST, value, :line => line, :column => token_column)
|
334
|
+
tokens << new_token(:DQPOST, value, value.size + 1, :line => line, :column => token_column)
|
342
335
|
end
|
343
336
|
else
|
344
337
|
if first
|
345
|
-
tokens << new_token(:DQPRE, value, :line => line, :column => column)
|
338
|
+
tokens << new_token(:DQPRE, value, value.size + 1, :line => line, :column => column)
|
346
339
|
first = false
|
347
340
|
else
|
348
341
|
line += value.scan(/(\r\n|\r|\n)/).size
|
349
342
|
token_column = column + (ss.pos - value.size)
|
350
|
-
tokens << new_token(:DQMID, value, :line => line, :column => token_column)
|
343
|
+
tokens << new_token(:DQMID, value, value.size, :line => line, :column => token_column)
|
351
344
|
end
|
352
345
|
if ss.scan(/\{/).nil?
|
353
346
|
var_name = ss.scan(/(::)?([\w-]+::)*[\w-]+/)
|
354
347
|
if var_name.nil?
|
355
348
|
token_column = column + ss.pos - 1
|
356
|
-
tokens << new_token(:DQMID, "$", :line => line, :column => token_column)
|
349
|
+
tokens << new_token(:DQMID, "$", 1, :line => line, :column => token_column)
|
357
350
|
else
|
358
351
|
token_column = column + (ss.pos - var_name.size)
|
359
|
-
tokens << new_token(:UNENC_VARIABLE, var_name, :line => line, :column => token_column)
|
352
|
+
tokens << new_token(:UNENC_VARIABLE, var_name, var_name.size, :line => line, :column => token_column)
|
360
353
|
end
|
361
354
|
else
|
362
355
|
contents = ss.scan_until(/\}/)[0..-2]
|
@@ -368,7 +361,7 @@ class PuppetLint
|
|
368
361
|
lexer.tokens.each do |token|
|
369
362
|
tok_col = column + token.column + (ss.pos - contents.size - 1)
|
370
363
|
tok_line = token.line + line - 1
|
371
|
-
tokens << new_token(token.type, token.value, :line => tok_line, :column => tok_col)
|
364
|
+
tokens << new_token(token.type, token.value, token.value.size, :line => tok_line, :column => tok_col)
|
372
365
|
end
|
373
366
|
end
|
374
367
|
end
|
@@ -186,6 +186,17 @@ PuppetLint.new_check(:variable_scope) do
|
|
186
186
|
'serverip',
|
187
187
|
'serverversion',
|
188
188
|
'caller_module_name',
|
189
|
+
'alias',
|
190
|
+
'audit',
|
191
|
+
'before',
|
192
|
+
'loglevel',
|
193
|
+
'noop',
|
194
|
+
'notify',
|
195
|
+
'require',
|
196
|
+
'schedule',
|
197
|
+
'stage',
|
198
|
+
'subscribe',
|
199
|
+
'tag',
|
189
200
|
]
|
190
201
|
POST_VAR_TOKENS = Set[:COMMA, :EQUALS, :RPAREN]
|
191
202
|
|
@@ -2,17 +2,22 @@
|
|
2
2
|
# each instance found.
|
3
3
|
PuppetLint.new_check(:unquoted_node_name) do
|
4
4
|
def check
|
5
|
-
tokens.select { |
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
:
|
15
|
-
|
5
|
+
node_tokens = tokens.select { |token| token.type == :NODE }
|
6
|
+
node_tokens.each do |node|
|
7
|
+
node_token_idx = tokens.index(node)
|
8
|
+
node_lbrace_idx = tokens.index(tokens.find { |token| token.type == :LBRACE })
|
9
|
+
|
10
|
+
tokens[node_token_idx..node_lbrace_idx].select { |token|
|
11
|
+
token.type == :NAME
|
12
|
+
}.each do |token|
|
13
|
+
unless token.value == 'default'
|
14
|
+
notify :warning, {
|
15
|
+
:message => 'unquoted node name found',
|
16
|
+
:line => token.line,
|
17
|
+
:column => token.column,
|
18
|
+
:token => token,
|
19
|
+
}
|
20
|
+
end
|
16
21
|
end
|
17
22
|
end
|
18
23
|
end
|
@@ -111,7 +111,8 @@ PuppetLint.new_check(:arrow_alignment) do
|
|
111
111
|
resource_tokens.each_with_index do |token, idx|
|
112
112
|
if token.type == :FARROW
|
113
113
|
(level_tokens[indent_depth_idx] ||= []) << token
|
114
|
-
|
114
|
+
prev_indent_token = resource_tokens[0..idx].rindex { |t| t.type == :INDENT }
|
115
|
+
indent_length = resource_tokens[prev_indent_token].to_manifest.length + token.prev_code_token.to_manifest.length + 2
|
115
116
|
|
116
117
|
if indent_depth[indent_depth_idx] < indent_length
|
117
118
|
indent_depth[indent_depth_idx] = indent_length
|
@@ -124,12 +125,15 @@ PuppetLint.new_check(:arrow_alignment) do
|
|
124
125
|
elsif token.type == :RBRACE
|
125
126
|
level_tokens[indent_depth_idx].each do |arrow_tok|
|
126
127
|
unless arrow_tok.column == indent_depth[indent_depth_idx]
|
128
|
+
arrows_on_line = level_tokens[indent_depth_idx].select { |t| t.line == arrow_tok.line }
|
127
129
|
notify :warning, {
|
128
|
-
:message
|
129
|
-
:line
|
130
|
-
:column
|
131
|
-
:token
|
132
|
-
:indent_depth
|
130
|
+
:message => 'indentation of => is not properly aligned',
|
131
|
+
:line => arrow_tok.line,
|
132
|
+
:column => arrow_tok.column,
|
133
|
+
:token => arrow_tok,
|
134
|
+
:indent_depth => indent_depth[indent_depth_idx],
|
135
|
+
:newline => !(arrows_on_line.index(arrow_tok) == 0),
|
136
|
+
:newline_indent => arrows_on_line.first.prev_code_token.prev_token.value,
|
133
137
|
}
|
134
138
|
end
|
135
139
|
end
|
@@ -142,7 +146,24 @@ PuppetLint.new_check(:arrow_alignment) do
|
|
142
146
|
end
|
143
147
|
|
144
148
|
def fix(problem)
|
145
|
-
|
146
|
-
|
149
|
+
new_ws_len = (problem[:indent_depth] - (problem[:newline_indent].length + problem[:token].prev_code_token.to_manifest.length + 1))
|
150
|
+
new_ws = ' ' * new_ws_len
|
151
|
+
if problem[:newline]
|
152
|
+
index = tokens.index(problem[:token].prev_code_token.prev_token)
|
153
|
+
|
154
|
+
#insert newline
|
155
|
+
tokens.insert(index, PuppetLint::Lexer::Token.new(:NEWLINE, "\n", 0, 0))
|
156
|
+
|
157
|
+
# indent the parameter to the correct depth
|
158
|
+
problem[:token].prev_code_token.prev_token.type = :INDENT
|
159
|
+
problem[:token].prev_code_token.prev_token.value = problem[:newline_indent].dup
|
160
|
+
end
|
161
|
+
|
162
|
+
if problem[:token].prev_token.type == :WHITESPACE
|
163
|
+
problem[:token].prev_token.value = new_ws
|
164
|
+
else
|
165
|
+
index = tokens.index(problem[:token].prev_token)
|
166
|
+
tokens.insert(index + 1, PuppetLint::Lexer::Token.new(:WHITESPACE, new_ws, 0, 0))
|
167
|
+
end
|
147
168
|
end
|
148
169
|
end
|
@@ -11,6 +11,22 @@ class PuppetLint
|
|
11
11
|
# require 'puppet-lint'
|
12
12
|
# PuppetLint::RakeTask.new
|
13
13
|
class RakeTask < ::Rake::TaskLib
|
14
|
+
include ::Rake::DSL if defined?(::Rake::DSL)
|
15
|
+
|
16
|
+
DEFAULT_PATTERN = '**/*.pp'
|
17
|
+
|
18
|
+
attr_accessor :name
|
19
|
+
attr_accessor :pattern
|
20
|
+
attr_accessor :ignore_paths
|
21
|
+
attr_accessor :with_filename
|
22
|
+
attr_accessor :disable_checks
|
23
|
+
attr_accessor :fail_on_warnings
|
24
|
+
attr_accessor :error_level
|
25
|
+
attr_accessor :log_format
|
26
|
+
attr_accessor :with_context
|
27
|
+
attr_accessor :fix
|
28
|
+
attr_accessor :show_ignored
|
29
|
+
|
14
30
|
# Public: Initialise a new PuppetLint::RakeTask.
|
15
31
|
#
|
16
32
|
# args - Not used.
|
@@ -18,20 +34,38 @@ class PuppetLint
|
|
18
34
|
# Example
|
19
35
|
#
|
20
36
|
# PuppetLint::RakeTask.new
|
21
|
-
def initialize(*args)
|
37
|
+
def initialize(*args, &task_block)
|
38
|
+
@name = args.shift || :lint
|
39
|
+
@pattern = DEFAULT_PATTERN
|
40
|
+
@with_filename = true
|
41
|
+
@disable_checks = []
|
42
|
+
@ignore_paths = []
|
43
|
+
|
44
|
+
define(args, &task_block)
|
45
|
+
end
|
46
|
+
|
47
|
+
def define(args, &task_block)
|
22
48
|
desc 'Run puppet-lint'
|
23
49
|
|
24
|
-
|
25
|
-
|
50
|
+
task_block.call(*[self, args].slice(0, task_block.arity)) if task_block
|
51
|
+
|
52
|
+
task @name do
|
26
53
|
PuppetLint::OptParser.build
|
27
54
|
|
55
|
+
Array(@disable_checks).each do |check|
|
56
|
+
PuppetLint.configuration.send("disable_#{check}")
|
57
|
+
end
|
58
|
+
|
59
|
+
%w{with_filename fail_on_warnings error_level log_format with_context fix show_ignored}.each do |config|
|
60
|
+
value = instance_variable_get("@#{config}")
|
61
|
+
PuppetLint.configuration.send("#{config}=".to_sym, value) unless value.nil?
|
62
|
+
end
|
63
|
+
|
28
64
|
RakeFileUtils.send(:verbose, true) do
|
29
65
|
linter = PuppetLint.new
|
30
|
-
matched_files = FileList[
|
66
|
+
matched_files = FileList[@pattern]
|
31
67
|
|
32
|
-
|
33
|
-
matched_files = matched_files.exclude(*ignore_paths)
|
34
|
-
end
|
68
|
+
matched_files = matched_files.exclude(*@ignore_paths)
|
35
69
|
|
36
70
|
matched_files.to_a.each do |puppet_file|
|
37
71
|
linter.file = puppet_file
|
data/lib/puppet-lint/version.rb
CHANGED
@@ -306,4 +306,21 @@ describe PuppetLint::Bin do
|
|
306
306
|
" for a good reason",
|
307
307
|
].join("\n")) }
|
308
308
|
end
|
309
|
+
|
310
|
+
context 'ignoring multiple checks on a line' do
|
311
|
+
let(:args) { [
|
312
|
+
'spec/fixtures/test/manifests/ignore_multiple_line.pp',
|
313
|
+
] }
|
314
|
+
|
315
|
+
its(:exitstatus) { is_expected.to eq(0) }
|
316
|
+
end
|
317
|
+
|
318
|
+
context 'ignoring multiple checks in a block' do
|
319
|
+
let(:args) { [
|
320
|
+
'spec/fixtures/test/manifests/ignore_multiple_block.pp',
|
321
|
+
] }
|
322
|
+
|
323
|
+
its(:exitstatus) { is_expected.to eq(0) }
|
324
|
+
its(:stdout) { is_expected.to match(/^.*line 6$/) }
|
325
|
+
end
|
309
326
|
end
|
@@ -94,4 +94,16 @@ describe 'quoted_booleans', :type => :lint do
|
|
94
94
|
expect(problems).to contain_ignored(msg).on_line(5).in_column(7).with_reason('another reason')
|
95
95
|
end
|
96
96
|
end
|
97
|
+
|
98
|
+
context 'disable multiple checks on a line with a reason' do
|
99
|
+
let(:code) { '"true" # lint:ignore:quoted_booleans lint:ignore:double_quoted_string a reason' }
|
100
|
+
|
101
|
+
it 'should detect 1 problems' do
|
102
|
+
expect(problems).to have(1).problems
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'should have one ignored problems' do
|
106
|
+
expect(problems).to contain_ignored(msg).on_line(1).in_column(1).with_reason('a reason')
|
107
|
+
end
|
108
|
+
end
|
97
109
|
end
|
@@ -13,27 +13,31 @@ describe PuppetLint::Lexer do
|
|
13
13
|
|
14
14
|
context '#new_token' do
|
15
15
|
it 'should calculate the line number for an empty string' do
|
16
|
-
token = @lexer.new_token(:TEST, 'test',
|
16
|
+
token = @lexer.new_token(:TEST, 'test', 4)
|
17
17
|
expect(token.line).to eq(1)
|
18
18
|
end
|
19
19
|
|
20
20
|
it 'should calculate the line number for a multi line string' do
|
21
|
-
|
21
|
+
@lexer.instance_variable_set('@line_no', 2)
|
22
|
+
token = @lexer.new_token(:TEST, 'test', 4)
|
22
23
|
expect(token.line).to eq(2)
|
23
24
|
end
|
24
25
|
|
25
26
|
it 'should calculate the column number for an empty string' do
|
26
|
-
token = @lexer.new_token(:TEST, 'test',
|
27
|
+
token = @lexer.new_token(:TEST, 'test', 4)
|
27
28
|
expect(token.column).to eq(1)
|
28
29
|
end
|
29
30
|
|
30
31
|
it 'should calculate the column number for a single line string' do
|
31
|
-
|
32
|
+
@lexer.instance_variable_set('@column', 'this is a test'.size)
|
33
|
+
token = @lexer.new_token(:TEST, 'test', 4)
|
32
34
|
expect(token.column).to eq(14)
|
33
35
|
end
|
34
36
|
|
35
37
|
it 'should calculate the column number for a multi line string' do
|
36
|
-
|
38
|
+
@lexer.instance_variable_set('@line_no', 4)
|
39
|
+
@lexer.instance_variable_set('@column', "gronk".size)
|
40
|
+
token = @lexer.new_token(:TEST, 'test', 4)
|
37
41
|
expect(token.column).to eq(5)
|
38
42
|
end
|
39
43
|
end
|
@@ -165,4 +165,18 @@ describe 'variable_scope' do
|
|
165
165
|
expect(problems).to contain_warning(msg).on_line(6).in_column(11)
|
166
166
|
end
|
167
167
|
end
|
168
|
+
|
169
|
+
%w{alias audit before loglevel noop notify require schedule stage subscribe tag}.each do |metaparam|
|
170
|
+
context "referencing #{metaparam} metaparam value as a variable" do
|
171
|
+
let(:code) { "
|
172
|
+
class foo() {
|
173
|
+
$#{metaparam}
|
174
|
+
}
|
175
|
+
" }
|
176
|
+
|
177
|
+
it 'should not detect any problems' do
|
178
|
+
expect(problems).to have(0).problems
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
168
182
|
end
|
@@ -39,6 +39,33 @@ describe 'unquoted_node_name' do
|
|
39
39
|
expect(problems).to have(0).problems
|
40
40
|
end
|
41
41
|
end
|
42
|
+
|
43
|
+
context 'multiple bare node names' do
|
44
|
+
let(:code) { "node foo, bar, baz { }" }
|
45
|
+
|
46
|
+
it 'should detect 3 problems' do
|
47
|
+
expect(problems).to have(3).problems
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should create 3 warnings' do
|
51
|
+
expect(problems).to contain_warning(msg).on_line(1).in_column(6)
|
52
|
+
expect(problems).to contain_warning(msg).on_line(1).in_column(11)
|
53
|
+
expect(problems).to contain_warning(msg).on_line(1).in_column(16)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'mixed node name types' do
|
58
|
+
let(:code) { "node foo, 'bar', baz { }" }
|
59
|
+
|
60
|
+
it 'should detect 2 problems' do
|
61
|
+
expect(problems).to have(2).problems
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'should create 2 warnings' do
|
65
|
+
expect(problems).to contain_warning(msg).on_line(1).in_column(6)
|
66
|
+
expect(problems).to contain_warning(msg).on_line(1).in_column(18)
|
67
|
+
end
|
68
|
+
end
|
42
69
|
end
|
43
70
|
|
44
71
|
context 'with fix enabled' do
|
@@ -65,5 +92,42 @@ describe 'unquoted_node_name' do
|
|
65
92
|
expect(manifest).to eq("node 'foo' { }")
|
66
93
|
end
|
67
94
|
end
|
95
|
+
|
96
|
+
context 'multiple bare node names' do
|
97
|
+
let(:code) { "node foo, bar, baz { }" }
|
98
|
+
let(:fixed) { "node 'foo', 'bar', 'baz' { }" }
|
99
|
+
|
100
|
+
it 'should detect 3 problems' do
|
101
|
+
expect(problems).to have(3).problems
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'should fix the 3 problems' do
|
105
|
+
expect(problems).to contain_fixed(msg).on_line(1).in_column(6)
|
106
|
+
expect(problems).to contain_fixed(msg).on_line(1).in_column(11)
|
107
|
+
expect(problems).to contain_fixed(msg).on_line(1).in_column(16)
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'should quote all three node names' do
|
111
|
+
expect(manifest).to eq(fixed)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context 'mixed node name types' do
|
116
|
+
let(:code) { "node foo, 'bar', baz { }" }
|
117
|
+
let(:fixed) { "node 'foo', 'bar', 'baz' { }" }
|
118
|
+
|
119
|
+
it 'should detect 2 problems' do
|
120
|
+
expect(problems).to have(2).problems
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'should fix the 2 problems' do
|
124
|
+
expect(problems).to contain_fixed(msg).on_line(1).in_column(6)
|
125
|
+
expect(problems).to contain_fixed(msg).on_line(1).in_column(18)
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'should quote the 2 unquoted node names' do
|
129
|
+
expect(manifest).to eq(fixed)
|
130
|
+
end
|
131
|
+
end
|
68
132
|
end
|
69
133
|
end
|
@@ -250,6 +250,24 @@ describe 'arrow_alignment' do
|
|
250
250
|
expect(problems).to have(0).problems
|
251
251
|
end
|
252
252
|
end
|
253
|
+
|
254
|
+
context 'multiline resource with multiple params on a line' do
|
255
|
+
let(:code) { "
|
256
|
+
user { 'test':
|
257
|
+
a => 'foo', bb => 'bar',
|
258
|
+
ccc => 'baz',
|
259
|
+
}
|
260
|
+
" }
|
261
|
+
|
262
|
+
it 'should detect 2 problems' do
|
263
|
+
expect(problems).to have(2).problems
|
264
|
+
end
|
265
|
+
|
266
|
+
it 'should create 2 warnings' do
|
267
|
+
expect(problems).to contain_warning(msg).on_line(3).in_column(13)
|
268
|
+
expect(problems).to contain_warning(msg).on_line(3).in_column(26)
|
269
|
+
end
|
270
|
+
end
|
253
271
|
end
|
254
272
|
|
255
273
|
context 'with fix enabled' do
|
@@ -399,5 +417,94 @@ describe 'arrow_alignment' do
|
|
399
417
|
expect(manifest).to eq(fixed)
|
400
418
|
end
|
401
419
|
end
|
420
|
+
|
421
|
+
context 'resource with unaligned => and no whitespace between param and =>' do
|
422
|
+
let(:code) { "
|
423
|
+
user { 'test':
|
424
|
+
param1 => 'foo',
|
425
|
+
param2=> 'bar',
|
426
|
+
}
|
427
|
+
" }
|
428
|
+
|
429
|
+
let(:fixed) { "
|
430
|
+
user { 'test':
|
431
|
+
param1 => 'foo',
|
432
|
+
param2 => 'bar',
|
433
|
+
}
|
434
|
+
" }
|
435
|
+
|
436
|
+
it 'should detect 1 problem' do
|
437
|
+
expect(problems).to have(1).problem
|
438
|
+
end
|
439
|
+
|
440
|
+
it 'should fix the problem' do
|
441
|
+
expect(problems).to contain_fixed(msg).on_line(4).in_column(17)
|
442
|
+
end
|
443
|
+
|
444
|
+
it 'should add whitespace between the param and the arrow' do
|
445
|
+
expect(manifest).to eq(fixed)
|
446
|
+
end
|
447
|
+
end
|
448
|
+
|
449
|
+
context 'multiline resource with multiple params on a line' do
|
450
|
+
let(:code) { "
|
451
|
+
user { 'test':
|
452
|
+
a => 'foo', bb => 'bar',
|
453
|
+
ccc => 'baz',
|
454
|
+
}
|
455
|
+
" }
|
456
|
+
|
457
|
+
let(:fixed) { "
|
458
|
+
user { 'test':
|
459
|
+
a => 'foo',
|
460
|
+
bb => 'bar',
|
461
|
+
ccc => 'baz',
|
462
|
+
}
|
463
|
+
" }
|
464
|
+
|
465
|
+
it 'should detect 2 problems' do
|
466
|
+
expect(problems).to have(2).problems
|
467
|
+
end
|
468
|
+
|
469
|
+
it 'should fix 2 problems' do
|
470
|
+
expect(problems).to contain_fixed(msg).on_line(3).in_column(13)
|
471
|
+
expect(problems).to contain_fixed(msg).on_line(3).in_column(26)
|
472
|
+
end
|
473
|
+
|
474
|
+
it 'should move the extra param onto its own line and realign' do
|
475
|
+
expect(manifest).to eq(fixed)
|
476
|
+
end
|
477
|
+
end
|
478
|
+
|
479
|
+
context 'multiline resource with multiple params on a line, extra one longer' do
|
480
|
+
let(:code) { "
|
481
|
+
user { 'test':
|
482
|
+
a => 'foo', bbccc => 'bar',
|
483
|
+
ccc => 'baz',
|
484
|
+
}
|
485
|
+
" }
|
486
|
+
|
487
|
+
let(:fixed) { "
|
488
|
+
user { 'test':
|
489
|
+
a => 'foo',
|
490
|
+
bbccc => 'bar',
|
491
|
+
ccc => 'baz',
|
492
|
+
}
|
493
|
+
" }
|
494
|
+
|
495
|
+
it 'should detect 2 problems' do
|
496
|
+
expect(problems).to have(3).problems
|
497
|
+
end
|
498
|
+
|
499
|
+
it 'should fix 2 problems' do
|
500
|
+
expect(problems).to contain_fixed(msg).on_line(3).in_column(13)
|
501
|
+
expect(problems).to contain_fixed(msg).on_line(3).in_column(29)
|
502
|
+
expect(problems).to contain_fixed(msg).on_line(4).in_column(15)
|
503
|
+
end
|
504
|
+
|
505
|
+
it 'should move the extra param onto its own line and realign' do
|
506
|
+
expect(manifest).to eq(fixed)
|
507
|
+
end
|
508
|
+
end
|
402
509
|
end
|
403
510
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: puppet-lint
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 19
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
-
- 0
|
9
8
|
- 1
|
10
|
-
|
9
|
+
- 0
|
10
|
+
version: 1.1.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Tim Sharpe
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2014-
|
18
|
+
date: 2014-09-23 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -123,6 +123,8 @@ files:
|
|
123
123
|
- puppet-lint.gemspec
|
124
124
|
- spec/fixtures/test/manifests/fail.pp
|
125
125
|
- spec/fixtures/test/manifests/ignore.pp
|
126
|
+
- spec/fixtures/test/manifests/ignore_multiple_block.pp
|
127
|
+
- spec/fixtures/test/manifests/ignore_multiple_line.pp
|
126
128
|
- spec/fixtures/test/manifests/ignore_reason.pp
|
127
129
|
- spec/fixtures/test/manifests/init.pp
|
128
130
|
- spec/fixtures/test/manifests/malformed.pp
|
@@ -203,6 +205,8 @@ summary: Ensure your Puppet manifests conform with the Puppetlabs style guide
|
|
203
205
|
test_files:
|
204
206
|
- spec/fixtures/test/manifests/fail.pp
|
205
207
|
- spec/fixtures/test/manifests/ignore.pp
|
208
|
+
- spec/fixtures/test/manifests/ignore_multiple_block.pp
|
209
|
+
- spec/fixtures/test/manifests/ignore_multiple_line.pp
|
206
210
|
- spec/fixtures/test/manifests/ignore_reason.pp
|
207
211
|
- spec/fixtures/test/manifests/init.pp
|
208
212
|
- spec/fixtures/test/manifests/malformed.pp
|