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,5 +1,7 @@
1
1
  # Public: Test the manifest tokens for any right-to-left (<-) chaining
2
2
  # operators and record a warning for each instance found.
3
+ #
4
+ # https://docs.puppet.com/guides/style_guide.html#chaining-arrow-syntax
3
5
  PuppetLint.new_check(:right_to_left_relationship) do
4
6
  def check
5
7
  tokens.select { |r| r.type == :OUT_EDGE }.each do |token|
@@ -15,6 +17,8 @@ end
15
17
  # Public: Test the manifest tokens for any classes or defined types that are
16
18
  # not in an appropriately named file for the autoloader to detect and record
17
19
  # an error of each instance found.
20
+ #
21
+ # https://docs.puppet.com/guides/style_guide.html#separate-files
18
22
  PuppetLint.new_check(:autoloader_layout) do
19
23
  def check
20
24
  unless fullpath.nil? || fullpath == ''
@@ -46,6 +50,8 @@ end
46
50
 
47
51
  # Public: Check the manifest tokens for any classes or defined types that
48
52
  # have a dash in their name and record an error for each instance found.
53
+ #
54
+ # No style guide reference
49
55
  PuppetLint.new_check(:names_containing_dash) do
50
56
  def check
51
57
  (class_indexes + defined_type_indexes).each do |class_idx|
@@ -68,6 +74,8 @@ end
68
74
 
69
75
  # Public: Check the manifest tokens for any classes that inherit a params
70
76
  # subclass and record a warning for each instance found.
77
+ #
78
+ # No style guide reference
71
79
  PuppetLint.new_check(:class_inherits_from_params_class) do
72
80
  def check
73
81
  class_indexes.each do |class_idx|
@@ -88,17 +96,25 @@ PuppetLint.configuration.send('disable_class_inherits_from_params_class')
88
96
  # Public: Test the manifest tokens for any parameterised classes or defined
89
97
  # types that take parameters and record a warning if there are any optional
90
98
  # parameters listed before required parameters.
99
+ #
100
+ # https://docs.puppet.com/guides/style_guide.html#display-order-of-parameters
91
101
  PuppetLint.new_check(:parameter_order) do
92
102
  def check
93
103
  (class_indexes + defined_type_indexes).each do |class_idx|
94
104
  unless class_idx[:param_tokens].nil?
95
105
  paren_stack = []
106
+ hash_or_array_stack = []
96
107
  class_idx[:param_tokens].each_with_index do |token, i|
97
108
  if token.type == :LPAREN
98
109
  paren_stack.push(true)
99
110
  elsif token.type == :RPAREN
100
111
  paren_stack.pop
112
+ elsif token.type == :LBRACE || token.type == :LBRACK
113
+ hash_or_array_stack.push(true)
114
+ elsif token.type == :RBRACE || token.type == :RBRACK
115
+ hash_or_array_stack.pop
101
116
  end
117
+ next if (! hash_or_array_stack.empty?)
102
118
  next unless paren_stack.empty?
103
119
 
104
120
  if token.type == :VARIABLE
@@ -124,6 +140,8 @@ end
124
140
 
125
141
  # Public: Test the manifest tokens for any classes that inherit across
126
142
  # namespaces and record a warning for each instance found.
143
+ #
144
+ # https://docs.puppet.com/guides/style_guide.html#class-inheritance
127
145
  PuppetLint.new_check(:inherits_across_namespaces) do
128
146
  def check
129
147
  class_indexes.each do |class_idx|
@@ -145,6 +163,8 @@ end
145
163
 
146
164
  # Public: Test the manifest tokens for any classes or defined types that are
147
165
  # defined inside another class.
166
+ #
167
+ # https://docs.puppet.com/guides/style_guide.html#nested-classes-or-defined-types
148
168
  PuppetLint.new_check(:nested_classes_or_defines) do
149
169
  TOKENS = Set[:CLASS, :DEFINE]
150
170
 
@@ -170,11 +190,63 @@ PuppetLint.new_check(:nested_classes_or_defines) do
170
190
  end
171
191
  end
172
192
 
193
+ # Public: Find and warn about module names with illegal uppercase characters.
194
+ #
195
+ # https://docs.puppet.com/puppet/latest/reference/modules_fundamentals.html#allowed-module-names
196
+ # Provides a fix. [puppet-lint #554]
197
+ PuppetLint.new_check(:names_containing_uppercase) do
198
+ def check
199
+ (class_indexes + defined_type_indexes).each do |class_idx|
200
+ if class_idx[:name_token].value =~ /[A-Z]/
201
+ if class_idx[:type] == :CLASS
202
+ obj_type = 'class'
203
+ else
204
+ obj_type = 'defined type'
205
+ end
206
+
207
+ notify :error, {
208
+ :message => "#{obj_type} '#{class_idx[:name_token].value}' contains illegal uppercase",
209
+ :line => class_idx[:name_token].line,
210
+ :column => class_idx[:name_token].column,
211
+ :token => class_idx[:name_token],
212
+ }
213
+ end
214
+ end
215
+ end
216
+
217
+ def fix(problem)
218
+ problem[:token].value.downcase!
219
+ end
220
+ end
221
+
222
+ # Public: Test that no code is outside of a class or define scope.
223
+ #
224
+ # No style guide reference
225
+ PuppetLint.new_check(:code_on_top_scope) do
226
+ def check
227
+ class_scope = (class_indexes + defined_type_indexes).map { |e| tokens[e[:start]..e[:end]] }.flatten
228
+ top_scope = tokens - class_scope
229
+
230
+ top_scope.each do |token|
231
+ unless formatting_tokens.include? token.type
232
+ notify :warning, {
233
+ :message => "code outside of class or define block - #{token.value}",
234
+ :line => token.line,
235
+ :column => token.column
236
+ }
237
+ end
238
+ end
239
+ end
240
+ end
241
+ PuppetLint.configuration.send("disable_code_on_top_scope")
242
+
173
243
  # Public: Test the manifest tokens for any variables that are referenced in
174
244
  # the manifest. If the variables are not fully qualified or one of the
175
245
  # variables automatically created in the scope, check that they have been
176
246
  # defined in the local scope and record a warning for each variable that has
177
247
  # not.
248
+ #
249
+ # https://docs.puppet.com/guides/style_guide.html#namespacing-variables
178
250
  PuppetLint.new_check(:variable_scope) do
179
251
  DEFAULT_SCOPE_VARS = Set[
180
252
  'name',
@@ -287,3 +359,4 @@ PuppetLint.new_check(:variable_scope) do
287
359
  end
288
360
  end
289
361
  end
362
+
@@ -1,5 +1,7 @@
1
1
  # Public: Check the manifest tokens for any comments started with slashes
2
2
  # (//) and record a warning for each instance found.
3
+ #
4
+ # https://docs.puppet.com/guides/style_guide.html#comments
3
5
  PuppetLint.new_check(:slash_comments) do
4
6
  def check
5
7
  tokens.select { |token|
@@ -21,6 +23,8 @@ end
21
23
 
22
24
  # Public: Check the manifest tokens for any comments encapsulated with
23
25
  # slash-asterisks (/* */) and record a warning for each instance found.
26
+ #
27
+ # https://docs.puppet.com/guides/style_guide.html#comments
24
28
  PuppetLint.new_check(:star_comments) do
25
29
  def check
26
30
  tokens.select { |token|
@@ -1,5 +1,7 @@
1
1
  # Public: Test the manifest tokens for any selectors embedded within resource
2
2
  # declarations and record a warning for each instance found.
3
+ #
4
+ # https://docs.puppet.com/guides/style_guide.html#keep-resource-declarations-simple
3
5
  PuppetLint.new_check(:selector_inside_resource) do
4
6
  def check
5
7
  resource_indexes.each do |resource|
@@ -24,6 +26,8 @@ end
24
26
 
25
27
  # Public: Test the manifest tokens for any case statements that do not
26
28
  # contain a "default" case and record a warning for each instance found.
29
+ #
30
+ # https://docs.puppet.com/guides/style_guide.html#defaults-for-case-statements-and-selectors
27
31
  PuppetLint.new_check(:case_without_default) do
28
32
  def check
29
33
  case_indexes = []
@@ -1,6 +1,8 @@
1
1
  # Public: Check the manifest tokens for any class or defined type that does not
2
2
  # have a comment directly above it (hopefully, explaining the usage of it) and
3
3
  # record a warning for each instance found.
4
+ #
5
+ # https://docs.puppet.com/guides/style_guide.html#public-and-private
4
6
  PuppetLint.new_check(:documentation) do
5
7
  COMMENT_TOKENS = Set[:COMMENT, :MLCOMMENT, :SLASH_COMMENT]
6
8
  WHITESPACE_TOKENS = Set[:WHITESPACE, :NEWLINE, :INDENT]
@@ -1,5 +1,7 @@
1
1
  # Public: Check the manifest for unquoted node names and record a warning for
2
2
  # each instance found.
3
+ #
4
+ # No style guide reference
3
5
  PuppetLint.new_check(:unquoted_node_name) do
4
6
  def check
5
7
  node_tokens = tokens.select { |token| token.type == :NODE }
@@ -1,5 +1,7 @@
1
1
  # Public: Check the manifest tokens for any resource titles / namevars that
2
2
  # are not quoted and record a warning for each instance found.
3
+ #
4
+ # https://docs.puppet.com/guides/style_guide.html#resource-names
3
5
  PuppetLint.new_check(:unquoted_resource_title) do
4
6
  def check
5
7
  title_tokens.each do |token|
@@ -22,6 +24,8 @@ end
22
24
  # Public: Check the tokens of each resource instance for an ensure parameter
23
25
  # and if found, check that it is the first parameter listed. If it is not
24
26
  # the first parameter, record a warning.
27
+ #
28
+ # https://docs.puppet.com/guides/style_guide.html#attribute-ordering
25
29
  PuppetLint.new_check(:ensure_first_param) do
26
30
  def check
27
31
  resource_indexes.each do |resource|
@@ -34,18 +38,85 @@ PuppetLint.new_check(:ensure_first_param) do
34
38
  if ensure_attr_index > 0
35
39
  ensure_token = resource[:param_tokens][ensure_attr_index]
36
40
  notify :warning, {
37
- :message => "ensure found on line but it's not the first attribute",
38
- :line => ensure_token.line,
39
- :column => ensure_token.column,
41
+ :message => "ensure found on line but it's not the first attribute",
42
+ :line => ensure_token.line,
43
+ :column => ensure_token.column,
44
+ :resource => resource,
40
45
  }
41
46
  end
42
47
  end
43
48
  end
44
49
  end
50
+ def fix(problem)
51
+ # We find the first and ensure paramss boundaries
52
+ first_param_name_token = nil
53
+ first_param_name_idx = nil
54
+ first_param_comma_token = nil
55
+ first_param_comma_idx = nil
56
+ ensure_param_name_token = nil
57
+ ensure_param_name_idx = nil
58
+ ensure_param_comma_token = nil
59
+ ensure_param_comma_idx = nil
60
+ tokens[(problem[:resource][:start])..(problem[:resource][:end])].each_with_index do |token, token_idx|
61
+ if first_param_name_token.nil?
62
+ if token.type == :NAME
63
+ first_param_name_token = token
64
+ first_param_name_idx = problem[:resource][:start] + token_idx
65
+ end
66
+ elsif first_param_comma_token.nil?
67
+ if token.type == :COMMA
68
+ first_param_comma_token = token
69
+ first_param_comma_idx = problem[:resource][:start] + token_idx
70
+ end
71
+ elsif ensure_param_name_token.nil?
72
+ if token.type == :NAME and token.value == 'ensure'
73
+ ensure_param_name_token = token
74
+ ensure_param_name_idx = problem[:resource][:start] + token_idx
75
+ end
76
+ elsif ensure_param_comma_token.nil?
77
+ if token.type == :COMMA or token.type == :SEMIC
78
+ ensure_param_comma_token = token
79
+ ensure_param_comma_idx = problem[:resource][:start] + token_idx
80
+ break
81
+ end
82
+ end
83
+ end
84
+ if first_param_name_token.nil? or first_param_comma_token.nil? or ensure_param_name_token.nil? or ensure_param_comma_token.nil?
85
+ raise PuppetLint::NoFix
86
+ end
87
+ # Flip params
88
+ prev_token = first_param_name_token.prev_token
89
+ first_param_name_token.prev_token = ensure_param_name_token.prev_token
90
+ ensure_param_name_token.prev_token = prev_token
91
+
92
+ prev_code_token = first_param_name_token.prev_code_token
93
+ first_param_name_token.prev_code_token = ensure_param_name_token.prev_code_token
94
+ ensure_param_name_token.prev_code_token = prev_code_token
95
+
96
+ next_token = first_param_comma_token.next_token
97
+ first_param_comma_token = ensure_param_comma_token.next_token
98
+ ensure_param_comma_token.next_token = next_token
99
+
100
+ next_code_token = first_param_comma_token.next_code_token
101
+ first_param_comma_code_token = ensure_param_comma_token.next_code_token
102
+ ensure_param_comma_token.next_code_token = next_code_token
103
+
104
+ # Update index
105
+ ensure_tmp = tokens.slice!(ensure_param_name_idx..ensure_param_comma_idx-1)
106
+ first_tmp = tokens.slice!(first_param_name_idx..first_param_comma_idx-1)
107
+ ensure_tmp.reverse_each do |item|
108
+ tokens.insert(first_param_name_idx, item)
109
+ end
110
+ first_tmp.reverse_each do |item|
111
+ tokens.insert(ensure_param_name_idx + ensure_tmp.length - first_tmp.length, item)
112
+ end
113
+ end
45
114
  end
46
115
 
47
116
  # Public: Check the tokens of each resource instance for any duplicate
48
117
  # parameters and record a warning for each instance found.
118
+ #
119
+ # No style guide reference
49
120
  PuppetLint.new_check(:duplicate_params) do
50
121
  def check
51
122
  resource_indexes.each do |resource|
@@ -83,6 +154,8 @@ end
83
154
  # Public: Check the tokens of each File resource instance for a mode
84
155
  # parameter and if found, record a warning if the value of that parameter is
85
156
  # not a quoted string.
157
+ #
158
+ # https://docs.puppet.com/guides/style_guide.html#file-modes
86
159
  PuppetLint.new_check(:unquoted_file_mode) do
87
160
  TOKEN_TYPES = Set[:NAME, :NUMBER]
88
161
 
@@ -113,6 +186,8 @@ end
113
186
  # Public: Check the tokens of each File resource instance for a mode
114
187
  # parameter and if found, record a warning if the value of that parameter is
115
188
  # not a 4 digit octal value (0755) or a symbolic mode ('o=rwx,g+r').
189
+ #
190
+ # https://docs.puppet.com/guides/style_guide.html#file-modes
116
191
  PuppetLint.new_check(:file_mode) do
117
192
  MSG = 'mode should be represented as a 4 digit octal value or symbolic mode'
118
193
  SYM_RE = "([ugoa]*[-=+][-=+rstwxXugo]*)(,[ugoa]*[-=+][-=+rstwxXugo]*)*"
@@ -154,6 +229,8 @@ end
154
229
  # Public: Check the tokens of each File resource instance for an ensure
155
230
  # parameter and record a warning if the value of that parameter looks like
156
231
  # a symlink target (starts with a '/').
232
+ #
233
+ # https://docs.puppet.com/guides/style_guide.html#symbolic-links
157
234
  PuppetLint.new_check(:ensure_not_symlink_target) do
158
235
  def check
159
236
  resource_indexes.each do |resource|
@@ -1,6 +1,8 @@
1
1
  # Public: Check the manifest tokens for any double quoted strings that don't
2
2
  # contain any variables or common escape characters and record a warning for
3
3
  # each instance found.
4
+ #
5
+ # https://docs.puppet.com/guides/style_guide.html#quoting
4
6
  PuppetLint.new_check(:double_quoted_strings) do
5
7
  def check
6
8
  tokens.select { |token|
@@ -26,6 +28,8 @@ end
26
28
 
27
29
  # Public: Check the manifest tokens for double quoted strings that contain
28
30
  # a single variable only and record a warning for each instance found.
31
+ #
32
+ # https://docs.puppet.com/guides/style_guide.html#quoting
29
33
  PuppetLint.new_check(:only_variable_string) do
30
34
  VAR_TYPES = Set[:VARIABLE, :UNENC_VARIABLE]
31
35
 
@@ -89,6 +93,8 @@ end
89
93
  # Public: Check the manifest tokens for any variables in a string that have
90
94
  # not been enclosed by braces ({}) and record a warning for each instance
91
95
  # found.
96
+ #
97
+ # https://docs.puppet.com/guides/style_guide.html#quoting
92
98
  PuppetLint.new_check(:variables_not_enclosed) do
93
99
  def check
94
100
  tokens.select { |r|
@@ -110,10 +116,12 @@ end
110
116
 
111
117
  # Public: Check the manifest tokens for any single quoted strings containing
112
118
  # a enclosed variable and record an error for each instance found.
119
+ #
120
+ # https://docs.puppet.com/guides/style_guide.html#quoting
113
121
  PuppetLint.new_check(:single_quote_string_with_variables) do
114
122
  def check
115
123
  tokens.select { |r|
116
- r.type == :SSTRING && r.value.include?('${')
124
+ r.type == :SSTRING && r.value.include?('${') && (! r.prev_token.prev_token.value.match(%r{inline_(epp|template)}) )
117
125
  }.each do |token|
118
126
  notify :error, {
119
127
  :message => 'single quoted string containing a variable found',
@@ -127,6 +135,8 @@ end
127
135
  # Public: Check the manifest tokens for any double or single quoted strings
128
136
  # containing only a boolean value and record a warning for each instance
129
137
  # found.
138
+ #
139
+ # No style guide reference
130
140
  PuppetLint.new_check(:quoted_booleans) do
131
141
  STRING_TYPES = Set[:STRING, :SSTRING]
132
142
  BOOLEANS = Set['true', 'false']
@@ -152,6 +162,8 @@ end
152
162
  # Public: Check the manifest tokens for any puppet:// URL strings where the
153
163
  # path section doesn't start with modules/ and record a warning for each
154
164
  # instance found.
165
+ #
166
+ # No style guide reference
155
167
  PuppetLint.new_check(:puppet_url_without_modules) do
156
168
  def check
157
169
  tokens.select { |token|
@@ -1,5 +1,7 @@
1
1
  # Public: Test the manifest tokens for variables that contain a dash and
2
2
  # record a warning for each instance found.
3
+ #
4
+ # No style guide reference
3
5
  PuppetLint.new_check(:variable_contains_dash) do
4
6
  VARIABLE_DASH_TYPES = Set[:VARIABLE, :UNENC_VARIABLE]
5
7
 
@@ -18,6 +20,10 @@ PuppetLint.new_check(:variable_contains_dash) do
18
20
  end
19
21
  end
20
22
 
23
+ # Public: Test the manifest tokens for variables that contain an uppercase
24
+ # letter and record a warning for each instance found.
25
+ #
26
+ # No style guide reference
21
27
  PuppetLint.new_check(:variable_is_lowercase) do
22
28
  VARIABLE_LOWERCASE_TYPES = Set[:VARIABLE, :UNENC_VARIABLE]
23
29
 
@@ -1,5 +1,7 @@
1
1
  # Public: Check the raw manifest string for lines containing hard tab
2
2
  # characters and record an error for each instance found.
3
+ #
4
+ # https://docs.puppet.com/guides/style_guide.html#spacing-indentation-and-whitespace
3
5
  PuppetLint.new_check(:hard_tabs) do
4
6
  WHITESPACE_TYPES = Set[:INDENT, :WHITESPACE]
5
7
 
@@ -23,6 +25,8 @@ end
23
25
 
24
26
  # Public: Check the manifest tokens for lines ending with whitespace and record
25
27
  # an error for each instance found.
28
+ #
29
+ # https://docs.puppet.com/guides/style_guide.html#spacing-indentation-and-whitespace
26
30
  PuppetLint.new_check(:trailing_whitespace) do
27
31
  def check
28
32
  tokens.select { |token|
@@ -52,6 +56,8 @@ end
52
56
  # characters and record a warning for each instance found. The only exceptions
53
57
  # to this rule are lines containing URLs and template() calls which would hurt
54
58
  # readability if split.
59
+ #
60
+ # https://docs.puppet.com/guides/style_guide.html#spacing-indentation-and-whitespace
55
61
  PuppetLint.new_check(:'140chars') do
56
62
  def check
57
63
  manifest_lines.each_with_index do |line, idx|
@@ -71,6 +77,8 @@ end
71
77
  # Public: Test the raw manifest string for lines containing more than 80
72
78
  # characters. This is DISABLED by default and behaves like the default
73
79
  # 140chars check by excepting URLs and template() calls.
80
+ #
81
+ # https://docs.puppet.com/guides/style_guide.html#spacing-indentation-and-whitespace (older version)
74
82
  PuppetLint.new_check(:'80chars') do
75
83
  def check
76
84
  manifest_lines.each_with_index do |line, idx|
@@ -90,6 +98,8 @@ PuppetLint.configuration.send("disable_80chars")
90
98
 
91
99
  # Public: Check the manifest tokens for any indentation not using 2 space soft
92
100
  # tabs and record an error for each instance found.
101
+ #
102
+ # https://docs.puppet.com/guides/style_guide.html#spacing-indentation-and-whitespace
93
103
  PuppetLint.new_check(:'2sp_soft_tabs') do
94
104
  def check
95
105
  tokens.select { |r|
@@ -108,6 +118,8 @@ end
108
118
 
109
119
  # Public: Check the manifest tokens for any arrows (=>) in a grouping ({}) that
110
120
  # are not aligned with other arrows in that grouping.
121
+ #
122
+ # https://docs.puppet.com/guides/style_guide.html#spacing-indentation-and-whitespace
111
123
  PuppetLint.new_check(:arrow_alignment) do
112
124
  COMMENT_TYPES = Set[:COMMENT, :SLASH_COMMENT, :MLCOMMENT]
113
125