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 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:
@@ -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
- control, reason = token.value.strip.split(' ', 2)
305
- split_control = control.split(':')
306
- command = split_control[1]
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
- if command == 'ignore'
309
- check = split_control[2].to_sym
318
+ if command == 'ignore'
319
+ check = split_control[2].to_sym
310
320
 
311
- if token.prev_token && !Set[:NEWLINE, :INDENT].include?(token.prev_token.type)
312
- # control comment at the end of the line, override applies to
313
- # a single line only
314
- (ignore_overrides[check] ||= {})[token.line] = reason
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 << [token.line, reason, check]
317
- end
318
- else
319
- start = stack.pop
320
- unless start.nil?
321
- (start[0]..token.line).each do |i|
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
@@ -15,24 +15,22 @@ class PuppetLint
15
15
 
16
16
  # Internal: Initialise a new PuppetLint::LexerError object.
17
17
  #
18
- # code - The String manifest code being tokenised.
19
- # offset - The Integer position in the code string that the tokeniser was
20
- # at when it encountered the error.
21
- def initialize(code, offset)
22
- chunk = code[0..offset]
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, :chunk => code[0..i])
157
+ tokens << new_token(value.upcase.to_sym, value, length)
159
158
  else
160
- tokens << new_token(type, value, :chunk => code[0..i])
159
+ tokens << new_token(type, value, length)
161
160
  end
162
161
  else
163
- tokens << new_token(type, value, :chunk => code[0..i])
162
+ tokens << new_token(type, value, length)
164
163
  end
165
- i += value.size
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
- tokens << new_token(:VARIABLE, var_name, :chunk => code[0..i])
174
- i += var_name.size + 1
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
- tokens << new_token(:SSTRING, str_content[0..-2], :chunk => code[0..i])
179
- i += str_content.size + 1
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
- i += str_contents.size + 1
184
+ length = str_contents.size + 1
186
185
 
187
186
  elsif comment = chunk[/\A(#.*)/, 1]
188
- comment_size = comment.size
187
+ length = comment.size
189
188
  comment.sub!(/#/, '')
190
- tokens << new_token(:COMMENT, comment, :chunk => code[0..i])
191
- i += comment_size
189
+ tokens << new_token(:COMMENT, comment, length)
192
190
 
193
191
  elsif slash_comment = chunk[/\A(\/\/.*)/, 1]
194
- slash_comment_size = slash_comment.size
192
+ length = slash_comment.size
195
193
  slash_comment.sub!(/\/\//, '')
196
- tokens << new_token(:SLASH_COMMENT, slash_comment, :chunk => code[0..i])
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
- mlcomment_size = mlcomment.size
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, :chunk => code[0..i])
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
- tokens << new_token(:REGEX, str_content[0..-2], :chunk => code[0..i])
211
- i += str_content.size + 1
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, :chunk => code[0..i])
217
- tokens << new_token(:INDENT, indent, :chunk => code[0..i+eol.size])
218
- i += indent.size + eol.size
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
- tokens << new_token(:WHITESPACE, whitespace, :chunk => code[0..i])
222
- i += whitespace.size
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
- tokens << new_token(:NEWLINE, eol, :chunk => code[0..i])
226
- i += eol.size
221
+ length = eol.size
222
+ tokens << new_token(:NEWLINE, eol, length)
227
223
 
228
224
  elsif chunk.match(/\A\//)
229
- tokens << new_token(:DIV, '/', :chunk => code[0..i])
230
- i += 1
225
+ length = 1
226
+ tokens << new_token(:DIV, '/', length)
231
227
 
232
228
  else
233
- raise PuppetLint::LexerError.new(code, i)
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 - The Symbol token type.
263
- # value - The token value.
264
- # opts - A Hash of additional values required to determine line number and
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
- if opts[:chunk]
274
- line_no = opts[:chunk].scan(/(\r\n|\r|\n)/).size + 1
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 { |r|
6
- r.type == :NODE && r.next_code_token.type == :NAME
7
- }.each do |token|
8
- value_token = token.next_code_token
9
- unless value_token.value == 'default'
10
- notify :warning, {
11
- :message => 'unquoted node name found',
12
- :line => value_token.line,
13
- :column => value_token.column,
14
- :token => value_token,
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
- indent_length = token.prev_token.column + 1
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 => 'indentation of => is not properly aligned',
129
- :line => arrow_tok.line,
130
- :column => arrow_tok.column,
131
- :token => arrow_tok,
132
- :indent_depth => indent_depth[indent_depth_idx],
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
- new_indent = ' ' * (problem[:indent_depth] - problem[:token].prev_token.column)
146
- problem[:token].prev_token.value = new_indent
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
- task :lint do
25
- PuppetLint.configuration.with_filename = true
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['**/*.pp']
66
+ matched_files = FileList[@pattern]
31
67
 
32
- if ignore_paths = PuppetLint.configuration.ignore_paths
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
@@ -1,3 +1,3 @@
1
1
  class PuppetLint
2
- VERSION = '1.0.1'
2
+ VERSION = '1.1.0'
3
3
  end
@@ -0,0 +1,6 @@
1
+ # lint:ignore:double_quoted_strings lint:ignore:quoted_booleans
2
+ "true"
3
+ "false"
4
+ # lint:endignore
5
+
6
+ "true"
@@ -0,0 +1,2 @@
1
+ "true" # lint:ignore:double_quoted_strings lint:ignore:quoted_booleans
2
+ "false" # lint:ignore:quoted_booleans lint:ignore:double_quoted_strings reason
@@ -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', :chunk => '')
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
- token = @lexer.new_token(:TEST, 'test', :chunk => "foo\nbar")
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', :chunk => '')
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
- token = @lexer.new_token(:TEST, 'test', :chunk => 'this is a test')
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
- token = @lexer.new_token(:TEST, 'test', :chunk => "foo\nbar\nbaz\ngronk")
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: 21
4
+ hash: 19
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
- - 0
9
8
  - 1
10
- version: 1.0.1
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-08-20 00:00:00 +10:00
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