cookstyle 6.6.9 → 6.11.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -11,7 +11,8 @@ require 'rubocop/monkey_patches/comment_config.rb'
11
11
  # monkey patches needed for the TargetChefVersion config option
12
12
  require 'rubocop/monkey_patches/config.rb'
13
13
  require 'rubocop/monkey_patches/cop.rb'
14
- require 'rubocop/monkey_patches/commissioner.rb'
14
+ require 'rubocop/monkey_patches/team.rb'
15
+ require 'rubocop/monkey_patches/registry_cop.rb'
15
16
 
16
17
  module RuboCop
17
18
  class ConfigLoader
@@ -1,4 +1,4 @@
1
1
  module Cookstyle
2
- VERSION = "6.6.9".freeze # rubocop: disable Style/StringLiterals
3
- RUBOCOP_VERSION = '0.83.0'.freeze
2
+ VERSION = "6.11.4".freeze # rubocop: disable Style/StringLiterals
3
+ RUBOCOP_VERSION = '0.87.1'.freeze
4
4
  end
@@ -25,6 +25,8 @@ module RuboCop
25
25
  # # bad
26
26
  # ::Chef::Recipe.send(:include, Filebeat::Helpers)
27
27
  # ::Chef::Provider.send(:include, Filebeat::Helpers)
28
+ # ::Chef::Recipe.include Filebeat::Helpers
29
+ # ::Chef::Provider.include Filebeat::Helpers
28
30
  #
29
31
  # # good
30
32
  # ::Chef::DSL::Recipe.send(:include, Filebeat::Helpers) # covers previous Recipe & Provider classes
@@ -36,10 +38,18 @@ module RuboCop
36
38
  (send (const (const (cbase) :Chef) {:Recipe :Provider}) :send (sym :include) ... )
37
39
  PATTERN
38
40
 
41
+ def_node_matcher :legacy_class_includes?, <<-PATTERN
42
+ (send (const (const (cbase) :Chef) {:Recipe :Provider}) :include ... )
43
+ PATTERN
44
+
39
45
  def on_send(node)
40
46
  legacy_class_sends?(node) do
41
47
  add_offense(node, location: :expression, message: MSG, severity: :refactor)
42
48
  end
49
+
50
+ legacy_class_includes?(node) do
51
+ add_offense(node, location: :expression, message: MSG, severity: :refactor)
52
+ end
43
53
  end
44
54
 
45
55
  def autocorrect(node)
@@ -36,7 +36,7 @@ module RuboCop
36
36
 
37
37
  def on_send(node)
38
38
  version?(node) do |ver|
39
- if ver.value !~ /\A\d+\.\d+(\.\d+)?\z/ # entirely borrowed from Foodcritic.
39
+ unless /\A\d+\.\d+(\.\d+)?\z/.match?(ver.value) # entirely borrowed from Foodcritic.
40
40
  add_offense(ver, location: :expression, message: MSG, severity: :refactor)
41
41
  end
42
42
  end
@@ -19,7 +19,7 @@ module RuboCop
19
19
  module Cop
20
20
  module Chef
21
21
  module ChefCorrectness
22
- # When setting a node attribute as a default value for a custom resource property, make sure to wrap the node attribute in `lazy {}` so that the node attribute is available when the resource executes.
22
+ # When setting a node attribute as the default value for a custom resource property, wrap the node attribute in `lazy {}` so that its value is available when the resource executes.
23
23
  #
24
24
  # @example
25
25
  #
@@ -32,10 +32,10 @@ module RuboCop
32
32
  class LazyEvalNodeAttributeDefaults < Cop
33
33
  include RuboCop::Chef::CookbookHelpers
34
34
 
35
- MSG = 'When setting a node attribute as a default value for a custom resource property, make sure to wrap the node attribute in `lazy {}` so that the node attribute is available when the resource executes.'.freeze
35
+ MSG = 'When setting a node attribute as the default value for a custom resource property, wrap the node attribute in `lazy {}` so that its value is available when the resource executes.'.freeze
36
36
 
37
37
  def_node_matcher :non_lazy_node_attribute_default?, <<-PATTERN
38
- (send nil? :property (sym _) ... (hash <(pair (sym :default) $(send (send _ :node) :[] _) ) ...>))
38
+ (send nil? :property (sym _) ... (hash <(pair (sym :default) $(send (send _ :node) :[] _) ) ...>))
39
39
  PATTERN
40
40
 
41
41
  def on_send(node)
@@ -0,0 +1,141 @@
1
+ #
2
+ # Copyright:: Copyright (c) Chef Software Inc.
3
+ # Author:: Tim Smith (<tsmith@chef.io>)
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ module RuboCop
19
+ module Cop
20
+ module Chef
21
+ module ChefDeprecations
22
+ # Chef Infra Client 16 and later a legacy HWRP resource must use `provides` to define how the resource is called in recipes or other resources. To maintain compatibility with Chef Infra Client < 16 use both `resource_name` and `provides`.
23
+ #
24
+ # @example
25
+ #
26
+ # # bad
27
+ # class Chef
28
+ # class Resource
29
+ # class UlimitRule < Chef::Resource
30
+ # property :type, [Symbol, String], required: true
31
+ # property :item, [Symbol, String], required: true
32
+ #
33
+ # # additional resource code
34
+ # end
35
+ # end
36
+ # end
37
+ #
38
+ # # bad
39
+ # class Chef
40
+ # class Resource
41
+ # class UlimitRule < Chef::Resource
42
+ # resource_name :ulimit_rule
43
+ #
44
+ # property :type, [Symbol, String], required: true
45
+ # property :item, [Symbol, String], required: true
46
+ #
47
+ # # additional resource code
48
+ # end
49
+ # end
50
+ # end
51
+ #
52
+ # # good when Chef Infra Client < 15 (but compatible with 16+ as well)
53
+ # class Chef
54
+ # class Resource
55
+ # class UlimitRule < Chef::Resource
56
+ # resource_name :ulimit_rule
57
+ # provides :ulimit_rule
58
+ #
59
+ # property :type, [Symbol, String], required: true
60
+ # property :item, [Symbol, String], required: true
61
+ #
62
+ # # additional resource code
63
+ # end
64
+ # end
65
+ # end
66
+ #
67
+ # # good when Chef Infra Client 16+
68
+ # class Chef
69
+ # class Resource
70
+ # class UlimitRule < Chef::Resource
71
+ # provides :ulimit_rule
72
+ #
73
+ # property :type, [Symbol, String], required: true
74
+ # property :item, [Symbol, String], required: true
75
+ #
76
+ # # additional resource code
77
+ # end
78
+ # end
79
+ # end
80
+ #
81
+ # # better
82
+ # Convert your legacy HWRPs to custom resources
83
+ #
84
+ class HWRPWithoutProvides < Cop
85
+ MSG = 'In Chef Infra Client 16 and later a legacy HWRP resource must use `provides` to define how the resource is called in recipes or other resources. To maintain compatibility with Chef Infra Client < 16 use both `resource_name` and `provides`.'.freeze
86
+
87
+ def_node_matcher :HWRP?, <<-PATTERN
88
+ (class
89
+ (const nil? :Chef) nil?
90
+ (class
91
+ (const nil? :Resource) nil?
92
+ $(class
93
+ (const nil? ... )
94
+ (const
95
+ (const nil? :Chef) :Resource)
96
+ (begin ... ))))
97
+ PATTERN
98
+
99
+ def_node_search :provides, '(send nil? :provides (sym $_) ...)'
100
+ def_node_search :resource_name_ast, '$(send nil? :resource_name ...)'
101
+ def_node_search :resource_name, '(send nil? :resource_name (sym $_))'
102
+
103
+ def on_class(node)
104
+ HWRP?(node) do |inherit|
105
+ add_offense(inherit, location: :expression, message: MSG, severity: :warning) unless has_provides?
106
+ end
107
+ end
108
+
109
+ def has_provides?
110
+ provides_ast = provides(processed_source.ast)
111
+ return false if provides_ast.count == 0
112
+
113
+ resource_ast = resource_name(processed_source.ast)
114
+
115
+ if resource_ast.count == 0
116
+ true # no resource_name, but provides
117
+ else
118
+ # since we have a resource and provides make sure the there is a provides that
119
+ # matches the resource name
120
+ provides_ast.include?(resource_ast.first)
121
+ end
122
+ end
123
+
124
+ def indentation(node)
125
+ node.source_range.source_line =~ /\S/
126
+ end
127
+
128
+ def autocorrect(node)
129
+ lambda do |corrector|
130
+ resource_name_ast(node) do |ast_match|
131
+ # build a new string to add after that includes the new line and the proper indentation
132
+ new_string = "\n" + ast_match.source.dup.gsub('resource_name', 'provides').prepend(' ' * indentation(ast_match))
133
+ corrector.insert_after(ast_match.source_range, new_string)
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,86 @@
1
+ #
2
+ # Copyright:: Copyright (c) Chef Software Inc.
3
+ # Author:: Tim Smith (<tsmith@chef.io>)
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+ module RuboCop
18
+ module Cop
19
+ module Chef
20
+ module ChefDeprecations
21
+ # Starting with Chef Infra Client 16, using `resource_name` without also using `provides` will result in resource failures. Make sure to use both `resource_name` and `provides` to change the name of the resource. You can also omit `resource_name` entirely if the value set matches the name Chef Infra Client automatically assigns based on COOKBOOKNAME_FILENAME.
22
+ #
23
+ # @example
24
+ #
25
+ # # bad
26
+ # mycookbook/resources/myresource.rb:
27
+ # resource_name :mycookbook_myresource
28
+ #
29
+ class ResourceUsesOnlyResourceName < Cop
30
+ include RuboCop::Chef::CookbookHelpers
31
+ include RangeHelp
32
+
33
+ MSG = 'Starting with Chef Infra Client 16, using `resource_name` without also using `provides` will result in resource failures. Make sure to use both `resource_name` and `provides` to change the name of the resource. You can also omit `resource_name` entirely if the value set matches the name Chef Infra Client automatically assigns based on COOKBOOKNAME_FILENAME.'.freeze
34
+
35
+ def_node_matcher :resource_name?, '(send nil? :resource_name (sym $_ ))'
36
+
37
+ def_node_search :cb_name_match, '(send nil? :name (str $_))'
38
+
39
+ def_node_search :provides, '(send nil? :provides (sym $_) ...)'
40
+
41
+ # determine the cookbook name either by parsing metdata.rb or by parsing metata.json
42
+ #
43
+ # @returns [String] the cookbook name
44
+ def cookbook_name
45
+ cb_path = File.expand_path(File.join(processed_source.file_path, '../..'))
46
+
47
+ if File.exist?(File.join(cb_path, 'metadata.rb'))
48
+ cb_metadata_ast = ProcessedSource.from_file(File.join(cb_path, 'metadata.rb'), @config.target_ruby_version).ast
49
+ cb_name_match(cb_metadata_ast).first
50
+ elsif File.exist?(File.join(cb_path, 'metadata.json')) # this exists only for supermarket files that lack metadata.rb
51
+ JSON.parse(File.read(File.join(cb_path, 'metadata.json')))['name']
52
+ end
53
+ end
54
+
55
+ # given a resource name make sure there's a provides that matches that name
56
+ #
57
+ # @returns [TrueClass, FalseClass]
58
+ def valid_provides?(resource_name)
59
+ provides_ast = provides(processed_source.ast)
60
+ return false unless provides_ast
61
+
62
+ provides_ast.include?(resource_name)
63
+ end
64
+
65
+ def on_send(node)
66
+ resource_name?(node) do |r_name|
67
+ add_offense(node, location: :expression, message: MSG, severity: :warning) unless valid_provides?(r_name)
68
+ end
69
+ end
70
+
71
+ def autocorrect(node)
72
+ lambda do |corrector|
73
+ resource_name?(node) do |name|
74
+ if name.to_s == "#{cookbook_name}_#{File.basename(processed_source.path, '.rb')}"
75
+ corrector.remove(range_with_surrounding_space(range: node.loc.expression, side: :left))
76
+ else
77
+ corrector.insert_after(node.source_range, "\n#{node.source.gsub('resource_name', 'provides')}")
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,56 @@
1
+ #
2
+ # Copyright:: 2019, Chef Software, Inc.
3
+ # Author:: Tim Smith (<tsmith@chef.io>)
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+ module RuboCop
18
+ module Cop
19
+ module Chef
20
+ module ChefModernize
21
+ # Use ::File.exist?('/foo/bar') instead of the slower 'test -f /foo/bar' which requires shelling out
22
+ #
23
+ # @example
24
+ #
25
+ # # bad
26
+ # only_if 'test -f /bin/foo'
27
+ #
28
+ # # good
29
+ # only_if { ::File.exist?('bin/foo') }
30
+ #
31
+ class ConditionalUsingTest < Cop
32
+ MSG = "Use ::File.exist?('/foo/bar') instead of the slower 'test -f /foo/bar' which requires shelling out".freeze
33
+
34
+ def_node_matcher :resource_conditional?, <<~PATTERN
35
+ (send nil? {:not_if :only_if} $str )
36
+ PATTERN
37
+
38
+ def on_send(node)
39
+ resource_conditional?(node) do |conditional|
40
+ add_offense(node, location: :expression, message: MSG, severity: :refactor) if conditional.value.match?(/^test -[ef] \S*$/)
41
+ end
42
+ end
43
+
44
+ def autocorrect(node)
45
+ lambda do |corrector|
46
+ resource_conditional?(node) do |conditional|
47
+ new_string = "{ ::File.exist?('#{conditional.value.match(/^test -[ef] (\S*)$/)[1]}') }"
48
+ corrector.replace(conditional.loc.expression, new_string)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright:: 2019, Chef Software Inc.
2
+ # Copyright:: 2019-2020, Chef Software Inc.
3
3
  # Author:: Tim Smith (<tsmith@chef.io>)
4
4
  #
5
5
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -42,13 +42,34 @@ module RuboCop
42
42
  (send nil? :require ( str {"chef/mixin/shell_out" "chef/mixin/powershell_out"} ))
43
43
  PATTERN
44
44
 
45
+ def_node_search :hwrp_classes?, <<-PATTERN
46
+ (class
47
+ (const ... )
48
+ {(const
49
+ (const
50
+ (const nil? :Chef) :Provider) :LWRPBase)
51
+ (const
52
+ (const nil? :Chef) :Provider)
53
+ }
54
+ ...)
55
+ PATTERN
56
+
57
+ def check_for_offenses(node)
58
+ containing_dir = File.basename(File.dirname(processed_source.path))
59
+
60
+ # only add offenses when we're in a custom resource or HWRP, but not a plain old library
61
+ if containing_dir == 'resources' || hwrp_classes?(processed_source.ast)
62
+ add_offense(node, location: :expression, message: MSG, severity: :refactor)
63
+ end
64
+ end
65
+
45
66
  def on_send(node)
46
67
  require_shellout?(node) do
47
- add_offense(node, location: :expression, message: MSG, severity: :refactor)
68
+ check_for_offenses(node)
48
69
  end
49
70
 
50
71
  include_shellout?(node) do
51
- add_offense(node, location: :expression, message: MSG, severity: :refactor)
72
+ check_for_offenses(node)
52
73
  end
53
74
  end
54
75
 
@@ -27,18 +27,20 @@ module RuboCop
27
27
  # ::File.open('/proc/1/comm').chomp == 'systemd'
28
28
  # File.open('/proc/1/comm').gets.chomp == 'systemd'
29
29
  # File.open('/proc/1/comm').chomp == 'systemd'
30
- # File.exist?('/proc/1/comm') && File.open('/proc/1/comm').chomp == 'systemd'
31
- #
32
30
  # IO.read('/proc/1/comm').chomp == 'systemd'
33
31
  # IO.read('/proc/1/comm').gets.chomp == 'systemd'
34
32
  # ::IO.read('/proc/1/comm').chomp == 'systemd'
35
33
  # ::IO.read('/proc/1/comm').gets.chomp == 'systemd'
36
34
  # File.exist?('/proc/1/comm') && File.open('/proc/1/comm').chomp == 'systemd'
35
+ # only_if 'test -f /bin/systemctl && /bin/systemctl'
37
36
  #
38
37
  # # good
39
38
  # node['init_package'] == 'systemd'
39
+ # only_if { node['init_package'] == 'systemd' }
40
40
  #
41
- class NodeInitPackage < Cop
41
+ class NodeInitPackage < Base
42
+ extend RuboCop::Cop::AutoCorrector
43
+
42
44
  MSG = "Use node['init_package'] to check for systemd instead of reading the contents of '/proc/1/comm'".freeze
43
45
 
44
46
  def_node_matcher :file_reads_proc_1_comm?, <<-PATTERN
@@ -58,18 +60,24 @@ module RuboCop
58
60
  :== (str "systemd"))
59
61
  PATTERN
60
62
 
63
+ def_node_matcher :file_systemd_conditional?, <<~PATTERN
64
+ (send nil? {:not_if :only_if} $(str "test -f /bin/systemctl && /bin/systemctl"))
65
+ PATTERN
66
+
61
67
  def on_send(node)
62
68
  compare_init_system?(node) do
63
69
  # if there's a ::File.exist?('/proc/1/comm') check first we want to match that as well
64
70
  node = node.parent if node.parent&.and_type? && proc_1_comm_exists?(node.parent.conditions.first)
65
71
 
66
- add_offense(node, location: :expression, message: MSG, severity: :refactor)
72
+ add_offense(node.loc.expression, message: MSG, severity: :refactor) do |corrector|
73
+ corrector.replace(node, "node['init_package'] == 'systemd'")
74
+ end
67
75
  end
68
- end
69
76
 
70
- def autocorrect(node)
71
- lambda do |corrector|
72
- corrector.replace(node.loc.expression, "node['init_package'] == 'systemd'")
77
+ file_systemd_conditional?(node) do |conditional|
78
+ add_offense(node.loc.expression, message: MSG, severity: :refactor) do |corrector|
79
+ corrector.replace(conditional.loc.expression, "{ node['init_package'] == 'systemd' }")
80
+ end
73
81
  end
74
82
  end
75
83
  end