puppet-lint 2.0.2 → 2.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.
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