puppet-lint 1.0.1 → 1.1.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.
- 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
|