puppet-lint-params_not_optional_with_undef-check 1.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6e51d0fd67328a2d9e2eca7c0798c84900e18e4a7e23d51cbefc29bc7001a91b
4
+ data.tar.gz: 8d16522f020be9b8bf050bfc4f4acebbf11a36f8c498432fd57671c634d9e3c9
5
+ SHA512:
6
+ metadata.gz: 4a3afe7e9ab3f25ae81f14c9fba670e900ae7ca25289c1aae372909ef4697f6b0fba77d9af39a804874b5d3ab4199231a785f95b7ab3ba5ff3fca4317a565bdc
7
+ data.tar.gz: 8e78e50a68fc44cdd039fe226f5d9ef67dc46a3850f468f29536d334480016261ad3ae8c01826541fa7ab5829b00a65e17cf72e71d67ae5d6462d62ca5afbf50
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2021 Tim Meusel
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.
data/README.md ADDED
@@ -0,0 +1,106 @@
1
+ # puppet-lint-params_not_optional_with_undef-check
2
+
3
+ [![License](https://img.shields.io/github/license/voxpupuli/puppet-lint-params_not_optional_with_undef-check.svg)](https://github.com/voxpupuli/puppet-lint-params_not_optional_with_undef-check/blob/master/LICENSE)
4
+ [![Test](https://github.com/voxpupuli/puppet-lint-params_not_optional_with_undef-check/actions/workflows/test.yml/badge.svg)](https://github.com/voxpupuli/puppet-lint-params_not_optional_with_undef-check/actions/workflows/test.yml)
5
+ [![Release](https://github.com/voxpupuli/puppet-lint-params_not_optional_with_undef-check/actions/workflows/release.yml/badge.svg)](https://github.com/voxpupuli/puppet-lint-params_not_optional_with_undef-check/actions/workflows/release.yml)
6
+ [![RubyGem Version](https://img.shields.io/gem/v/puppet-lint-params_not_optional_with_undef-check.svg)](https://rubygems.org/gems/puppet-lint-params_not_optional_with_undef-check)
7
+ [![RubyGem Downloads](https://img.shields.io/gem/dt/puppet-lint-params_not_optional_with_undef-check.svg)](https://rubygems.org/gems/puppet-lint-params_not_optional_with_undef-check)
8
+ [![Donated by Tim Meusel](https://img.shields.io/badge/donated%20by-Tim%20%27bastelfreak%27%20Meusel-fb7047.svg)](#transfer-notice)
9
+
10
+ A puppet-lint plugin to check for parameters without Optional as type but undef
11
+ as value.
12
+
13
+ ## Installing
14
+
15
+ ### From the command line
16
+
17
+ ```shell
18
+ $ gem install puppet-lint-params_not_optional_with_undef-check
19
+ ```
20
+
21
+ ### In a Gemfile
22
+
23
+ ```ruby
24
+ gem 'puppet-lint-params_not_optional_with_undef-check', require: false
25
+ ```
26
+
27
+ ## Checks
28
+
29
+ ### Parameter assigned to the empty string
30
+
31
+ According the the Vox Pupuli best practices, a class parameter with the string
32
+ datatype should default to `undef` and not `''`, if it's optional. The
33
+ recommendations are documented at [voxpupuli.org](https://voxpupuli.org/docs/reviewing_pr/).
34
+
35
+ #### What you have done
36
+
37
+ ```puppet
38
+ class foo (
39
+ String $bar = undef,
40
+ ) {
41
+ # logic
42
+ }
43
+ ```
44
+
45
+ #### What you should have done
46
+
47
+ ```puppet
48
+ class foo (
49
+ Optional[String[1]] $bar = undef,
50
+ ) {
51
+ # logic
52
+ }
53
+ ```
54
+
55
+ or:
56
+
57
+ ```puppet
58
+ class foo (
59
+ String[1] $bar = 'value',
60
+ ) {
61
+ # logic
62
+ }
63
+ ```
64
+
65
+ #### Disabling the check
66
+
67
+ To disable this check, you can add `--no-params_not_optional_with_undef-check` to your puppet-lint command line.
68
+
69
+ ```shell
70
+ $ puppet-lint --no-empty_string_assignment-check path/to/file.pp
71
+ ```
72
+
73
+ Alternatively, if you’re calling puppet-lint via the Rake task, you should insert the following line to your `Rakefile`.
74
+
75
+ ```ruby
76
+ PuppetLint.configuration.send('params_not_optional_with_undef')
77
+ ```
78
+
79
+ You can also disable it inline:
80
+
81
+ ```puppet
82
+ class foo (
83
+ String $baz = '', # lint:ignore:params_empty_string_assignment
84
+ ) {
85
+ # awesome logic here
86
+ }
87
+ ```
88
+
89
+ ## Transfer Notice
90
+
91
+ This plugin was originally authored by [Tim 'bastelfreak' Meusel](https://github.com/bastelfreak).
92
+ The maintainer preferred that Vox Pupuli take ownership of the module for future improvement and maintenance.
93
+
94
+ ## License
95
+
96
+ This gem is licensed under the MIT license.
97
+
98
+ ## Release information
99
+
100
+ To make a new release, please do:
101
+ * update the version in the gemspec file
102
+ * Install gems with `bundle install --with release --path .vendor`
103
+ * generate the changelog with `bundle exec rake changelog`
104
+ * Check if the new version matches the closed issues/PRs in the changelog
105
+ * Create a PR with it
106
+ * After it got merged, push a tag. GitHub actions will do the actual release to rubygems and GitHub Packages
@@ -0,0 +1,129 @@
1
+ # this code is based on:
2
+ # https://github.com/voxpupuli/puppet-lint-empty_string-check
3
+ # https://github.com/voxpupuli/puppet-lint-optional_default-check
4
+
5
+ # frozen_string_literal: true
6
+
7
+ PuppetLint.new_check(:params_not_optional_with_undef) do
8
+ def check
9
+ class_indexes.concat(defined_type_indexes).each do |idx|
10
+ params = extract_params(idx)
11
+ params.each do |param|
12
+ default_value = extract_default_value_tokens(param)
13
+ type = extract_type_tokens(param)
14
+
15
+ next unless type.size.positive? && # The parameter has a type
16
+ type[0].type == :TYPE && type[0].value != 'Optional' && # That type is not Optional
17
+ default_value.size.positive? && # There is a default set
18
+ (default_value.map(&:type) & %i[DOT LPAREN]).none? && # That default doesn't contain a call to a function
19
+ default_value[0].type == :UNDEF && # It is undef
20
+
21
+ notify(
22
+ :warning,
23
+ message: 'Not optional parameter defaults to undef',
24
+ line: param.line,
25
+ column: param.column,
26
+ )
27
+ end
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ # Returns an array of parameter tokens
34
+ def extract_params(idx)
35
+ params = []
36
+ return params if idx[:param_tokens].nil?
37
+
38
+ e = idx[:param_tokens].each
39
+ begin
40
+ while (ptok = e.next)
41
+ next unless ptok.type == :VARIABLE
42
+
43
+ params << ptok
44
+ nesting = 0
45
+ # skip to the next parameter to avoid finding default values of variables
46
+ loop do
47
+ ptok = e.next
48
+ case ptok.type
49
+ when :LPAREN, :LBRACK
50
+ nesting += 1
51
+ when :RPAREN, :RBRACK
52
+ nesting -= 1
53
+ when :COMMA
54
+ break unless nesting.positive?
55
+ end
56
+ end
57
+ end
58
+ rescue StopIteration; end # rubocop:disable Lint/SuppressedException
59
+ params
60
+ end
61
+
62
+ # Returns array of tokens that cover the value that the parameter token has as its default
63
+ # Search forward to find value assigned to this parameter
64
+ # We want to find the thing after `=` and before `,`
65
+ def extract_default_value_tokens(ptok)
66
+ value_tokens = []
67
+ token = ptok.next_code_token
68
+ nesting = 0
69
+ while token
70
+ case token.type
71
+ when :LPAREN, :LBRACK
72
+ nesting += 1
73
+ when :RBRACK
74
+ nesting -= 1
75
+ when :RPAREN
76
+ nesting -= 1
77
+ if nesting.negative?
78
+ # This is the RPAREN at the end of the parameters. There wasn't a COMMA
79
+ last_token = token.prev_code_token
80
+ break
81
+ end
82
+ when :EQUALS
83
+ first_token = token.next_code_token
84
+ when :COMMA
85
+ unless nesting.positive?
86
+ last_token = token.prev_code_token
87
+ break
88
+ end
89
+ end
90
+ token = token.next_token
91
+ end
92
+ value_tokens = tokens[tokens.find_index(first_token)..tokens.find_index(last_token)] if first_token && last_token
93
+ value_tokens
94
+ end
95
+
96
+ # Returns an array of tokens that cover the data type of the parameter ptok
97
+ # Search backwards until we either bump into a comma (whilst not nested), or reach the opening LPAREN
98
+ def extract_type_tokens(ptok)
99
+ type_tokens = []
100
+ token = ptok.prev_code_token
101
+ nesting = 0
102
+ while token
103
+ case token.type
104
+ when :LBRACK
105
+ nesting += 1
106
+ when :LPAREN
107
+ nesting += 1
108
+ if nesting.positive?
109
+ # This is the LPAREN at the start of the parameter list
110
+ first_token = token.next_code_token
111
+ last_token = ptok.prev_code_token
112
+ break
113
+ end
114
+ when :RBRACK, :RPAREN
115
+ nesting -= 1
116
+ when :COMMA
117
+ if nesting.zero?
118
+ first_token = token.next_code_token
119
+ last_token = ptok.prev_code_token
120
+ break
121
+ end
122
+ end
123
+
124
+ token = token.prev_code_token
125
+ end
126
+ type_tokens = tokens[tokens.find_index(first_token)..tokens.find_index(last_token)] if first_token && last_token
127
+ type_tokens
128
+ end
129
+ end
@@ -0,0 +1,211 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'params_not_optional_with_undef' do
4
+ let(:msg) { 'Not optional parameter defaults to undef' }
5
+
6
+ context 'with fix disabled' do
7
+ context 'class definition without empty strings' do
8
+ let(:code) do
9
+ <<-EOS
10
+ class foo ( $bar = 'baz' ) { }
11
+ EOS
12
+ end
13
+
14
+ it 'does not detect any problems' do
15
+ expect(problems).to have(0).problems
16
+ end
17
+ end
18
+
19
+ context 'class definition with String type and undef value' do
20
+ let(:code) do
21
+ <<-EOS
22
+ class foo ( String[0] $bar = undef ) { }
23
+ EOS
24
+ end
25
+
26
+ it 'detects one problem' do
27
+ expect(problems).to have(1).problem
28
+ end
29
+ end
30
+
31
+ context 'class definition with empty strings and loose Variant datatype 1' do
32
+ let(:code) do
33
+ <<-EOS
34
+ class foo ( Variant[String[0], Integer] $bar = undef ) { }
35
+ EOS
36
+ end
37
+
38
+ it 'detects one problem' do
39
+ expect(problems).to have(1).problem
40
+ end
41
+ end
42
+
43
+ context 'class definition with empty strings and loose Variant datatype 2' do
44
+ let(:code) do
45
+ <<-EOS
46
+ class foo ( Variant[Any, Optional] $bar = undef ) { }
47
+ EOS
48
+ end
49
+
50
+ it 'detects one problem' do
51
+ expect(problems).to have(1).problem
52
+ end
53
+ end
54
+
55
+ context 'class internal variable without empty strings' do
56
+ let(:code) do
57
+ <<-EOS
58
+ class foo ( ) { $bar = 'baz' }
59
+ EOS
60
+ end
61
+
62
+ it 'does not detect any problems' do
63
+ expect(problems).to have(0).problems
64
+ end
65
+ end
66
+
67
+ context 'class definition with empty strings' do
68
+ let(:code) do
69
+ <<-EOS
70
+ class foo ( String $bar = undef ) { }
71
+ EOS
72
+ end
73
+
74
+ it 'detects a single problem' do
75
+ expect(problems).to have(1).problem
76
+ end
77
+
78
+ it 'creates a warning' do
79
+ expect(problems).to contain_warning(msg).on_line(1).in_column(28)
80
+ end
81
+ end
82
+
83
+ context 'class internal variable with empty strings' do
84
+ let(:code) do
85
+ <<-EOS
86
+ class foo ( ) { $bar = '' }
87
+ EOS
88
+ end
89
+
90
+ it 'does not detect any problems' do
91
+ expect(problems).to have(0).problem
92
+ end
93
+ end
94
+
95
+ context 'class definition with value and minimal string length at 0' do
96
+ let(:code) do
97
+ <<-EOS
98
+ class foo ( String[0] $var = 'public' ) { }
99
+ EOS
100
+ end
101
+
102
+ it 'does not detect any problems' do
103
+ expect(problems).to have(0).problem
104
+ end
105
+ end
106
+
107
+ context 'class definition with value and no minimal string length' do
108
+ let(:code) do
109
+ <<-EOS
110
+ class foo ( String $var = 'public' ) { }
111
+ EOS
112
+ end
113
+
114
+ it 'does not detect any problems' do
115
+ expect(problems).to have(0).problem
116
+ end
117
+ end
118
+
119
+ # this usecase was reported on slack
120
+ context 'class definition with value and string interpolation and values' do
121
+ let(:code) do
122
+ <<-EOS
123
+ class foo (
124
+ String $install_path = 'bla',
125
+ String $bin_path = "${install_path}/public",
126
+ ) {
127
+ # code
128
+ }
129
+ EOS
130
+ end
131
+
132
+ it 'does not detect any problems' do
133
+ expect(problems).to have(0).problem
134
+ end
135
+ end
136
+
137
+ context 'class definition with value and string interpolation and not all values' do
138
+ let(:code) do
139
+ <<-EOS
140
+ class foo (
141
+ String $install_path,
142
+ String $bin_path = "${install_path}/public",
143
+ ) {
144
+ # code
145
+ }
146
+ EOS
147
+ end
148
+
149
+ it 'does not detect any problems' do
150
+ expect(problems).to have(0).problem
151
+ end
152
+ end
153
+
154
+ context 'class definition with value and string interpolation and not all values and types' do
155
+ let(:code) do
156
+ <<-EOS
157
+ class foo (
158
+ String $install_path,
159
+ String[1] $bin_path = "${install_path}/public",
160
+ ) {
161
+ # code
162
+ }
163
+ EOS
164
+ end
165
+
166
+ it 'does not detect any problems' do
167
+ expect(problems).to have(0).problem
168
+ end
169
+ end
170
+
171
+ context 'class definition with value and string interpolation and not all values and types' do
172
+ let(:code) do
173
+ <<-EOS
174
+ define bar::foo (
175
+ String $install_path,
176
+ String[1] $bin_path = "${install_path}/public",
177
+ ) {
178
+ # code
179
+ }
180
+ EOS
181
+ end
182
+
183
+ it 'does not detect any problems' do
184
+ expect(problems).to have(0).problem
185
+ end
186
+ end
187
+
188
+ context 'class definition with value and string interpolation and not all values and types' do
189
+ let(:code) do
190
+ <<-EOS
191
+ define profiles::host_api::nexus::managed::gem_installation (
192
+ String $gem_source,
193
+ String $gem_name,
194
+ String $version,
195
+ String $user,
196
+ String $group,
197
+ String $install_path,
198
+ String[1] $bin_path = "${install_path}/bin",
199
+ Boolean $add_bin_stub = false,
200
+ ) {
201
+ # code
202
+ }
203
+ EOS
204
+ end
205
+
206
+ it 'does not detect any problems' do
207
+ expect(problems).to have(0).problem
208
+ end
209
+ end
210
+ end
211
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'puppet-lint'
4
+ require 'rspec/collection_matchers'
5
+
6
+ PuppetLint::Plugins.load_spec_helper
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: puppet-lint-params_not_optional_with_undef-check
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Vox Pupuli
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: puppet-lint
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '5.1'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '5.1'
26
+ - !ruby/object:Gem::Dependency
27
+ name: rspec-json_expectations
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '2.2'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '2.2'
40
+ email: voxpupuli@groups.io
41
+ executables: []
42
+ extensions: []
43
+ extra_rdoc_files: []
44
+ files:
45
+ - LICENSE
46
+ - README.md
47
+ - lib/puppet-lint/plugins/params_not_optional_with_undef.rb
48
+ - spec/puppet-lint/plugins/check_params_not_optional_with_undef/check_params_not_optional_with_undef_spec.rb
49
+ - spec/spec_helper.rb
50
+ homepage: https://github.com/voxpupuli/puppet-lint-params_not_optional_with_undef-check
51
+ licenses:
52
+ - MIT
53
+ metadata: {}
54
+ rdoc_options: []
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '3.2'
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ requirements: []
68
+ rubygems_version: 3.6.9
69
+ specification_version: 4
70
+ summary: A puppet-lint plugin to check for class parameters with undef as value but
71
+ not Optional type
72
+ test_files: []