puppet-lint 2.0.2 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/.rspec +1 -0
  4. data/CHANGELOG.md +56 -0
  5. data/Gemfile +15 -4
  6. data/README.md +60 -5
  7. data/Rakefile +13 -0
  8. data/lib/puppet-lint.rb +21 -4
  9. data/lib/puppet-lint/configuration.rb +1 -0
  10. data/lib/puppet-lint/data.rb +12 -4
  11. data/lib/puppet-lint/lexer.rb +32 -7
  12. data/lib/puppet-lint/optparser.rb +4 -3
  13. data/lib/puppet-lint/plugins/check_classes.rb +73 -0
  14. data/lib/puppet-lint/plugins/check_comments.rb +4 -0
  15. data/lib/puppet-lint/plugins/check_conditionals.rb +4 -0
  16. data/lib/puppet-lint/plugins/check_documentation.rb +2 -0
  17. data/lib/puppet-lint/plugins/check_nodes.rb +2 -0
  18. data/lib/puppet-lint/plugins/check_resources.rb +80 -3
  19. data/lib/puppet-lint/plugins/check_strings.rb +13 -1
  20. data/lib/puppet-lint/plugins/check_variables.rb +6 -0
  21. data/lib/puppet-lint/plugins/check_whitespace.rb +12 -0
  22. data/lib/puppet-lint/version.rb +1 -1
  23. data/puppet-lint.gemspec +0 -2
  24. data/spec/fixtures/test/manifests/ignore_reason.pp +4 -1
  25. data/spec/fixtures/test/manifests/mismatched_control_comment.pp +1 -0
  26. data/spec/puppet-lint/bin_spec.rb +25 -12
  27. data/spec/puppet-lint/configuration_spec.rb +1 -0
  28. data/spec/puppet-lint/lexer_spec.rb +56 -2
  29. data/spec/puppet-lint/plugins/check_classes/code_on_top_scope_spec.rb +43 -0
  30. data/spec/puppet-lint/plugins/check_classes/name_contains_uppercase_spec.rb +66 -0
  31. data/spec/puppet-lint/plugins/check_classes/parameter_order_spec.rb +49 -0
  32. data/spec/puppet-lint/plugins/check_resources/ensure_first_param_spec.rb +140 -51
  33. data/spec/puppet-lint/plugins/check_strings/single_quote_string_with_variables_spec.rb +24 -0
  34. data/spec/puppet-lint/plugins/check_strings/variables_not_enclosed_spec.rb +17 -0
  35. data/spec/puppet-lint/plugins/check_variables/variable_contains_dash_spec.rb +8 -0
  36. data/spec/spec_helper.rb +5 -0
  37. metadata +9 -17
@@ -1,3 +1,3 @@
1
1
  class PuppetLint
2
- VERSION = '2.0.2'
2
+ VERSION = '2.1.0'
3
3
  end
@@ -14,8 +14,6 @@ Gem::Specification.new do |s|
14
14
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
15
15
  s.require_paths = ["lib"]
16
16
 
17
- s.add_development_dependency 'github_changelog_generator'
18
-
19
17
  s.authors = ['Tim Sharpe']
20
18
  s.email = 'tim@sharpe.id.au'
21
19
  end
@@ -1 +1,4 @@
1
- "test" # lint:ignore:double_quoted_strings for a good reason
1
+ # test::ignore_reason
2
+ class test::ignore_reason {
3
+ $foo = "test" # lint:ignore:double_quoted_strings for a good reason
4
+ }
@@ -213,17 +213,6 @@ describe PuppetLint::Bin do
213
213
  }
214
214
  end
215
215
 
216
- context 'to print %{linenumber}' do
217
- let(:args) { [
218
- '--log-format', '%{linenumber}',
219
- 'spec/fixtures/test/manifests/fail.pp'
220
- ] }
221
-
222
- its(:exitstatus) { is_expected.to eq(1) }
223
- its(:stdout) { is_expected.to eq('2') }
224
- its(:stderr) { is_expected.to eq('DEPRECATION: Please use %{line} instead of %{linenumber}') }
225
- end
226
-
227
216
  context 'to print %{line}' do
228
217
  let(:args) { [
229
218
  '--log-format', '%{line}',
@@ -275,6 +264,21 @@ describe PuppetLint::Bin do
275
264
  end
276
265
  end
277
266
 
267
+ context 'when displaying results as json' do
268
+ let(:args) { [
269
+ '--json',
270
+ 'spec/fixtures/test/manifests/warning.pp',
271
+ ] }
272
+ its(:exitstatus) { is_expected.to eq(0) }
273
+ its(:stdout) do
274
+ if respond_to?(:include_json)
275
+ is_expected.to include_json([{'KIND' => 'WARNING'}])
276
+ else
277
+ is_expected.to match(/\[\n \{/)
278
+ end
279
+ end
280
+ end
281
+
278
282
  context 'when hiding ignored problems' do
279
283
  let(:args) { [
280
284
  'spec/fixtures/test/manifests/ignore.pp'
@@ -302,7 +306,7 @@ describe PuppetLint::Bin do
302
306
 
303
307
  its(:exitstatus) { is_expected.to eq(0) }
304
308
  its(:stdout) { is_expected.to eq([
305
- "IGNORED: double quoted string containing no variables on line 1",
309
+ "IGNORED: double quoted string containing no variables on line 3",
306
310
  " for a good reason",
307
311
  ].join("\n")) }
308
312
  end
@@ -323,4 +327,13 @@ describe PuppetLint::Bin do
323
327
  its(:exitstatus) { is_expected.to eq(0) }
324
328
  its(:stdout) { is_expected.to match(/^.*line 6$/) }
325
329
  end
330
+
331
+ context 'when an lint:endignore control comment exists with no opening lint:ignore comment' do
332
+ let(:args) { [
333
+ 'spec/fixtures/test/manifests/mismatched_control_comment.pp',
334
+ ] }
335
+
336
+ its(:exitstatus) { is_expected.to eq(0) }
337
+ its(:stdout) { is_expected.to match(/WARNING: lint:endignore comment with no opening lint:ignore:<check> comment found on line 1/) }
338
+ end
326
339
  end
@@ -51,6 +51,7 @@ describe PuppetLint::Configuration do
51
51
  'with_context' => false,
52
52
  'fix' => false,
53
53
  'show_ignored' => false,
54
+ 'json' => false,
54
55
  })
55
56
  end
56
57
  end
@@ -17,8 +17,26 @@ describe PuppetLint::Lexer do
17
17
  expect(token.line).to eq(1)
18
18
  end
19
19
 
20
+ it 'should get correct line number after double quoted multi line string' do
21
+ token = @lexer.new_token(:STRING, "test\ntest", 9)
22
+ token = @lexer.new_token(:TEST, 'test', 4)
23
+ expect(token.line).to eq(2)
24
+ end
25
+
26
+ it 'should get correct line number after a multi line comment' do
27
+ token = @lexer.new_token(:MLCOMMENT, "test\ntest", 9)
28
+ token = @lexer.new_token(:TEST, 'test', 4)
29
+ expect(token.line).to eq(2)
30
+ end
31
+
20
32
  it 'should calculate the line number for a multi line string' do
21
- @lexer.instance_variable_set('@line_no', 2)
33
+ token = @lexer.new_token(:SSTRING, "test\ntest", 9)
34
+ token = @lexer.new_token(:TEST, 'test', 4)
35
+ expect(token.line).to eq(2)
36
+ end
37
+
38
+ it 'should calculate line number for string that ends with newline' do
39
+ token = @lexer.new_token(:SSTRING, "test\n", 5)
22
40
  token = @lexer.new_token(:TEST, 'test', 4)
23
41
  expect(token.line).to eq(2)
24
42
  end
@@ -37,8 +55,9 @@ describe PuppetLint::Lexer do
37
55
  it 'should calculate the column number for a multi line string' do
38
56
  @lexer.instance_variable_set('@line_no', 4)
39
57
  @lexer.instance_variable_set('@column', "gronk".size)
58
+ token = @lexer.new_token(:SSTRING, "test\ntest", 9)
40
59
  token = @lexer.new_token(:TEST, 'test', 4)
41
- expect(token.column).to eq(5)
60
+ expect(token.column).to eq(4)
42
61
  end
43
62
  end
44
63
 
@@ -629,6 +648,12 @@ describe PuppetLint::Lexer do
629
648
  expect(token.type).to eq(:CLASSREF)
630
649
  expect(token.value).to eq('::One')
631
650
  end
651
+
652
+ it 'should match terms that start with Types' do
653
+ token = @lexer.tokenise('Regexp_foo').first
654
+ expect(token.type).to eq(:CLASSREF)
655
+ expect(token.value).to eq('Regexp_foo')
656
+ end
632
657
  end
633
658
 
634
659
  context ':NAME' do
@@ -655,6 +680,12 @@ describe PuppetLint::Lexer do
655
680
  expect(token.type).to eq(:NAME)
656
681
  expect(token.value).to eq('::1one::2two::3three')
657
682
  end
683
+
684
+ it 'should match barewords beginning with an underscore' do
685
+ token = @lexer.tokenise('_bareword').first
686
+ expect(token.type).to eq(:NAME)
687
+ expect(token.value).to eq('_bareword')
688
+ end
658
689
  end
659
690
 
660
691
  context ':NUMBER' do
@@ -773,6 +804,12 @@ describe PuppetLint::Lexer do
773
804
  expect(token.type).to eq(:SSTRING)
774
805
  expect(token.value).to eq(%{foo\\\\})
775
806
  end
807
+
808
+ it "should match single quoted string containing a line break" do
809
+ token = @lexer.tokenise("'\n'").first
810
+ expect(token.type).to eq(:SSTRING)
811
+ expect(token.value).to eq("\n")
812
+ end
776
813
  end
777
814
 
778
815
  context ':REGEX' do
@@ -809,6 +846,17 @@ describe PuppetLint::Lexer do
809
846
  tokens = @lexer.tokenise('$x = $a/$b/$c')
810
847
  expect(tokens.select { |r| r.type == :REGEX }).to be_empty
811
848
  end
849
+
850
+ it 'should properly parse when regex follows an if' do
851
+ tokens = @lexer.tokenise('if /^icinga_service_icon_.*/ in $location_info { }')
852
+ expect(tokens[2].type).to eq(:REGEX)
853
+ end
854
+
855
+ it 'should properly parse when a regex follows an elsif' do
856
+ tokens = @lexer.tokenise('if /a/ in $location_info { } elsif /b/ in $location_info { }')
857
+ expect(tokens[2].type).to eq(:REGEX)
858
+ expect(tokens[14].type).to eq(:REGEX)
859
+ end
812
860
  end
813
861
 
814
862
  context ':STRING' do
@@ -817,5 +865,11 @@ describe PuppetLint::Lexer do
817
865
  @lexer.tokenise("exec { \"/bin/echo \\\\\\\"${environment}\\\\\\\"\": }")
818
866
  }.to_not raise_error
819
867
  end
868
+
869
+ it "should match double quoted string containing a line break" do
870
+ token = @lexer.tokenise(%Q{"\n"}).first
871
+ expect(token.type).to eq(:STRING)
872
+ expect(token.value).to eq("\n")
873
+ end
820
874
  end
821
875
  end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'code_on_top_scope' do
4
+ describe 'comments outside class block' do
5
+ let(:code) { "
6
+ # Baz
7
+ class foo:bar {
8
+ }"
9
+ }
10
+
11
+ its(:problems) { should be_empty }
12
+ end
13
+
14
+ describe 'new lines outside of class-define block' do
15
+ let(:code) { "
16
+
17
+ class foo:bar {
18
+ }
19
+
20
+ "
21
+ }
22
+
23
+ its(:problems) { should be_empty }
24
+ end
25
+
26
+ describe 'code outside class block' do
27
+ let(:code) { "
28
+ include('something')
29
+
30
+ # Baz
31
+ class foo:bar {
32
+ }
33
+
34
+ define whatever {
35
+ }"
36
+ }
37
+
38
+ its(:problems) {
39
+ should contain_warning("code outside of class or define block - include")
40
+ should have(4).problems
41
+ }
42
+ end
43
+ end
@@ -0,0 +1,66 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'names_containing_uppercase' do
4
+
5
+ context 'defined type named FooBar' do
6
+ let(:code) { 'define FooBar { }' }
7
+ let(:path) { 'foobar/manifests/init.pp' }
8
+ let(:class_msg) { "defined type 'FooBar' contains illegal uppercase" }
9
+
10
+ it 'should only detect a single problem' do
11
+ expect(problems).to have(1).problem
12
+ end
13
+
14
+ it 'should create an error' do
15
+ expect(problems).to contain_error(class_msg).on_line(1).in_column(8)
16
+ end
17
+ end
18
+
19
+ context 'class named FooBar' do
20
+ let(:code) { 'class FooBar { }' }
21
+ let(:path) { 'foobar/manifests/init.pp' }
22
+ let(:class_msg) { "class 'FooBar' contains illegal uppercase" }
23
+
24
+ it 'should only detect a single problem' do
25
+ expect(problems).to have(1).problem
26
+ end
27
+
28
+ it 'should create an error' do
29
+ expect(problems).to contain_error(class_msg).on_line(1).in_column(7)
30
+ end
31
+ end
32
+
33
+ context 'class named Foo::BarFoo' do
34
+ let(:code) { 'class Foo::BarFoo { }' }
35
+ let(:path) { 'foo/manifests/barfoo.pp' }
36
+ let(:class_msg) { "class 'Foo::BarFoo' contains illegal uppercase" }
37
+
38
+ it 'should only detect a single problem' do
39
+ expect(problems).to have(1).problem
40
+ end
41
+
42
+ it 'should create an error' do
43
+ expect(problems).to contain_error(class_msg).on_line(1).in_column(7)
44
+ end
45
+
46
+ context 'check fix -' do
47
+ before do
48
+ PuppetLint.configuration.fix = true
49
+ end
50
+
51
+ after do
52
+ PuppetLint.configuration.fix = false
53
+ end
54
+
55
+ let(:fixed) { code.downcase }
56
+
57
+ it 'should create an error' do
58
+ expect(problems).to contain_fixed(class_msg).on_line(1).in_column(7)
59
+ end
60
+
61
+ it 'should downcase the class name' do
62
+ expect(manifest).to eq(fixed)
63
+ end
64
+ end
65
+ end
66
+ end
@@ -73,5 +73,54 @@ describe 'parameter_order' do
73
73
  expect(problems).to have(0).problems
74
74
  end
75
75
  end
76
+
77
+ context "#{type} parameter w/a hash containing a variable and no optional parameters" do
78
+ let(:code) { "
79
+ $var1 = 'test'
80
+
81
+ #{type} test (
82
+ $entries = {
83
+ '200 xxx' => {
84
+ param1 => $var1,
85
+ param2 => 'value2',
86
+ param3 => 'value3',
87
+ }
88
+ },
89
+ $mandatory => undef,
90
+ ) { }
91
+ "}
92
+
93
+ it { expect(problems).to have(0).problem }
94
+ end
95
+
96
+ context "#{type} parameter w/a hash containing a variable followed by an optional parameter" do
97
+ let(:code) { "
98
+ $var1 = 'test'
99
+
100
+ #{type} test (
101
+ $entries = {
102
+ '200 xxx' => {
103
+ param1 => $var1,
104
+ param2 => 'value2',
105
+ param3 => 'value3',
106
+ }
107
+ },
108
+ $optional,
109
+ $mandatory => undef,
110
+ ) { }
111
+ "}
112
+
113
+ it { expect(problems).to contain_warning(msg).on_line(12).in_column(11) }
114
+ end
115
+
116
+ context "#{type} parameter w/array containing a variable" do
117
+ let(:code) {"
118
+ #{type} test (
119
+ $var1 = [$::hostname, 'host'],
120
+ ) { }
121
+ "}
122
+
123
+ it { expect(problems).to have(0).problem }
124
+ end
76
125
  end
77
126
  end
@@ -3,72 +3,161 @@ require 'spec_helper'
3
3
  describe 'ensure_first_param' do
4
4
  let(:msg) { "ensure found on line but it's not the first attribute" }
5
5
 
6
- context 'ensure as only attr in a single line resource' do
7
- let(:code) { "file { 'foo': ensure => present }" }
6
+ context 'with fix disabled' do
7
+ context 'ensure as only attr in a single line resource' do
8
+ let(:code) { "file { 'foo': ensure => present }" }
8
9
 
9
- it 'should not detect any problems' do
10
- expect(problems).to have(0).problems
10
+ it 'should not detect any problems' do
11
+ expect(problems).to have(0).problems
12
+ end
11
13
  end
12
- end
13
14
 
14
- context 'ensure as only attr in a multi line resource' do
15
- let(:code) { "
16
- file { 'foo':
17
- ensure => present,
18
- }"
19
- }
15
+ context 'ensure as only attr in a multi line resource' do
16
+ let(:code) { "
17
+ file { 'foo':
18
+ ensure => present,
19
+ }"
20
+ }
20
21
 
21
- it 'should not detect any problems' do
22
- expect(problems).to have(0).problems
22
+ it 'should not detect any problems' do
23
+ expect(problems).to have(0).problems
24
+ end
23
25
  end
24
- end
25
26
 
26
- context 'ensure as second attr in a multi line resource' do
27
- let(:code) { "
28
- file { 'foo':
29
- mode => '0000',
30
- ensure => present,
31
- }"
32
- }
27
+ context 'ensure as second attr in a multi line resource' do
28
+ let(:code) { "
29
+ file { 'foo':
30
+ mode => '0000',
31
+ ensure => present,
32
+ }"
33
+ }
34
+
35
+ it 'should only detect a single problem' do
36
+ expect(problems).to have(1).problem
37
+ end
33
38
 
34
- it 'should only detect a single problem' do
35
- expect(problems).to have(1).problem
39
+ it 'should create a warning' do
40
+ expect(problems).to contain_warning(msg).on_line(4).in_column(11)
41
+ end
36
42
  end
37
43
 
38
- it 'should create a warning' do
39
- expect(problems).to contain_warning(msg).on_line(4).in_column(9)
44
+ context 'ensure as first attr in a multi line resource' do
45
+ let(:code) { "
46
+ file { 'foo':
47
+ ensure => present,
48
+ mode => '0000',
49
+ }"
50
+ }
51
+
52
+ it 'should not detect any problems' do
53
+ expect(problems).to have(0).problems
54
+ end
40
55
  end
41
- end
42
56
 
43
- context 'ensure as first attr in a multi line resource' do
44
- let(:code) { "
45
- file { 'foo':
46
- ensure => present,
47
- mode => '0000',
48
- }"
49
- }
57
+ context 'ensure as a hash key in classes does not need to be first' do
58
+ let(:code) { "
59
+ class thing {
60
+ class {'thang':
61
+ stuff => {
62
+ 'stuffing' => {
63
+ ensure => 'present',
64
+ blah => 'bleah',
65
+ }
66
+ },
67
+ }
68
+ }"
69
+ }
50
70
 
51
- it 'should not detect any problems' do
52
- expect(problems).to have(0).problems
71
+ it 'should not detect any problems' do
72
+ expect(problems).to have(0).problems
73
+ end
53
74
  end
54
75
  end
55
76
 
56
- context 'ensure as a hash key in classes does not need to be first' do
57
- let(:code) { "
58
- class thing {
59
- class {'thang':
60
- stuff => {
61
- 'stuffing' => {
62
- ensure => 'present',
63
- blah => 'bleah',
64
- }
65
- },
66
- }
67
- }"
68
- }
69
-
70
- it 'should not detect any problems' do
71
- expect(problems).to have(0).problems
77
+ context 'with fix enabled' do
78
+ before do
79
+ PuppetLint.configuration.fix = true
80
+ end
81
+
82
+ after do
83
+ PuppetLint.configuration.fix = false
84
+ end
85
+
86
+ context 'ensure as only attr in a single line resource' do
87
+ let(:code) { "file { 'foo': ensure => present }" }
88
+
89
+ it 'should not detect any problems' do
90
+ expect(problems).to have(0).problems
91
+ end
92
+ end
93
+
94
+ context 'ensure as only attr in a multi line resource' do
95
+ let(:code) { "
96
+ file { 'foo':
97
+ ensure => present,
98
+ }"
99
+ }
100
+
101
+ it 'should not detect any problems' do
102
+ expect(problems).to have(0).problems
103
+ end
104
+ end
105
+
106
+ context 'ensure as second attr in a multi line resource' do
107
+ let(:code) { "
108
+ file { 'foo':
109
+ mode => '0000',
110
+ ensure => present,
111
+ }"
112
+ }
113
+
114
+ it 'should only detect a single problem' do
115
+ expect(problems).to have(1).problem
116
+ end
117
+
118
+ it 'should create a warning' do
119
+ expect(problems).to contain_fixed(msg).on_line(4).in_column(11)
120
+ end
121
+
122
+ it 'should make ensure the first attr' do
123
+ expect(manifest).to eq("
124
+ file { 'foo':
125
+ ensure => present,
126
+ mode => '0000',
127
+ }")
128
+ end
129
+ end
130
+
131
+ context 'ensure as first attr in a multi line resource' do
132
+ let(:code) { "
133
+ file { 'foo':
134
+ ensure => present,
135
+ mode => '0000',
136
+ }"
137
+ }
138
+
139
+ it 'should not detect any problems' do
140
+ expect(problems).to have(0).problems
141
+ end
142
+ end
143
+
144
+ context 'ensure as a hash key in classes does not need to be first' do
145
+ let(:code) { "
146
+ class thing {
147
+ class {'thang':
148
+ stuff => {
149
+ 'stuffing' => {
150
+ ensure => 'present',
151
+ blah => 'bleah',
152
+ }
153
+ },
154
+ }
155
+ }"
156
+ }
157
+
158
+ it 'should not detect any problems' do
159
+ expect(problems).to have(0).problems
160
+ end
72
161
  end
73
162
  end
74
163
  end