puppet-lint-param_comment-check 0.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.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +41 -0
- data/lib/puppet-lint/plugins/check_param_comment.rb +154 -0
- data/lib/puppet-lint-param_comment-check/param_comments.rb +133 -0
- data/lib/puppet-lint-param_comment-check/param_workflow.rb +28 -0
- data/spec/puppet-lint/plugins/check_param_comment_spec.rb +288 -0
- data/spec/spec_helper.rb +9 -0
- metadata +165 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 001c0354a4c8e6d8d852d3f07122cf01f80603b17aaa8eebe9954ea4566704b6
|
4
|
+
data.tar.gz: 2502c094ecbbebca5c3986ec25f8f1a2563b55cf1d430d8abe575e9d637abfe0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 60175714324271adf92951be259db9ad0dc292c35681784058d7f8b1e5dbec2ecb01c589186c89938aaec72ca62ccef50c7c5d96a2a67c33f08420c5f5f978a4
|
7
|
+
data.tar.gz: 5a15fc0ea2b159d6d41470b0f74267d1a74d518f840da822c1e94544b258c78314f3a36e491c9d885e05ca2b68d6da00495305f20b6c39fba379901b263355d7
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2022 DO! DevOps
|
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,41 @@
|
|
1
|
+
# Puppet lint param check
|
2
|
+
|
3
|
+
This is an extensive, opinionated check for valid parameter comments. It checks if the following criteria are matched:
|
4
|
+
|
5
|
+
- All parameters are documented
|
6
|
+
- @param-tags are separated from another by one empty line
|
7
|
+
- The description of a @param tag is always indented in the next line
|
8
|
+
- The @option comments directly follow the corresponding hash @param tag without a separator
|
9
|
+
- @param tags are sorted like the parameters they document
|
10
|
+
|
11
|
+
```
|
12
|
+
# @param mandatory
|
13
|
+
# A mandatory parameter
|
14
|
+
# @option mandatory [String] hashkey
|
15
|
+
# A key of the hash "mandatory" named "hashkey".
|
16
|
+
#
|
17
|
+
# @param withdefault
|
18
|
+
# A parameter with a default value
|
19
|
+
#
|
20
|
+
# @param optional
|
21
|
+
# An optional parameter
|
22
|
+
|
23
|
+
class my_class {
|
24
|
+
Hash $mandatory,
|
25
|
+
Boolean $withdefault = false,
|
26
|
+
Optional[String] $optional = undef,
|
27
|
+
```
|
28
|
+
|
29
|
+
## Development
|
30
|
+
|
31
|
+
This check uses a finite state machine to work through the expected list of parameters.
|
32
|
+
|
33
|
+
The workflow used by the fsm can be visualized like this:
|
34
|
+
|
35
|
+

|
36
|
+
|
37
|
+
## Usage
|
38
|
+
|
39
|
+
To use the plugin, add the following line to the Gemfile:
|
40
|
+
|
41
|
+
gem 'puppet-lint-summary_param-check'
|
@@ -0,0 +1,154 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../puppet-lint-param_comment-check/param_workflow'
|
4
|
+
require_relative '../../puppet-lint-param_comment-check/param_comments'
|
5
|
+
|
6
|
+
# The empty data of a parameter
|
7
|
+
EMPTY_PARAM = {
|
8
|
+
name: '',
|
9
|
+
type: '',
|
10
|
+
has_default: false,
|
11
|
+
default: ''
|
12
|
+
}.freeze
|
13
|
+
|
14
|
+
# Find the header comments for a class or a defined type
|
15
|
+
#
|
16
|
+
# @param tokens The list of all tokens
|
17
|
+
# @param token_start The index of the token to start from upwards
|
18
|
+
# @return The head comments
|
19
|
+
def get_comments(tokens, token_start)
|
20
|
+
comments = []
|
21
|
+
token_pointer = token_start
|
22
|
+
while token_pointer >= 0
|
23
|
+
comments.append(tokens[token_pointer]) if tokens[token_pointer].type == :COMMENT
|
24
|
+
token_pointer -= 1
|
25
|
+
end
|
26
|
+
comments.reverse
|
27
|
+
end
|
28
|
+
|
29
|
+
# Analyze a parameter token
|
30
|
+
#
|
31
|
+
# @param token The token to analyze
|
32
|
+
# @param current_param the data object for the currently analyzed parameter
|
33
|
+
def analyze_param_token(token, current_param)
|
34
|
+
# noinspection RubyCaseWithoutElseBlockInspection
|
35
|
+
case token.type
|
36
|
+
when :VARIABLE
|
37
|
+
current_param[:name] = token.value
|
38
|
+
when :CLASSREF
|
39
|
+
current_param[:type] = token.value
|
40
|
+
when :EQUALS
|
41
|
+
current_param[:has_default] = true
|
42
|
+
current_param[:default] = token.next_token.value
|
43
|
+
end
|
44
|
+
current_param
|
45
|
+
end
|
46
|
+
|
47
|
+
# Analyze the parameters of a class or a defined type
|
48
|
+
#
|
49
|
+
# @param param_tokens The parameter tokens to analyze
|
50
|
+
def analyze_params(param_tokens)
|
51
|
+
params = []
|
52
|
+
current_param = EMPTY_PARAM.dup
|
53
|
+
param_tokens.reject { |token| %i[WHITESPACE NEWLINE].include? token.type }.each do |token|
|
54
|
+
current_param = analyze_param_token(token, current_param) unless token.type == :COMMA
|
55
|
+
if token.type == :COMMA
|
56
|
+
params.append(current_param)
|
57
|
+
current_param = EMPTY_PARAM.dup
|
58
|
+
end
|
59
|
+
end
|
60
|
+
params
|
61
|
+
end
|
62
|
+
|
63
|
+
# Find, which parameters in the long list are missing in the short list and return their names
|
64
|
+
#
|
65
|
+
# @param long_list The list containing all parameters
|
66
|
+
# @param short_list The list missing some parameters
|
67
|
+
# @return The names of the missing parameters
|
68
|
+
def get_missing_parameters(long_list, short_list)
|
69
|
+
long_list.reject { |param| short_list.any? { |short_list_param| short_list_param[:name] == param[:name] } }
|
70
|
+
.map { |param| param[:name] }
|
71
|
+
end
|
72
|
+
|
73
|
+
PuppetLint.new_check(:param_comment) do # rubocop:disable Metrics/BlockLength
|
74
|
+
def initialize
|
75
|
+
@comment_engine = ParamComments.new
|
76
|
+
# noinspection RubySuperCallWithoutSuperclassInspection
|
77
|
+
super
|
78
|
+
end
|
79
|
+
|
80
|
+
# A shortcut to add a new Puppetlint warning
|
81
|
+
def warn(message, line = 1, column = 1)
|
82
|
+
notify :warning, { message: message, line: line, column: column }
|
83
|
+
false
|
84
|
+
end
|
85
|
+
|
86
|
+
# Check if the comments are formatted correctly by piping them through the fsm workflow
|
87
|
+
def check_comment_format(comments)
|
88
|
+
begin
|
89
|
+
@comment_engine.process(comments)
|
90
|
+
rescue InvalidCommentForState, OptionDoesntMatchHash => e
|
91
|
+
return warn(e.message, e.comment.line, e.comment.column)
|
92
|
+
end
|
93
|
+
true
|
94
|
+
end
|
95
|
+
|
96
|
+
# Check the header lines of parameters or hash options
|
97
|
+
def check_param_option_headers(comments)
|
98
|
+
comments.each do |comment|
|
99
|
+
next unless comment.value.match?(/@param/) || comment.value.match?(/@option/)
|
100
|
+
next if comment.value.strip.match?(REGEXP_PARAM_HEADER) || comment.value.strip.match?(REGEXP_OPTION_HEADER)
|
101
|
+
|
102
|
+
return warn('Invalid param or hash option header', comment.line, comment.column)
|
103
|
+
end
|
104
|
+
true
|
105
|
+
end
|
106
|
+
|
107
|
+
# Check comments
|
108
|
+
def check_comments(comments)
|
109
|
+
return false unless check_param_option_headers(comments)
|
110
|
+
return false unless check_comment_format(comments)
|
111
|
+
|
112
|
+
true
|
113
|
+
end
|
114
|
+
|
115
|
+
# Check if parameters and parameter comments match
|
116
|
+
def check_parameters_count(params)
|
117
|
+
param_comments = @comment_engine.params
|
118
|
+
if params.length > param_comments.length
|
119
|
+
missing_params = get_missing_parameters(params, param_comments)
|
120
|
+
return warn("Missing parameter documentation for #{missing_params.join(',')}")
|
121
|
+
elsif params.length < param_comments.length
|
122
|
+
missing_params = get_missing_parameters(param_comments, params)
|
123
|
+
return warn("Documented but unused parameters found: #{missing_params.join(',')}")
|
124
|
+
end
|
125
|
+
true
|
126
|
+
end
|
127
|
+
|
128
|
+
# Check if the parameter comments are ordered like the parameters
|
129
|
+
def check_comment_order(params)
|
130
|
+
param_comments = @comment_engine.params
|
131
|
+
param_comments.each_with_index do |param, index|
|
132
|
+
return false unless param[:name] == params[index][:name]
|
133
|
+
end
|
134
|
+
true
|
135
|
+
end
|
136
|
+
|
137
|
+
# Check class or defined type indexes
|
138
|
+
def check_indexes(indexes)
|
139
|
+
indexes.each do |index|
|
140
|
+
comments = get_comments(tokens, index[:start])
|
141
|
+
params = analyze_params(index[:param_tokens])
|
142
|
+
return false unless check_comments(comments)
|
143
|
+
return false unless check_parameters_count(params)
|
144
|
+
return warn('Parameters sorted wrong') unless check_comment_order(params)
|
145
|
+
end
|
146
|
+
true
|
147
|
+
end
|
148
|
+
|
149
|
+
# Run the check
|
150
|
+
def check
|
151
|
+
return unless check_indexes(class_indexes)
|
152
|
+
return unless check_indexes(defined_type_indexes)
|
153
|
+
end
|
154
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The empty data of a parameter
|
4
|
+
EMPTY_PARAM_COMMENT = {
|
5
|
+
name: '',
|
6
|
+
description: '',
|
7
|
+
options: []
|
8
|
+
}.freeze
|
9
|
+
|
10
|
+
# The empty data of a hash option
|
11
|
+
EMPTY_OPTION_COMMENT = {
|
12
|
+
name: '',
|
13
|
+
type: '',
|
14
|
+
description: ''
|
15
|
+
}.freeze
|
16
|
+
|
17
|
+
# A regular expression describing a parameter header
|
18
|
+
REGEXP_PARAM_HEADER = /^@param (?<name>[^ ]+)$/.freeze
|
19
|
+
|
20
|
+
# A regular expression describing a hash option header
|
21
|
+
REGEXP_OPTION_HEADER = /^@option (?<hash_name>[^ ]+) \[(?<type>[^\]]+)\] :(?<name>[^ ]+)$/.freeze
|
22
|
+
|
23
|
+
# Comment received in an invalid state
|
24
|
+
class InvalidCommentForState < StandardError
|
25
|
+
def initialize(comment, state)
|
26
|
+
@comment = comment
|
27
|
+
@state = state
|
28
|
+
super "Invalid state #{@state} for comment #{@comment.value.strip}"
|
29
|
+
end
|
30
|
+
|
31
|
+
attr_reader :comment
|
32
|
+
end
|
33
|
+
|
34
|
+
# Unexpected comment found
|
35
|
+
class UnexpectedComment < StandardError
|
36
|
+
def initialize(comment)
|
37
|
+
@comment = comment
|
38
|
+
super "Unexpected comment #{@comment.value}"
|
39
|
+
end
|
40
|
+
|
41
|
+
attr_reader :comment
|
42
|
+
end
|
43
|
+
|
44
|
+
# The hash referenced in an option doesn't match the current parameter
|
45
|
+
class OptionDoesntMatchHash < StandardError
|
46
|
+
def initialize(comment)
|
47
|
+
@comment = comment
|
48
|
+
super "Option references wrong hash #{@comment.value.strip}"
|
49
|
+
end
|
50
|
+
|
51
|
+
attr_reader :comment
|
52
|
+
end
|
53
|
+
|
54
|
+
# A helper to analyze parameter comments using the ParamWorkflow fsm
|
55
|
+
class ParamComments
|
56
|
+
def initialize
|
57
|
+
@workflow = ParamWorkflow.new(self)
|
58
|
+
|
59
|
+
@current_param = nil
|
60
|
+
@current_option = nil
|
61
|
+
@in_option = false
|
62
|
+
@params_have_started = false
|
63
|
+
@params = []
|
64
|
+
end
|
65
|
+
|
66
|
+
# Walk through every comment and transition the workflow fsm accordingly
|
67
|
+
#
|
68
|
+
# @param comments A list of Comment tokens appearing before the class/defined type header
|
69
|
+
def process(comments) # rubocop:disable Metrics/MethodLength
|
70
|
+
@current_comment = PuppetLint::Lexer::Token.new(:COMMENT, '', 1, 1)
|
71
|
+
comments.each do |comment|
|
72
|
+
@current_comment = comment
|
73
|
+
# noinspection RubyCaseWithoutElseBlockInspection
|
74
|
+
case comment.value
|
75
|
+
when /@param/ # A parameter comment header
|
76
|
+
@workflow.got_header(comment)
|
77
|
+
when /@option/ # A hash option
|
78
|
+
@workflow.got_option_header(comment) if @params_have_started
|
79
|
+
when /^\s*$/ # An empty or whitespace-only comment, thus interpreted as a separator
|
80
|
+
@workflow.got_separator(comment) if @params_have_started
|
81
|
+
when / {2}[^ ]+/ # A description. Either for the parameter or a hash option
|
82
|
+
@workflow.got_description(comment) if @params_have_started && !@in_option
|
83
|
+
@workflow.got_option_description(comment) if @params_have_started && @in_option
|
84
|
+
end
|
85
|
+
end
|
86
|
+
@params.append(@current_param) unless @current_param.nil?
|
87
|
+
end
|
88
|
+
|
89
|
+
# Called before the got_header event. Interpret the parameter header comment
|
90
|
+
def got_header_trigger(_, comment)
|
91
|
+
@params_have_started = true
|
92
|
+
@current_param[:options].append(@current_option) if @in_option && !@current_option.nil?
|
93
|
+
@params.append(@current_param) unless @current_param.nil?
|
94
|
+
@current_param = EMPTY_PARAM_COMMENT.dup
|
95
|
+
@current_option = nil
|
96
|
+
@in_option = false
|
97
|
+
comment.value.strip.match(REGEXP_PARAM_HEADER) do |match|
|
98
|
+
@current_param[:name] = match.named_captures['name'].strip
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Called before either the got_description or get_option_description event. Add a description to the
|
103
|
+
# current parameter or hash option
|
104
|
+
def got_description_trigger(_, comment)
|
105
|
+
return unless @params_have_started
|
106
|
+
|
107
|
+
@current_option[:description] += comment.value.strip if @in_option
|
108
|
+
@current_param[:description] += comment.value.strip unless @in_option
|
109
|
+
end
|
110
|
+
|
111
|
+
# Called before the got_option_header event. Interpret a hash option comment
|
112
|
+
def got_option_header_trigger(_, comment) # rubocop:disable Metrics/AbcSize
|
113
|
+
return unless @params_have_started
|
114
|
+
|
115
|
+
@current_param[:options].append(@current_option) if @in_option && !@current_option.nil?
|
116
|
+
@in_option = true
|
117
|
+
@current_option = EMPTY_OPTION_COMMENT.dup
|
118
|
+
comment.value.strip.match(REGEXP_OPTION_HEADER) do |match|
|
119
|
+
raise OptionDoesntMatchHash, comment unless match.named_captures['hash_name'] == @current_param[:name]
|
120
|
+
|
121
|
+
@current_option[:name] = match.named_captures['name']
|
122
|
+
@current_option[:type] = match.named_captures['type']
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# Called when an invalid state transition would happen
|
127
|
+
def invalid_state
|
128
|
+
raise InvalidCommentForState.new(@current_comment, @workflow.current)
|
129
|
+
end
|
130
|
+
|
131
|
+
# The list of analyzed parameters in the comments
|
132
|
+
attr_reader :params
|
133
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'finite_machine'
|
4
|
+
|
5
|
+
# A finite state machine working through the expected parameter comments
|
6
|
+
class ParamWorkflow < FiniteMachine::Definition
|
7
|
+
initial :start
|
8
|
+
|
9
|
+
event :got_header, from: :start, to: :awaiting_description
|
10
|
+
event :got_header, from: :awaiting_header, to: :awaiting_description
|
11
|
+
event :got_description, from: :awaiting_description, to: :awaiting_separator
|
12
|
+
event :got_separator, from: :awaiting_separator, to: :awaiting_header
|
13
|
+
|
14
|
+
# handling options
|
15
|
+
event :got_option_header, from: :awaiting_separator, to: :awaiting_option_description
|
16
|
+
event :got_option_description, from: :awaiting_option_description, to: :awaiting_separator
|
17
|
+
|
18
|
+
# for separators inside descriptions
|
19
|
+
event :got_description, from: :awaiting_header, to: :awaiting_separator
|
20
|
+
event :got_option_description, from: :awaiting_separator, to: :awaiting_separator
|
21
|
+
|
22
|
+
on_before(:got_header) { |event, comment| target.got_header_trigger(event, comment) }
|
23
|
+
on_before(:got_description) { |event, comment| target.got_description_trigger(event, comment) }
|
24
|
+
on_before(:got_option_description) { |event, comment| target.got_description_trigger(event, comment) }
|
25
|
+
on_before(:got_option_header) { |event, comment| target.got_option_header_trigger(event, comment) }
|
26
|
+
|
27
|
+
handle FiniteMachine::InvalidStateError, with: -> { target.invalid_state }
|
28
|
+
end
|
@@ -0,0 +1,288 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe 'param_comment' do
|
6
|
+
context 'valid code' do
|
7
|
+
let(:code) do
|
8
|
+
<<~CODE
|
9
|
+
# @summary
|
10
|
+
# some class
|
11
|
+
#
|
12
|
+
# @param mandatory
|
13
|
+
# A mandatory parameter
|
14
|
+
#
|
15
|
+
# @param withdefault
|
16
|
+
# A parameter with a default value
|
17
|
+
#
|
18
|
+
# A two paragraph description
|
19
|
+
#
|
20
|
+
# @param optional
|
21
|
+
# An optional parameter
|
22
|
+
|
23
|
+
class my_class (
|
24
|
+
String $mandatory,
|
25
|
+
Boolean $withdefault = false,
|
26
|
+
Optional[String] $optional = undef,
|
27
|
+
) {}
|
28
|
+
CODE
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should not detect any problems' do
|
32
|
+
expect(problems).to have(0).problems
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'code with missing parameter comment' do
|
37
|
+
let(:code) do
|
38
|
+
<<~CODE
|
39
|
+
# @param mandatory
|
40
|
+
# A mandatory parameter
|
41
|
+
#
|
42
|
+
# @param withdefault
|
43
|
+
# A parameter with a default value
|
44
|
+
|
45
|
+
class my_class (
|
46
|
+
String $mandatory,
|
47
|
+
Boolean $withdefault = false,
|
48
|
+
Optional[String] $optional = undef,
|
49
|
+
) {}
|
50
|
+
CODE
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should detect exactly one problem' do
|
54
|
+
expect(problems).to have(1).problems
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'should create a warning' do
|
58
|
+
expect(problems).to contain_warning('Missing parameter documentation for optional').on_line(1).in_column(1)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context 'code with additional parameter comment' do
|
63
|
+
let(:code) do
|
64
|
+
<<~CODE
|
65
|
+
# @param mandatory
|
66
|
+
# A mandatory parameter
|
67
|
+
#
|
68
|
+
# @param withdefault
|
69
|
+
# A parameter with a default value
|
70
|
+
|
71
|
+
class my_class (
|
72
|
+
String $mandatory,
|
73
|
+
) {}
|
74
|
+
CODE
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'should detect exactly one problem' do
|
78
|
+
expect(problems).to have(1).problems
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'should create a warning' do
|
82
|
+
expect(problems).to contain_warning('Documented but unused parameters found: withdefault').on_line(1).in_column(1)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'code with wrongly sorted parameter comments' do
|
87
|
+
let(:code) do
|
88
|
+
<<~CODE
|
89
|
+
# @param withdefault
|
90
|
+
# A parameter with a default value
|
91
|
+
#
|
92
|
+
# @param mandatory
|
93
|
+
# A mandatory parameter
|
94
|
+
#
|
95
|
+
# @param optional
|
96
|
+
# An optional parameter
|
97
|
+
|
98
|
+
class my_class (
|
99
|
+
String $mandatory,
|
100
|
+
Boolean $withdefault = false,
|
101
|
+
Optional[String] $optional = undef,
|
102
|
+
) {}
|
103
|
+
CODE
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'should detect exactly one problem' do
|
107
|
+
expect(problems).to have(1).problems
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'should create a warning' do
|
111
|
+
expect(problems).to contain_warning('Parameters sorted wrong').on_line(1).in_column(1)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context 'code with missing separator comment' do
|
116
|
+
let(:code) do
|
117
|
+
<<~CODE
|
118
|
+
# @param mandatory
|
119
|
+
# A mandatory parameter
|
120
|
+
# @param withdefault
|
121
|
+
# A parameter with a default value
|
122
|
+
#
|
123
|
+
# @param optional
|
124
|
+
# An optional parameter
|
125
|
+
|
126
|
+
class my_class (
|
127
|
+
String $mandatory,
|
128
|
+
Boolean $withdefault = false,
|
129
|
+
Optional[String] $optional = undef,
|
130
|
+
) {}
|
131
|
+
CODE
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'should detect exactly one problem' do
|
135
|
+
expect(problems).to have(1).problems
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'should create a warning' do
|
139
|
+
expect(problems).to contain_warning('Invalid state awaiting_separator for comment @param withdefault')
|
140
|
+
.on_line(3)
|
141
|
+
.in_column(1)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
context 'code with description in header' do
|
146
|
+
let(:code) do
|
147
|
+
<<~CODE
|
148
|
+
# @param mandatory A mandatory parameter
|
149
|
+
class my_class (
|
150
|
+
String $mandatory,
|
151
|
+
) {}
|
152
|
+
CODE
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'should detect exactly one problem' do
|
156
|
+
expect(problems).to have(1).problems
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'should create a warning' do
|
160
|
+
expect(problems).to contain_warning('Invalid param or hash option header')
|
161
|
+
.on_line(1)
|
162
|
+
.in_column(1)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
context 'code with correct hash options' do
|
167
|
+
let(:code) do
|
168
|
+
<<~CODE
|
169
|
+
# @param mandatory
|
170
|
+
# A mandatory parameter
|
171
|
+
# @option mandatory [Boolean] :some_option
|
172
|
+
# An option
|
173
|
+
class my_class (
|
174
|
+
Hash $mandatory,
|
175
|
+
) {}
|
176
|
+
CODE
|
177
|
+
end
|
178
|
+
|
179
|
+
it 'should detect no problem' do
|
180
|
+
expect(problems).to have(0).problems
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
context 'code with incorrect hash name' do
|
185
|
+
let(:code) do
|
186
|
+
<<~CODE
|
187
|
+
# @param mandatory
|
188
|
+
# A mandatory parameter
|
189
|
+
# @option mandatry [Boolean] :some_option
|
190
|
+
# An option
|
191
|
+
class my_class (
|
192
|
+
Hash $mandatory,
|
193
|
+
) {}
|
194
|
+
CODE
|
195
|
+
end
|
196
|
+
|
197
|
+
it 'should detect exactly one problem' do
|
198
|
+
expect(problems).to have(1).problems
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'should create a warning' do
|
202
|
+
expect(problems).to contain_warning('Option references wrong hash @option mandatry [Boolean] :some_option')
|
203
|
+
.on_line(3)
|
204
|
+
.in_column(1)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
context 'code with a separator between param and option' do
|
209
|
+
let(:code) do
|
210
|
+
<<~CODE
|
211
|
+
# @param mandatory
|
212
|
+
# A mandatory parameter
|
213
|
+
#
|
214
|
+
# @option mandatory [Boolean] :some_option
|
215
|
+
# An option
|
216
|
+
class my_class (
|
217
|
+
Hash $mandatory,
|
218
|
+
) {}
|
219
|
+
CODE
|
220
|
+
end
|
221
|
+
|
222
|
+
it 'should detect exactly one problem' do
|
223
|
+
expect(problems).to have(1).problems
|
224
|
+
end
|
225
|
+
|
226
|
+
it 'should create a warning' do
|
227
|
+
expect(problems).to contain_warning(
|
228
|
+
'Invalid state awaiting_header for comment @option mandatory [Boolean] :some_option'
|
229
|
+
)
|
230
|
+
.on_line(4)
|
231
|
+
.in_column(1)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
context 'code with option description on the same line' do
|
236
|
+
let(:code) do
|
237
|
+
<<~CODE
|
238
|
+
# @param mandatory
|
239
|
+
# A mandatory parameter
|
240
|
+
# @option mandatory [Boolean] :some_option An option
|
241
|
+
class my_class (
|
242
|
+
Hash $mandatory,
|
243
|
+
) {}
|
244
|
+
CODE
|
245
|
+
end
|
246
|
+
|
247
|
+
it 'should detect exactly one problem' do
|
248
|
+
expect(problems).to have(1).problems
|
249
|
+
end
|
250
|
+
|
251
|
+
it 'should create a warning' do
|
252
|
+
expect(problems).to contain_warning(
|
253
|
+
'Invalid param or hash option header'
|
254
|
+
)
|
255
|
+
.on_line(3)
|
256
|
+
.in_column(1)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
context 'code with no separator between hash option and next parameter' do
|
261
|
+
let(:code) do
|
262
|
+
<<~CODE
|
263
|
+
# @param mandatory
|
264
|
+
# A mandatory parameter
|
265
|
+
# @option mandatory [Boolean] :some_option
|
266
|
+
# An option
|
267
|
+
# @param second
|
268
|
+
# Something else
|
269
|
+
class my_class (
|
270
|
+
Hash $mandatory,
|
271
|
+
String $second,
|
272
|
+
) {}
|
273
|
+
CODE
|
274
|
+
end
|
275
|
+
|
276
|
+
it 'should detect exactly one problem' do
|
277
|
+
expect(problems).to have(1).problems
|
278
|
+
end
|
279
|
+
|
280
|
+
it 'should create a warning' do
|
281
|
+
expect(problems).to contain_warning(
|
282
|
+
'Invalid state awaiting_separator for comment @param second'
|
283
|
+
)
|
284
|
+
.on_line(5)
|
285
|
+
.in_column(1)
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: puppet-lint-param_comment-check
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Dennis Ploeger
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-05-30 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: puppet-lint
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: finite_machine
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec-its
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec-collection_matchers
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rubocop
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: simplecov
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
description: " A puppet-lint plugin to check that manifest files contain properly
|
126
|
+
formatted @param comments.\n"
|
127
|
+
email: develop@dieploegers.de
|
128
|
+
executables: []
|
129
|
+
extensions: []
|
130
|
+
extra_rdoc_files: []
|
131
|
+
files:
|
132
|
+
- LICENSE
|
133
|
+
- README.md
|
134
|
+
- lib/puppet-lint-param_comment-check/param_comments.rb
|
135
|
+
- lib/puppet-lint-param_comment-check/param_workflow.rb
|
136
|
+
- lib/puppet-lint/plugins/check_param_comment.rb
|
137
|
+
- spec/puppet-lint/plugins/check_param_comment_spec.rb
|
138
|
+
- spec/spec_helper.rb
|
139
|
+
homepage: https://github.com/dodevops/puppet-lint-param_comment-check
|
140
|
+
licenses:
|
141
|
+
- MIT
|
142
|
+
metadata: {}
|
143
|
+
post_install_message:
|
144
|
+
rdoc_options: []
|
145
|
+
require_paths:
|
146
|
+
- lib
|
147
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
148
|
+
requirements:
|
149
|
+
- - ">="
|
150
|
+
- !ruby/object:Gem::Version
|
151
|
+
version: '0'
|
152
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
153
|
+
requirements:
|
154
|
+
- - ">="
|
155
|
+
- !ruby/object:Gem::Version
|
156
|
+
version: '0'
|
157
|
+
requirements: []
|
158
|
+
rubygems_version: 3.0.3.1
|
159
|
+
signing_key:
|
160
|
+
specification_version: 4
|
161
|
+
summary: '["A puppet-lint plugin to check @param comments", " A puppet-lint plugin
|
162
|
+
to check that manifest files contain properly formatted @param comments.\n"]'
|
163
|
+
test_files:
|
164
|
+
- spec/spec_helper.rb
|
165
|
+
- spec/puppet-lint/plugins/check_param_comment_spec.rb
|