puppet-lint 0.2.0.pre1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. data/.gitignore +1 -0
  2. data/.travis.yml +1 -14
  3. data/Gemfile +2 -0
  4. data/Rakefile +5 -0
  5. data/bin/puppet-lint +1 -99
  6. data/lib/puppet-lint.rb +4 -12
  7. data/lib/puppet-lint/bin.rb +115 -0
  8. data/lib/puppet-lint/configuration.rb +6 -2
  9. data/lib/puppet-lint/lexer.rb +135 -83
  10. data/lib/puppet-lint/lexer/token.rb +62 -0
  11. data/lib/puppet-lint/plugin.rb +57 -51
  12. data/lib/puppet-lint/plugins.rb +2 -0
  13. data/lib/puppet-lint/plugins/check_classes.rb +161 -45
  14. data/lib/puppet-lint/plugins/check_comments.rb +33 -0
  15. data/lib/puppet-lint/plugins/check_conditionals.rb +8 -10
  16. data/lib/puppet-lint/plugins/check_documentation.rb +41 -0
  17. data/lib/puppet-lint/plugins/check_resources.rb +28 -2
  18. data/lib/puppet-lint/plugins/check_strings.rb +6 -4
  19. data/lib/puppet-lint/plugins/check_variables.rb +1 -1
  20. data/lib/puppet-lint/plugins/check_whitespace.rb +26 -49
  21. data/lib/puppet-lint/tasks/puppet-lint.rb +2 -1
  22. data/lib/puppet-lint/version.rb +1 -1
  23. data/puppet-lint.gemspec +1 -0
  24. data/spec/fixtures/test/manifests/fail.pp +2 -0
  25. data/spec/fixtures/test/manifests/init.pp +3 -0
  26. data/spec/fixtures/test/manifests/warning.pp +2 -0
  27. data/spec/puppet-lint/bin_spec.rb +266 -0
  28. data/spec/puppet-lint/configuration_spec.rb +51 -0
  29. data/spec/puppet-lint/lexer/token_spec.rb +18 -0
  30. data/spec/puppet-lint/lexer_spec.rb +738 -0
  31. data/spec/puppet-lint/{check_classes_spec.rb → plugins/check_classes_spec.rb} +74 -7
  32. data/spec/puppet-lint/plugins/check_comments_spec.rb +40 -0
  33. data/spec/puppet-lint/{check_conditionals_spec.rb → plugins/check_conditionals_spec.rb} +19 -0
  34. data/spec/puppet-lint/plugins/check_documentation_spec.rb +55 -0
  35. data/spec/puppet-lint/{check_resources_spec.rb → plugins/check_resources_spec.rb} +65 -0
  36. data/spec/puppet-lint/{check_strings_spec.rb → plugins/check_strings_spec.rb} +18 -1
  37. data/spec/puppet-lint/{check_variables_spec.rb → plugins/check_variables_spec.rb} +0 -0
  38. data/spec/puppet-lint/plugins/check_whitespace_spec.rb +291 -0
  39. data/spec/puppet-lint_spec.rb +10 -0
  40. data/spec/spec_helper.rb +5 -0
  41. metadata +58 -24
  42. data/spec/puppet-lint/check_whitespace_spec.rb +0 -120
@@ -93,21 +93,28 @@ describe PuppetLint::Plugins::CheckClasses do
93
93
  }
94
94
  end
95
95
 
96
- describe 'class with attrs in order' do
96
+ describe 'parameterised class with a default value' do
97
97
  let(:code) { "class foo($bar, $baz='gronk') { }" }
98
98
 
99
- its(:problems) { should be_empty }
99
+ its(:problems) {
100
+ should only_have_problem({
101
+ :kind => :warning,
102
+ :message => 'parameterised class parameter without a default value',
103
+ :linenumber => 1,
104
+ :column => 11,
105
+ })
106
+ }
100
107
  end
101
108
 
102
- describe 'class with attrs out of order' do
103
- let(:code) { "class foo($bar='baz', $gronk) { }" }
109
+ describe 'parameterised class that inherits from a params class' do
110
+ let(:code) { "class foo($bar = $name) inherits foo::params { }" }
104
111
 
105
112
  its(:problems) {
106
113
  should have_problem({
107
114
  :kind => :warning,
108
- :message => "optional parameter listed before required parameter",
115
+ :message => "class inheriting from params class",
109
116
  :linenumber => 1,
110
- :column => 23,
117
+ :column => 34,
111
118
  })
112
119
  should_not have_problem :kind => :error
113
120
  }
@@ -119,6 +126,12 @@ describe PuppetLint::Plugins::CheckClasses do
119
126
  its(:problems) { should be_empty }
120
127
  end
121
128
 
129
+ describe 'define with parameter that calls a function' do
130
+ let(:code) { "define foo($bar=extlookup($name)) {}" }
131
+
132
+ its(:problems) { should == [] }
133
+ end
134
+
122
135
  describe 'define with attrs out of order' do
123
136
  let(:code) { "define foo($bar='baz', $gronk) { }" }
124
137
 
@@ -174,7 +187,7 @@ describe PuppetLint::Plugins::CheckClasses do
174
187
 
175
188
  describe 'class with parameters accessing local scope' do
176
189
  let(:code) { "
177
- class foo($bar) {
190
+ class foo($bar='UNSET') {
178
191
  $baz = $bar
179
192
  }"
180
193
  }
@@ -320,4 +333,58 @@ describe PuppetLint::Plugins::CheckClasses do
320
333
  let(:fullpath) { '/etc/puppet/modules/bar/manifests/init.pp' }
321
334
  its(:problems) { should be_empty }
322
335
  end
336
+
337
+ describe 'issue-101' do
338
+ let(:code) { "
339
+ define b (
340
+ $foo,
341
+ $bar='',
342
+ $baz={}
343
+ ) { }
344
+ " }
345
+
346
+ its(:problems) { should == [] }
347
+ end
348
+
349
+ describe 'module named foo-bar' do
350
+ let(:code) { 'class foo-bar { }' }
351
+ let(:fullpath) { '/etc/puppet/modules/foo-bar/manifests/init.pp' }
352
+
353
+ its(:problems) do
354
+ should only_have_problem({
355
+ :kind => :warning,
356
+ :message => 'class name containing a dash',
357
+ :linenumber => 1,
358
+ :column => 7,
359
+ })
360
+ end
361
+ end
362
+
363
+ describe 'define named foo-bar' do
364
+ let(:code) { 'define foo::foo-bar { }' }
365
+ let(:fullpath) { '/etc/puppet/modules/foo/manifests/foo-bar.pp' }
366
+
367
+ its(:problems) do
368
+ should only_have_problem({
369
+ :kind => :warning,
370
+ :message => 'defined type name containing a dash',
371
+ :linenumber => 1,
372
+ :column => 8,
373
+ })
374
+ end
375
+ end
376
+
377
+ describe 'class named bar-foo' do
378
+ let(:code) { 'class foo::bar-foo { }' }
379
+ let(:fullpath) { '/etc/puppet/modules/foo/manifests/bar-foo.pp' }
380
+
381
+ its(:problems) do
382
+ should only_have_problem({
383
+ :kind => :warning,
384
+ :message => 'class name containing a dash',
385
+ :linenumber => 1,
386
+ :column => 7,
387
+ })
388
+ end
389
+ end
323
390
  end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ describe PuppetLint::Plugins::CheckComments do
4
+ subject do
5
+ klass = described_class.new
6
+ fileinfo = {}
7
+ fileinfo[:fullpath] = defined?(fullpath).nil? ? '' : fullpath
8
+ klass.run(fileinfo, code)
9
+ klass
10
+ end
11
+
12
+ describe 'slash comments' do
13
+ let(:code) { "// foo" }
14
+
15
+ its(:problems) do
16
+ should only_have_problem({
17
+ :kind => :warning,
18
+ :message => '// comment found',
19
+ :linenumber => 1,
20
+ :column => 1,
21
+ })
22
+ end
23
+ end
24
+
25
+ describe 'slash asterisk comment' do
26
+ let(:code) { "
27
+ /* foo
28
+ */
29
+ "}
30
+
31
+ its(:problems) do
32
+ should only_have_problem({
33
+ :kind => :warning,
34
+ :message => '/* */ comment found',
35
+ :linenumber => 2,
36
+ :column => 7,
37
+ })
38
+ end
39
+ end
40
+ end
@@ -67,4 +67,23 @@ describe PuppetLint::Plugins::CheckConditionals do
67
67
  })
68
68
  end
69
69
  end
70
+
71
+ describe 'issue-117' do
72
+ let(:code) { "
73
+ $mem = inline_template('<%
74
+ mem,unit = scope.lookupvar(\'::memorysize\').split
75
+ mem = mem.to_f
76
+ # Normalize mem to bytes
77
+ case unit
78
+ when nil: mem *= (1<<0)
79
+ when \'kB\': mem *= (1<<10)
80
+ when \'MB\': mem *= (1<<20)
81
+ when \'GB\': mem *= (1<<30)
82
+ when \'TB\': mem *= (1<<40)
83
+ end
84
+ %><%= mem.to_i %>')
85
+ "}
86
+
87
+ its(:problems) { should == [] }
88
+ end
70
89
  end
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+
3
+ describe PuppetLint::Plugins::CheckDocumentation do
4
+ subject do
5
+ klass = described_class.new
6
+ fileinfo = {}
7
+ fileinfo[:fullpath] = defined?(fullpath).nil? ? '' : fullpath
8
+ klass.run(fileinfo, code)
9
+ klass
10
+ end
11
+
12
+ describe 'undocumented class' do
13
+ let(:code) { "class test {}" }
14
+
15
+ its(:problems) do
16
+ should only_have_problem({
17
+ :kind => :warning,
18
+ :message => 'class not documented',
19
+ :linenumber => 1,
20
+ :column => 1,
21
+ })
22
+ end
23
+ end
24
+
25
+ describe 'documented class' do
26
+ let(:code) { "
27
+ # foo
28
+ class test {}
29
+ "}
30
+
31
+ its(:problems) { should == [] }
32
+ end
33
+
34
+ describe 'undocumented defined type' do
35
+ let(:code) { "define test {}" }
36
+
37
+ its(:problems) do
38
+ should only_have_problem({
39
+ :kind => :warning,
40
+ :message => 'defined type not documented',
41
+ :linenumber => 1,
42
+ :column => 1,
43
+ })
44
+ end
45
+ end
46
+
47
+ describe 'documented defined type' do
48
+ let(:code) { "
49
+ # foo
50
+ define test {}
51
+ "}
52
+
53
+ its(:problems) { should == [] }
54
+ end
55
+ end
@@ -41,6 +41,20 @@ describe PuppetLint::Plugins::CheckResources do
41
41
  its(:problems) { should be_empty }
42
42
  end
43
43
 
44
+ describe 'file mode undef unquoted' do
45
+ let(:code) { "file { 'foo': mode => undef }" }
46
+
47
+ its(:problems) { should be_empty }
48
+ end
49
+
50
+ describe 'file mode undef quoted' do
51
+ let(:code) { "file { 'foo': mode => 'undef' }" }
52
+
53
+ its(:problems) {
54
+ should only_have_problem :kind => :warning, :message => "mode should be represented as a 4 digit octal value or symbolic mode", :linenumber => 1
55
+ }
56
+ end
57
+
44
58
  describe 'ensure as only attr in a single line resource' do
45
59
  let(:code) { "file { 'foo': ensure => present }" }
46
60
 
@@ -181,4 +195,55 @@ describe PuppetLint::Plugins::CheckResources do
181
195
  should only_have_problem :kind => :warning, :message => "symlink target specified in ensure attr", :linenumber => 3
182
196
  }
183
197
  end
198
+
199
+ # This should really be a lexer test, but I haven't had time to write that
200
+ # test suite yet.
201
+ describe 'issue #116' do
202
+ let(:code) { "
203
+ $config_file_init = $::operatingsystem ? {
204
+ /(?i:Debian|Ubuntu|Mint)/ => '/etc/default/foo',
205
+ default => '/etc/sysconfig/foo',
206
+ }"
207
+ }
208
+
209
+ its(:problems) { should == [] }
210
+ end
211
+
212
+ describe 'resource with duplicate parameters' do
213
+ let(:code) { "
214
+ file { '/tmp/foo':
215
+ ensure => present,
216
+ foo => bar,
217
+ baz => gronk,
218
+ foo => meh,
219
+ }"
220
+ }
221
+
222
+ its(:problems) {
223
+ should only_have_problem({
224
+ :kind => :error,
225
+ :message => 'duplicate parameter found in resource',
226
+ :linenumber => 6,
227
+ :column => 9,
228
+ })
229
+ }
230
+ end
231
+
232
+ describe 'case statement' do
233
+ let(:code) { %{
234
+ case $operatingsystem {
235
+ centos: {
236
+ $version = '1.2.3'
237
+ }
238
+ solaris: {
239
+ $version = '3.2.1'
240
+ }
241
+ default: {
242
+ fail("Module ${module_name} is not supported on ${operatingsystem}")
243
+ }
244
+ }}
245
+ }
246
+
247
+ its(:problems) { should == [] }
248
+ end
184
249
  end
@@ -87,7 +87,7 @@ describe PuppetLint::Plugins::CheckStrings do
87
87
  end
88
88
 
89
89
  describe 'double quoted string containing newline but no variables' do
90
- let(:code) { '"foo\n"' }
90
+ let(:code) { %{"foo\n"} }
91
91
 
92
92
  its(:problems) { should be_empty }
93
93
  end
@@ -155,4 +155,21 @@ describe PuppetLint::Plugins::CheckStrings do
155
155
  })
156
156
  }
157
157
  end
158
+
159
+ describe 'double quoted string with backslash for continuation' do
160
+ let(:code) { %{
161
+ class puppet::master::maintenance (
162
+ ) {
163
+ cron { 'puppet_master_reports_cleanup':
164
+ command => "/usr/bin/find /var/lib/puppet/reports -type f -mtime +15 \
165
+ -delete && /usr/bin/find /var/lib/puppet/reports -mindepth 1 \
166
+ -empty -type d -delete",
167
+ minute => '15',
168
+ hour => '5',
169
+ }
170
+ }
171
+ } }
172
+
173
+ its(:problems) { should == [] }
174
+ end
158
175
  end
@@ -0,0 +1,291 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe PuppetLint::Plugins::CheckWhitespace do
5
+ subject do
6
+ klass = described_class.new
7
+ klass.run(defined?(fullpath).nil? ? {:fullpath => ''} : {:fullpath => fullpath}, code)
8
+ klass
9
+ end
10
+
11
+ describe 'selectors inside a resource' do
12
+ let(:code) { "
13
+ file { 'foo':
14
+ ensure => $ensure,
15
+ require => $ensure ? {
16
+ present => Class['tomcat::install'],
17
+ absent => undef;
18
+ },
19
+ foo => bar,
20
+ }"
21
+ }
22
+
23
+ its(:problems) { should be_empty }
24
+ end
25
+
26
+ describe 'selectors in the middle of a resource' do
27
+ let(:code) { "
28
+ file { 'foo':
29
+ ensure => $ensure ? {
30
+ present => directory,
31
+ absent => undef,
32
+ },
33
+ owner => 'tomcat6',
34
+ }"
35
+ }
36
+
37
+ its(:problems) { should be_empty }
38
+ end
39
+
40
+ describe 'file resource with a source line > 80c' do
41
+ let(:code) { "
42
+ file {
43
+ source => 'puppet:///modules/certificates/etc/ssl/private/wildcard.example.com.crt',
44
+ }"
45
+ }
46
+
47
+ its(:problems) { should be_empty }
48
+ end
49
+
50
+ describe 'selector inside a resource' do
51
+ let(:code) { "
52
+ ensure => $ensure ? {
53
+ present => directory,
54
+ absent => undef,
55
+ },
56
+ owner => 'foo4',
57
+ group => 'foo4',
58
+ mode => '0755'," }
59
+
60
+ its(:problems) { should be_empty }
61
+ end
62
+
63
+ describe 'selector inside a hash inside a resource' do
64
+ let(:code) { "
65
+ server => {
66
+ ensure => ensure => $ensure ? {
67
+ present => directory,
68
+ absent => undef,
69
+ },
70
+ ip => '192.168.1.1'
71
+ },
72
+ owner => 'foo4',
73
+ group => 'foo4',
74
+ mode => '0755'," }
75
+
76
+ its(:problems) { should be_empty }
77
+ end
78
+
79
+
80
+ describe 'length of lines with UTF-8 characters' do
81
+ let(:code) { "
82
+ # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
83
+ # ┃ Configuration ┃
84
+ # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛"
85
+ }
86
+ its(:problems) {
87
+ should be_empty
88
+ }
89
+ end
90
+
91
+ describe 'issue #37' do
92
+ let(:code) { "
93
+ class { 'lvs::base':
94
+ virtualeservers => {
95
+ '192.168.2.13' => {
96
+ vport => '11025',
97
+ service => 'smtp',
98
+ scheduler => 'wlc',
99
+ protocol => 'tcp',
100
+ checktype => 'external',
101
+ checkcommand => '/path/to/checkscript',
102
+ real_servers => {
103
+ 'server01' => {
104
+ real_server => '192.168.2.14',
105
+ real_port => '25',
106
+ forwarding => 'masq',
107
+ },
108
+ 'server02' => {
109
+ real_server => '192.168.2.15',
110
+ real_port => '25',
111
+ forwarding => 'masq',
112
+ }
113
+ }
114
+ }
115
+ }
116
+ }"
117
+ }
118
+
119
+ its(:problems) { should be_empty }
120
+ end
121
+
122
+ describe 'single resource with a misaligned =>' do
123
+ let(:code) { "
124
+ file { '/tmp/foo':
125
+ foo => 1,
126
+ bar => 2,
127
+ gronk => 3,
128
+ baz => 4,
129
+ meh => 5,
130
+ }"
131
+ }
132
+
133
+ its(:problems) do
134
+ should have_problem({
135
+ :kind => :warning,
136
+ :message => '=> is not properly aligned',
137
+ :linenumber => 5,
138
+ :column => 15,
139
+ })
140
+ should have_problem({
141
+ :kind => :warning,
142
+ :message => '=> is not properly aligned',
143
+ :linenumber => 6,
144
+ :column => 14,
145
+ })
146
+ end
147
+ end
148
+
149
+ describe 'complex resource with a misaligned =>' do
150
+ let(:code) { "
151
+ file { '/tmp/foo':
152
+ foo => 1,
153
+ bar => $baz ? {
154
+ gronk => 2,
155
+ meh => 3,
156
+ },
157
+ meep => 4,
158
+ bah => 5,
159
+ }"
160
+ }
161
+
162
+ its(:problems) do
163
+ should have_problem({
164
+ :kind => :warning,
165
+ :message => '=> is not properly aligned',
166
+ :linenumber => 4,
167
+ :column => 14,
168
+ })
169
+ should have_problem({
170
+ :kind => :warning,
171
+ :message => '=> is not properly aligned',
172
+ :linenumber => 6,
173
+ :column => 15,
174
+ })
175
+ should have_problem({
176
+ :kind => :warning,
177
+ :message => '=> is not properly aligned',
178
+ :linenumber => 8,
179
+ :column => 14,
180
+ })
181
+ end
182
+ end
183
+
184
+ describe 'multi-resource with a misaligned =>' do
185
+ let(:code) { "
186
+ file {
187
+ '/tmp/foo': ;
188
+ '/tmp/bar':
189
+ foo => 'bar';
190
+ '/tmp/baz':
191
+ gronk => 'bah',
192
+ meh => 'no'
193
+ }"
194
+ }
195
+
196
+ its(:problems) do
197
+ should only_have_problem({
198
+ :kind => :warning,
199
+ :message => '=> is not properly aligned',
200
+ :linenumber => 8,
201
+ :column => 15,
202
+ })
203
+ end
204
+ end
205
+
206
+ describe 'multiple single line resources' do
207
+ let(:code) { "
208
+ file { 'foo': ensure => file }
209
+ package { 'bar': ensure => present }"
210
+ }
211
+
212
+ its(:problems) { should be_empty }
213
+ end
214
+
215
+ describe 'resource with unaligned => in commented line' do
216
+ let(:code) { "
217
+ file { 'foo':
218
+ ensure => directory,
219
+ # purge => true,
220
+ }"
221
+ }
222
+
223
+ its(:problems) { should be_empty }
224
+ end
225
+
226
+ describe 'hard tabs indents' do
227
+ let(:code) { "\tfoo => bar," }
228
+
229
+ its(:problems) {
230
+ should have_problem({
231
+ :kind => :error,
232
+ :message => 'tab character found',
233
+ :linenumber => 1,
234
+ :column => 1,
235
+ })
236
+ }
237
+ end
238
+
239
+ describe 'line with trailing whitespace' do
240
+ let(:code) { "foo " }
241
+
242
+ its(:problems) {
243
+ should have_problem({
244
+ :kind => :error,
245
+ :message => 'trailing whitespace found',
246
+ :linenumber => 1,
247
+ :column => 4,
248
+ })
249
+ }
250
+ end
251
+
252
+ describe '81 character line' do
253
+ let(:code) { 'a' * 81 }
254
+
255
+ its(:problems) {
256
+ should have_problem({
257
+ :kind => :warning,
258
+ :message => 'line has more than 80 characters',
259
+ :linenumber => 1,
260
+ :column => 80,
261
+ })
262
+ }
263
+ end
264
+
265
+ describe 'line indented by 3 spaces' do
266
+ let(:code) { "
267
+ file { 'foo':
268
+ foo => bar,
269
+ }"
270
+ }
271
+
272
+ its(:problems) {
273
+ should have_problem({
274
+ :kind => :error,
275
+ :message => 'two-space soft tabs not used',
276
+ :linenumber => 3,
277
+ :column => 1,
278
+ })
279
+ }
280
+ end
281
+
282
+ describe 'single line resource spread out on multiple lines' do
283
+ let(:code) {"
284
+ file {
285
+ 'foo': ensure => present,
286
+ }"
287
+ }
288
+
289
+ its(:problems) { should == [] }
290
+ end
291
+ end