puppet-lint 2.0.2 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
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