puppet-lint-manifest_whitespace-check 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3d91ac8fb2a3196f56aa2e30c76acdfa62f1b318
4
+ data.tar.gz: a8a98d0f46aada6c955650901e3fe9cdec2b565d
5
+ SHA512:
6
+ metadata.gz: f1bd0c7f396ce8307204b2fbb4b843cf570fecc32181a0c1ddf6095f60642f3518a072508d496d5b3af9fd84581180340736b1f212e41be3b64d3d9253807d1d
7
+ data.tar.gz: d3484a2404a91a7d558a1a8fb57c95e42f26abd43a8db0d5ba98cb6bdaefea39048b353cdf269dac72df4eeaca873759775117548d52c65c9c48088042798dcb
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Tim Sharpe
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,153 @@
1
+ # puppet-lint manifest whitespace check
2
+
3
+ Adds a new puppet-lint check to verify a number of whitespace issues (newlines etc.)
4
+
5
+ These checks are very opinionated.
6
+
7
+ **--fix support: Yes**
8
+
9
+ ## Installation
10
+
11
+ To use this plugin, add the following line to the Gemfile in your Puppet code
12
+ base and run `bundle install`.
13
+
14
+ ```ruby
15
+ gem 'puppet-lint-manifest_whitespace-check'
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ This plugin provides a number of new checks to `puppet-lint`.
21
+
22
+ ### manifest_whitespace_class_opening_curly_brace
23
+
24
+ > There should be a single space before the opening curly bracket of a class body.
25
+
26
+ Good examples:
27
+
28
+ ```puppet
29
+ class myclass (
30
+ # the parameters
31
+ ) {
32
+ # the body
33
+ }
34
+
35
+ class myclass {
36
+ # the body
37
+ }
38
+ ```
39
+
40
+ Bad examples:
41
+
42
+ ```puppet
43
+ class myclass (
44
+ # the parameters
45
+ )
46
+ {
47
+ # the body
48
+ }
49
+
50
+ class myclass (
51
+ # the parameters
52
+ ){
53
+ # the body
54
+ }
55
+
56
+ class myclass
57
+ {
58
+ # the body
59
+ }
60
+ ```
61
+
62
+ ### manifest_whitespace_missing_newline_end_of_file
63
+
64
+ > There should be a single newline at the end of a manifest.
65
+
66
+ Not zero, not two or more. Be advised: this single newline is implicit at the end of your last line of code. This check does not add a single empty line!
67
+
68
+ ### manifest_whitespace_double_newline_end_of_file
69
+
70
+ > There should be a single newline at the end of a manifest.
71
+
72
+ Not zero, not two or more. Be advised: this single newline is implicit at the end of your last line of code. This check does not add a single empty line!
73
+
74
+ ### manifest_whitespace_arrows_single_space_after
75
+
76
+ > There should be a single space after an arrow.
77
+
78
+ When you list resource parameters or build a hash, you usually use arrow operators (`=>`). There are checks that make sure your arrows are aligned, but this check will ensure the number of spaces after your arrows is consistently 1.
79
+
80
+ ### manifest_whitespace_newline_beginning_of_file
81
+
82
+ > There should not be a newline at the beginning of a manifest.
83
+
84
+ There should not be empty lines at the beginning of your file.
85
+
86
+ ### manifest_whitespace_class_name_single_space_before
87
+
88
+ > There should be a single space between the class or defined resource statement and the name.
89
+
90
+ Good examples:
91
+
92
+ ```puppet
93
+ class myclass (
94
+ # the parameters
95
+ ) {
96
+ # the body
97
+ }
98
+
99
+ class myclass {
100
+ # the body
101
+ }
102
+ ```
103
+
104
+ Bad example:
105
+
106
+ ```puppet
107
+ class myclass (
108
+ # the parameters
109
+ ) {
110
+ # the body
111
+ }
112
+ ```
113
+
114
+ ### manifest_whitespace_class_name_single_space_after
115
+
116
+ > There should be a single space between the class or resource name and the first bracket.
117
+
118
+ Good examples:
119
+
120
+ ```puppet
121
+ class myclass (
122
+ # the parameters
123
+ ) {
124
+ # the body
125
+ }
126
+
127
+ class myclass {
128
+ # the body
129
+ }
130
+ ```
131
+
132
+ Bad example:
133
+
134
+ ```puppet
135
+ class myclass(
136
+ # the parameters
137
+ ){
138
+ # the body
139
+ }
140
+
141
+ class myclass (
142
+ # the parameters
143
+ ){
144
+ # the body
145
+ }
146
+
147
+ class myclass
148
+ (
149
+ # the parameters
150
+ ){
151
+ # the body
152
+ }
153
+ ```
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ PuppetLint.new_check(:manifest_whitespace_arrows_single_space_after) do
4
+ def check
5
+ tokens.select { |token| token.type == :FARROW }.each do |token|
6
+ next_token = token.next_token
7
+
8
+ next unless next_token && !is_single_space(next_token)
9
+
10
+ notify(
11
+ :error,
12
+ message: 'there should be a single space after an arrow',
13
+ line: next_token.line,
14
+ column: next_token.column,
15
+ token: next_token,
16
+ )
17
+ end
18
+ end
19
+
20
+ def fix(problem)
21
+ token = problem[:token]
22
+
23
+ if token.type == :WHITESPACE
24
+ token.value = ' '
25
+ return
26
+ end
27
+
28
+ add_token(tokens.index(token), new_single_space)
29
+ end
30
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ PuppetLint.new_check(:manifest_whitespace_class_name_single_space_before) do
4
+ def check
5
+ (class_indexes + defined_type_indexes).each do |class_idx|
6
+ class_token = class_idx[:tokens].first
7
+ name_token = class_token.next_token_of(:NAME)
8
+ next unless name_token
9
+
10
+ next_token = class_token.next_token
11
+ next unless tokens.index(name_token) != tokens.index(class_token) + 2 ||
12
+ !is_single_space(next_token)
13
+
14
+ notify(
15
+ :error,
16
+ message: 'there should be a single space between the class or defined resource statement and the name',
17
+ line: next_token.line,
18
+ column: next_token.column,
19
+ token: next_token,
20
+ )
21
+ end
22
+ end
23
+
24
+ def fix(problem)
25
+ raise PuppetLint::NoFix if problem[:token].type != :WHITESPACE
26
+
27
+ problem[:token].value = ' '
28
+ end
29
+ end
30
+
31
+ PuppetLint.new_check(:manifest_whitespace_class_name_single_space_after) do
32
+ def check
33
+ (class_indexes + defined_type_indexes).each do |class_idx|
34
+ class_token = class_idx[:tokens].first
35
+ name_token = class_token.next_token_of(:NAME)
36
+ next unless name_token
37
+
38
+ next_token = name_token.next_token
39
+ bracket_token = name_token.next_token_of(%i[LPAREN LBRACE])
40
+ next unless tokens.index(name_token) != tokens.index(bracket_token) - 2 ||
41
+ !is_single_space(next_token)
42
+
43
+ notify(
44
+ :error,
45
+ message: 'there should be a single space between the class or resource name and the first bracket',
46
+ line: next_token.line,
47
+ column: next_token.column,
48
+ token: next_token,
49
+ )
50
+ end
51
+ end
52
+
53
+ def fix(problem)
54
+ token = problem[:token]
55
+ bracket_token = token.prev_token.next_token_of(%i[LPAREN LBRACE])
56
+
57
+ if token == bracket_token
58
+ add_token(tokens.index(bracket_token), new_single_space)
59
+ return
60
+ end
61
+
62
+ while token != bracket_token
63
+ unless %i[WHITESPACE INDENT NEWLINE].include?(token.type)
64
+ raise PuppetLint::NoFix
65
+ end
66
+
67
+ remove_token(token)
68
+ token = token.next_token
69
+ end
70
+
71
+ add_token(tokens.index(bracket_token), new_single_space)
72
+ end
73
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ PuppetLint.new_check(:manifest_whitespace_class_opening_curly_brace) do
4
+ def check
5
+ (class_indexes + defined_type_indexes).each do |class_idx|
6
+ class_token = class_idx[:tokens].first
7
+ bracket_token = class_token.next_token_of(:LBRACE)
8
+ prev_token = bracket_token.prev_token
9
+ prev_code_token = bracket_token.prev_token_of(:RPAREN)
10
+
11
+ next unless prev_code_token
12
+ next unless tokens.index(prev_code_token) != tokens.index(bracket_token) - 2 ||
13
+ !is_single_space(prev_token)
14
+
15
+ notify(
16
+ :error,
17
+ message: 'there should be a single space before the opening curly bracket of a class body',
18
+ line: bracket_token.line,
19
+ column: bracket_token.column,
20
+ token: bracket_token,
21
+ )
22
+ end
23
+ end
24
+
25
+ def fix(problem)
26
+ token = problem[:token]
27
+ prev_code_token = token.prev_token_of(:RPAREN).next_token
28
+
29
+ while token != prev_code_token
30
+ unless %i[WHITESPACE INDENT NEWLINE].include?(prev_code_token.type)
31
+ raise PuppetLint::NoFix
32
+ end
33
+
34
+ remove_token(prev_code_token)
35
+ prev_code_token = prev_code_token.next_token
36
+ end
37
+
38
+ add_token(tokens.index(token), new_single_space)
39
+ end
40
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ PuppetLint.new_check(:manifest_whitespace_newline_beginning_of_file) do
4
+ def check
5
+ tokens.each do |token|
6
+ return if token.type != :NEWLINE
7
+
8
+ notify(
9
+ :error,
10
+ message: 'there should not be a newline at the beginning of a manifest',
11
+ line: token.line,
12
+ column: token.column,
13
+ token: token,
14
+ )
15
+ end
16
+ end
17
+
18
+ def fix(problem)
19
+ remove_token(problem[:token])
20
+ end
21
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ PuppetLint.new_check(:manifest_whitespace_missing_newline_end_of_file) do
4
+ def check
5
+ last_token = tokens.last
6
+
7
+ if last_token.type != :NEWLINE
8
+ notify(
9
+ :error,
10
+ message: 'there should be a single newline at the end of a manifest',
11
+ line: last_token.line,
12
+ column: last_token.column,
13
+ token: last_token,
14
+ )
15
+ end
16
+ end
17
+
18
+ def fix(problem)
19
+ index = tokens.index(problem[:token])
20
+ tokens.insert(index + 1, PuppetLint::Lexer::Token.new(:NEWLINE, "\n", 0, 0))
21
+ end
22
+ end
23
+
24
+ PuppetLint.new_check(:manifest_whitespace_double_newline_end_of_file) do
25
+ def check
26
+ last_token = tokens.last
27
+
28
+ if last_token.type == :NEWLINE
29
+ while last_token.prev_token && last_token.prev_token.type == :NEWLINE
30
+ notify(
31
+ :error,
32
+ message: 'there should be a single newline at the end of a manifest',
33
+ line: last_token.line,
34
+ column: last_token.column,
35
+ token: last_token,
36
+ )
37
+
38
+ last_token = last_token.prev_token
39
+ end
40
+ end
41
+ end
42
+
43
+ def fix(problem)
44
+ tokens.delete(problem[:token])
45
+ end
46
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ def is_single_space(token)
4
+ token.type == :WHITESPACE && token.value == ' '
5
+ end
6
+
7
+ def new_single_space
8
+ PuppetLint::Lexer::Token.new(:WHITESPACE, ' ', 0, 0)
9
+ end
@@ -0,0 +1,249 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe 'manifest_whitespace_arrows_single_space_after' do
6
+ let(:single_space_msg) { 'there should be a single space after an arrow' }
7
+
8
+ context 'with two spaces' do
9
+ let(:code) do
10
+ <<~EOF
11
+ class { 'example2':
12
+ param1 => 'value1',
13
+ }
14
+ EOF
15
+ end
16
+
17
+ context 'with fix disabled' do
18
+ it 'should detect a single problem' do
19
+ expect(problems).to have(1).problem
20
+ end
21
+
22
+ it 'should create a error' do
23
+ expect(problems).to contain_error(single_space_msg).on_line(2).in_column(12)
24
+ end
25
+ end
26
+
27
+ context 'with fix enabled' do
28
+ before do
29
+ PuppetLint.configuration.fix = true
30
+ end
31
+
32
+ after do
33
+ PuppetLint.configuration.fix = false
34
+ end
35
+
36
+ it 'should detect a single problem' do
37
+ expect(problems).to have(1).problem
38
+ end
39
+
40
+ it 'should fix the manifest' do
41
+ expect(problems).to contain_fixed(single_space_msg)
42
+ end
43
+
44
+ it 'should fix the space' do
45
+ expect(manifest).to eq(
46
+ <<~EOF,
47
+ class { 'example2':
48
+ param1 => 'value1',
49
+ }
50
+ EOF
51
+ )
52
+ end
53
+ end
54
+ end
55
+
56
+ context 'with no spaces' do
57
+ let(:code) do
58
+ <<~EOF
59
+ class { 'example2':
60
+ param1 =>'value1',
61
+ }
62
+ EOF
63
+ end
64
+
65
+ context 'with fix disabled' do
66
+ it 'should detect a single problem' do
67
+ expect(problems).to have(1).problem
68
+ end
69
+
70
+ it 'should create a error' do
71
+ expect(problems).to contain_error(single_space_msg).on_line(2).in_column(12)
72
+ end
73
+ end
74
+
75
+ context 'with fix enabled' do
76
+ before do
77
+ PuppetLint.configuration.fix = true
78
+ end
79
+
80
+ after do
81
+ PuppetLint.configuration.fix = false
82
+ end
83
+
84
+ it 'should detect a single problem' do
85
+ expect(problems).to have(1).problem
86
+ end
87
+
88
+ it 'should fix the manifest' do
89
+ expect(problems).to contain_fixed(single_space_msg)
90
+ end
91
+
92
+ it 'should fix the space' do
93
+ expect(manifest).to eq(
94
+ <<~EOF,
95
+ class { 'example2':
96
+ param1 => 'value1',
97
+ }
98
+ EOF
99
+ )
100
+ end
101
+ end
102
+ end
103
+
104
+ context 'with string as space' do
105
+ let(:code) do
106
+ <<~EOF
107
+ class { 'example2':
108
+ param1 =>' ',
109
+ }
110
+ EOF
111
+ end
112
+
113
+ context 'with fix disabled' do
114
+ it 'should detect a single problem' do
115
+ expect(problems).to have(1).problem
116
+ end
117
+
118
+ it 'should create a error' do
119
+ expect(problems).to contain_error(single_space_msg).on_line(2).in_column(12)
120
+ end
121
+ end
122
+
123
+ context 'with fix enabled' do
124
+ before do
125
+ PuppetLint.configuration.fix = true
126
+ end
127
+
128
+ after do
129
+ PuppetLint.configuration.fix = false
130
+ end
131
+
132
+ it 'should detect a single problem' do
133
+ expect(problems).to have(1).problem
134
+ end
135
+
136
+ it 'should fix the manifest' do
137
+ expect(problems).to contain_fixed(single_space_msg)
138
+ end
139
+
140
+ it 'should fix the space' do
141
+ expect(manifest).to eq(
142
+ <<~EOF,
143
+ class { 'example2':
144
+ param1 => ' ',
145
+ }
146
+ EOF
147
+ )
148
+ end
149
+ end
150
+ end
151
+
152
+ context 'many resources' do
153
+ let(:code) do
154
+ <<~EOF
155
+ class { 'example2':
156
+ param1 =>'value1',
157
+ param2 => 'value2',
158
+ param3 => 'value3',
159
+ param4 => 'value4',
160
+ }
161
+ EOF
162
+ end
163
+
164
+ context 'with fix disabled' do
165
+ it 'should detect a single problem' do
166
+ expect(problems).to have(3).problems
167
+ end
168
+
169
+ it 'should create a error' do
170
+ expect(problems).to contain_error(single_space_msg).on_line(2).in_column(12)
171
+ expect(problems).to contain_error(single_space_msg).on_line(4).in_column(12)
172
+ expect(problems).to contain_error(single_space_msg).on_line(5).in_column(12)
173
+ end
174
+ end
175
+
176
+ context 'with fix enabled' do
177
+ before do
178
+ PuppetLint.configuration.fix = true
179
+ end
180
+
181
+ after do
182
+ PuppetLint.configuration.fix = false
183
+ end
184
+
185
+ it 'should detect a single problem' do
186
+ expect(problems).to have(3).problem
187
+ end
188
+
189
+ it 'should fix the manifest' do
190
+ expect(problems).to contain_fixed(single_space_msg)
191
+ end
192
+
193
+ it 'should fix the space' do
194
+ expect(manifest).to eq(
195
+ <<~EOF,
196
+ class { 'example2':
197
+ param1 => 'value1',
198
+ param2 => 'value2',
199
+ param3 => 'value3',
200
+ param4 => 'value4',
201
+ }
202
+ EOF
203
+ )
204
+ end
205
+ end
206
+ end
207
+
208
+ context 'valid cases' do
209
+ context 'correct arrow' do
210
+ let(:code) do
211
+ <<~EOF
212
+ class { 'example2':
213
+ param1 => 'value1',
214
+ }
215
+ EOF
216
+ end
217
+
218
+ it 'should detect a no problem' do
219
+ expect(problems).to have(0).problems
220
+ end
221
+ end
222
+
223
+ context 'in a string' do
224
+ let(:code) do
225
+ <<~EOF
226
+ "param1 => 'value1'",
227
+ EOF
228
+ end
229
+
230
+ it 'should detect a no problem' do
231
+ expect(problems).to have(0).problems
232
+ end
233
+ end
234
+
235
+ context 'in a heredoc' do
236
+ let(:code) do
237
+ <<~EOF
238
+ $data = @("DATA"/L)
239
+ param1 => 'value1',
240
+ | DATA
241
+ EOF
242
+ end
243
+
244
+ it 'should detect a no problem' do
245
+ expect(problems).to have(0).problems
246
+ end
247
+ end
248
+ end
249
+ end