puppet-lint-manifest_whitespace-check 0.0.1

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.
@@ -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