cookstyle 5.15.7 → 5.16.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/config/cookstyle.yml +172 -4
  3. data/lib/cookstyle.rb +6 -0
  4. data/lib/cookstyle/version.rb +1 -1
  5. data/lib/rubocop/chef/cookbook_helpers.rb +12 -4
  6. data/lib/rubocop/cop/chef/correctness/dnf_package_allow_downgrades.rb +50 -0
  7. data/lib/rubocop/cop/chef/correctness/invalid_notification_timing.rb +53 -0
  8. data/lib/rubocop/cop/chef/correctness/malformed_value_for_platform.rb +67 -0
  9. data/lib/rubocop/cop/chef/correctness/notifies_action_not_symbol.rb +11 -3
  10. data/lib/rubocop/cop/chef/deprecation/chef_rewind.rb +6 -3
  11. data/lib/rubocop/cop/chef/deprecation/depends_compat_resource.rb +4 -0
  12. data/lib/rubocop/cop/chef/deprecation/deprecated_platform_methods.rb +56 -0
  13. data/lib/rubocop/cop/chef/deprecation/legacy_notify_syntax.rb +11 -3
  14. data/lib/rubocop/cop/chef/deprecation/name_property_and_default.rb +18 -22
  15. data/lib/rubocop/cop/chef/deprecation/ruby_block_create_action.rb +64 -0
  16. data/lib/rubocop/cop/chef/modernize/apt_default_recipe.rb +5 -2
  17. data/lib/rubocop/cop/chef/modernize/chef_14_resources.rb +4 -0
  18. data/lib/rubocop/cop/chef/modernize/cron_manage_resource.rb +4 -0
  19. data/lib/rubocop/cop/chef/modernize/depends_zypper_cookbook.rb +4 -0
  20. data/lib/rubocop/cop/chef/modernize/execute_sc_exe.rb +66 -0
  21. data/lib/rubocop/cop/chef/modernize/execute_sleep.rb +77 -0
  22. data/lib/rubocop/cop/chef/modernize/execute_tzutil.rb +3 -0
  23. data/lib/rubocop/cop/chef/modernize/foodcritic_comments.rb +51 -0
  24. data/lib/rubocop/cop/chef/modernize/libarchive_file.rb +4 -0
  25. data/lib/rubocop/cop/chef/modernize/macos_user_defaults.rb +4 -0
  26. data/lib/rubocop/cop/chef/modernize/openssl_rsa_key_resource.rb +4 -0
  27. data/lib/rubocop/cop/chef/modernize/openssl_x509_resource.rb +4 -0
  28. data/lib/rubocop/cop/chef/modernize/powershell_expand_archive.rb +3 -0
  29. data/lib/rubocop/cop/chef/modernize/powershell_guard_interpreter.rb +3 -0
  30. data/lib/rubocop/cop/chef/modernize/powershell_install_package.rb +3 -0
  31. data/lib/rubocop/cop/chef/modernize/powershell_install_windowsfeature.rb +3 -0
  32. data/lib/rubocop/cop/chef/modernize/property_with_name_attribute.rb +13 -15
  33. data/lib/rubocop/cop/chef/modernize/respond_to_metadata.rb +4 -0
  34. data/lib/rubocop/cop/chef/modernize/sc_windows_resource.rb +49 -0
  35. data/lib/rubocop/cop/chef/modernize/seven_zip_archive.rb +4 -0
  36. data/lib/rubocop/cop/chef/modernize/systctl_param_resource.rb +4 -2
  37. data/lib/rubocop/cop/chef/modernize/whyrun_supported_true.rb +4 -0
  38. data/lib/rubocop/cop/chef/modernize/windows_default_recipe.rb +1 -2
  39. data/lib/rubocop/cop/chef/modernize/windows_zipfile.rb +4 -0
  40. data/lib/rubocop/cop/chef/modernize/zipfile_resource.rb +3 -0
  41. data/lib/rubocop/cop/chef/modernize/zypper_repo.rb +4 -0
  42. data/lib/rubocop/cop/chef/redundant/custom_resource_with_allowed_actions.rb +1 -1
  43. data/lib/rubocop/cop/chef/redundant/long_description_metadata.rb +0 -1
  44. data/lib/rubocop/cop/chef/redundant/sensitive_property_in_resource.rb +48 -0
  45. data/lib/rubocop/cop/chef/redundant/unnecessary_desired_state.rb +57 -0
  46. data/lib/rubocop/cop/chef/redundant/unnecessary_name_property.rb +10 -7
  47. data/lib/rubocop/cop/chef/style/immediate_notification_timing.rb +59 -0
  48. data/lib/rubocop/cop/chef/style/true_false_resource_properties.rb +55 -0
  49. data/lib/rubocop/cop/chef/style/unnecessary_platform_case_statement.rb +90 -0
  50. data/lib/rubocop/cop/chef/style/use_platform_helpers.rb +21 -5
  51. data/lib/rubocop/cop/target_chef_version.rb +18 -0
  52. data/lib/rubocop/monkey_patches/commissioner.rb +26 -0
  53. data/lib/rubocop/monkey_patches/config.rb +15 -0
  54. data/lib/rubocop/monkey_patches/cop.rb +10 -0
  55. metadata +20 -2
@@ -34,6 +34,10 @@ module RuboCop
34
34
  # chef_version '>= 13'
35
35
  #
36
36
  class RespondToInMetadata < Cop
37
+ extend TargetChefVersion
38
+
39
+ minimum_target_chef_version '12.15'
40
+
37
41
  MSG = 'It is no longer necessary to use respond_to? or if_defined? in metadata.rb in Chef Infra Client 12.15 and later'.freeze
38
42
 
39
43
  def on_if(node)
@@ -0,0 +1,49 @@
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
+ # The sc_windows resource from the sc cookbook allowed for the creation of windows services on legacy Chef Infra Client releases. Chef Infra Client 14.0 and later includes :create, :delete, and :configure actions without the need for additional cookbook dependencies. See the windows_service documentation at https://docs.chef.io/resource_windows_service.html for additional details on creating services with the windows_service resource.
22
+ #
23
+ # # bad
24
+ # sc_windows 'chef-client' do
25
+ # path "C:\\opscode\\chef\\bin"
26
+ # action :create
27
+ # end
28
+ #
29
+ # # good
30
+ # windows_service 'chef-client' do
31
+ # action :create
32
+ # binary_path_name "C:\\opscode\\chef\\bin"
33
+ # end
34
+ #
35
+ class WindowsScResource < Cop
36
+ extend TargetChefVersion
37
+
38
+ minimum_target_chef_version '14.0'
39
+
40
+ MSG = 'Chef Infra Client 14.0 and later includes :create, :delete, and :configure actions without the need for the sc cookbook dependency. See the windows_service documentation at https://docs.chef.io/resource_windows_service.html for additional details.'.freeze
41
+
42
+ def on_send(node)
43
+ add_offense(node, location: :expression, message: MSG, severity: :refactor) if node.method_name == :sc_windows
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -29,6 +29,10 @@ module RuboCop
29
29
  # end
30
30
  #
31
31
  class SevenZipArchiveResource < Cop
32
+ extend TargetChefVersion
33
+
34
+ minimum_target_chef_version '15.0'
35
+
32
36
  MSG = 'Use the archive_file resource built into Chef Infra Client 15+ instead of the seven_zip_archive'.freeze
33
37
 
34
38
  def on_send(node)
@@ -18,8 +18,7 @@ module RuboCop
18
18
  module Cop
19
19
  module Chef
20
20
  module ChefModernize
21
- # The sysctl_param resource was renamed to sysctl when it was added to Chef Infra Client
22
- # 14.0. The new resource name should be used.
21
+ # The sysctl_param resource was renamed to sysctl when it was added to Chef Infra Client 14.0. The new resource name should be used.
23
22
  #
24
23
  # # bad
25
24
  # sysctl_param 'fs.aio-max-nr' do
@@ -33,6 +32,9 @@ module RuboCop
33
32
  #
34
33
  class SysctlParamResource < Cop
35
34
  include RuboCop::Chef::CookbookHelpers
35
+ extend TargetChefVersion
36
+
37
+ minimum_target_chef_version '14.0'
36
38
 
37
39
  MSG = 'The sysctl_param resource was renamed to sysctl when it was added to Chef Infra Client 14.0. The new resource name should be used.'.freeze
38
40
 
@@ -28,6 +28,10 @@ module RuboCop
28
28
  # end
29
29
  #
30
30
  class WhyRunSupportedTrue < Cop
31
+ extend TargetChefVersion
32
+
33
+ minimum_target_chef_version '13.0'
34
+
31
35
  MSG = 'whyrun_supported? no longer needs to be set to true as it is the default in Chef Infra Client 13+'.freeze
32
36
 
33
37
  def on_def(node)
@@ -18,8 +18,7 @@ module RuboCop
18
18
  module Cop
19
19
  module Chef
20
20
  module ChefModernize
21
- # Don't include the windows default recipe that is either full of gem install that are part
22
- # of the Chef Infra Client, or empty (depends on version).
21
+ # Don't include the windows default recipe that is either full of gem install that are part of the Chef Infra Client, or empty (depends on version).
23
22
  #
24
23
  # @example
25
24
  #
@@ -28,6 +28,10 @@ module RuboCop
28
28
  # end
29
29
  #
30
30
  class WindowsZipfileUsage < Cop
31
+ extend TargetChefVersion
32
+
33
+ minimum_target_chef_version '15.0'
34
+
31
35
  MSG = 'Use the archive_file resource built into Chef Infra Client 15+ instead of the windows_zipfile from the Windows cookbook'.freeze
32
36
 
33
37
  def on_send(node)
@@ -30,6 +30,9 @@ module RuboCop
30
30
  #
31
31
  class ZipfileResource < Cop
32
32
  include RuboCop::Chef::CookbookHelpers
33
+ extend TargetChefVersion
34
+
35
+ minimum_target_chef_version '15.0'
33
36
 
34
37
  MSG = 'Use the archive_file resource built into Chef Infra Client 15+ instead of the zipfile resource from the zipfile cookbook.'.freeze
35
38
 
@@ -39,6 +39,10 @@ module RuboCop
39
39
  # end
40
40
  #
41
41
  class UsesZypperRepo < Cop
42
+ extend TargetChefVersion
43
+
44
+ minimum_target_chef_version '13.3'
45
+
42
46
  MSG = 'The zypper_repo resource was renamed zypper_repository when it was added to Chef Infra Client 13.3.'.freeze
43
47
 
44
48
  def on_send(node)
@@ -18,7 +18,7 @@
18
18
  module RuboCop
19
19
  module Cop
20
20
  module Chef
21
- module ChefRedundant
21
+ module ChefRedundantCode
22
22
  # It is not necessary to set `actions` or `allowed_actions` in custom resources as Chef Infra Client determines these automatically from the set of all actions defined in the resource.
23
23
  #
24
24
  # @example
@@ -26,7 +26,6 @@ module RuboCop
26
26
  # # bad
27
27
  # long_description 'this is my cookbook and this description will never be seen'
28
28
  #
29
-
30
29
  class LongDescriptionMetadata < Cop
31
30
  include RangeHelp
32
31
 
@@ -0,0 +1,48 @@
1
+ #
2
+ # Copyright:: 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 ChefRedundantCode
21
+ # Every Chef Infra resources already include a sensitive property with a default value of false.
22
+ #
23
+ # # bad
24
+ # property :sensitive, [true, false], default: false
25
+ #
26
+ class SensitivePropertyInResource < Cop
27
+ MSG = 'Every Chef Infra resources already include a sensitive property with a default value of false.'.freeze
28
+
29
+ def_node_matcher :sensitive_property?, <<-PATTERN
30
+ (send nil? {:property :attribute} (sym :sensitive) ... (hash (pair (sym :default) (false))))
31
+ PATTERN
32
+
33
+ def on_send(node)
34
+ if sensitive_property?(node)
35
+ add_offense(node, location: :expression, message: MSG, severity: :refactor)
36
+ end
37
+ end
38
+
39
+ def autocorrect(node)
40
+ lambda do |corrector|
41
+ corrector.remove(node.source_range)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,57 @@
1
+ #
2
+ # Copyright:: 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 ChefRedundantCode
21
+ # There is no need to set a property to desired_state: true as all properties have a desired_state of true by default.
22
+ #
23
+ # @example
24
+ #
25
+ # # bad
26
+ # property :foo, String, desired_state: true
27
+ #
28
+ class UnnecessaryDesiredState < Cop
29
+ include RangeHelp
30
+
31
+ MSG = 'There is no need to set a property to desired_state: true as all properties have a desired_state of true by default.'.freeze
32
+
33
+ def_node_matcher :property?, <<-PATTERN
34
+ (send nil? {:property :attribute} (sym _) ... $(hash ...))
35
+ PATTERN
36
+
37
+ def on_send(node)
38
+ property?(node) do |hash_vals|
39
+ hash_vals.each_pair do |k, v|
40
+ if k == s(:sym, :desired_state) && v == s(:true) # cookstyle: disable Lint/BooleanSymbol
41
+ add_offense(v.parent, location: :expression, message: MSG, severity: :refactor)
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ def autocorrect(node)
48
+ lambda do |corrector|
49
+ range = range_with_surrounding_comma(range_with_surrounding_space(range: node.loc.expression, side: :left), :left)
50
+ corrector.remove(range)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -18,26 +18,29 @@ module RuboCop
18
18
  module Cop
19
19
  module Chef
20
20
  module ChefRedundantCode
21
- # There is no need to define a property named :name in a resource as Chef Infra defines that property for all resources by default.
21
+ # There is no need to define a property or attribute named :name in a resource as Chef Infra defines this on all resources by default.
22
22
  #
23
23
  # @example
24
24
  #
25
25
  # # bad
26
26
  # property :name, String
27
27
  # property :name, String, name_property: true
28
+ # attribute :name, String
29
+ # attribute :name, String, name_attribute: true
28
30
  #
29
31
  class UnnecessaryNameProperty < Cop
30
- MSG = 'There is no need to define a property named :name in a resource as Chef Infra defines that property for all resources by default.'.freeze
32
+ MSG = 'There is no need to define a property or attribute named :name in a resource as Chef Infra defines this on all resources by default.'.freeze
31
33
 
34
+ # match on a property/attribute named :name that's a string. The property/attribute optionally
35
+ # set name_property/name_attribute true, but nothing else is allowed. If you're doing that it's
36
+ # no longer the default and your usage is fine.
32
37
  def_node_matcher :name_property?, <<-PATTERN
33
- (send nil? :property (sym :name) (const nil? :String) $...)
38
+ (send nil? {:property :attribute} (sym :name) (const nil? :String) (hash (pair (sym {:name_attribute :name_property}) (true)))?)
34
39
  PATTERN
35
40
 
36
41
  def on_send(node)
37
- name_property?(node) do |hash_vals|
38
- if hash_vals.empty? || (hash_vals.first.keys.count == 1 && hash_vals.first.keys.first.source == 'name_property')
39
- add_offense(node, location: :expression, message: MSG, severity: :refactor)
40
- end
42
+ name_property?(node) do
43
+ add_offense(node, location: :expression, message: MSG, severity: :refactor)
41
44
  end
42
45
  end
43
46
 
@@ -0,0 +1,59 @@
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 ChefStyle
21
+ # Use :immediately instead of :immediate for resource notification timing
22
+ #
23
+ # @example
24
+ #
25
+ # # bad
26
+ #
27
+ # template '/etc/www/configures-apache.conf' do
28
+ # notifies :restart, 'service[apache]', :immediate
29
+ # end
30
+ #
31
+ # # good
32
+ #
33
+ # template '/etc/www/configures-apache.conf' do
34
+ # notifies :restart, 'service[apache]', :immediately
35
+ # end
36
+ #
37
+ class ImmediateNotificationTiming < Cop
38
+ MSG = 'Use :immediately instead of :immediate for resource notification timing'.freeze
39
+
40
+ def_node_matcher :immediate_notify?, <<-PATTERN
41
+ (send nil? :notifies (sym _) (...) $(sym :immediate))
42
+ PATTERN
43
+
44
+ def on_send(node)
45
+ immediate_notify?(node) do |timing|
46
+ add_offense(timing, location: :expression, message: MSG, severity: :refactor)
47
+ end
48
+ end
49
+
50
+ def autocorrect(node)
51
+ lambda do |corrector|
52
+ corrector.replace(node.loc.expression, ':immediately')
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,55 @@
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 ChefStyle
21
+ # When setting the allowed types for a resource to accept either true or false values it's much simpler to use true and false instead of TrueClass and FalseClass.
22
+ #
23
+ # @example
24
+ #
25
+ # # bad
26
+ # property :foo, [TrueClass, FalseClass]
27
+ #
28
+ # # good
29
+ # property :foo, [true, false]
30
+ #
31
+ class TrueClassFalseClassResourceProperties < Cop
32
+ MSG = "When setting the allowed types for a resource to accept either true or false values it's much simpler to use true and false instead of TrueClass and FalseClass.".freeze
33
+
34
+ def_node_matcher :trueclass_falseclass_property?, <<-PATTERN
35
+ (send nil? {:property :attribute} (sym _) $(array (const nil? :TrueClass) (const nil? :FalseClass)) ... )
36
+ PATTERN
37
+
38
+ def on_send(node)
39
+ trueclass_falseclass_property?(node) do
40
+ add_offense(node, location: :expression, message: MSG, severity: :refactor)
41
+ end
42
+ end
43
+
44
+ def autocorrect(node)
45
+ lambda do |corrector|
46
+ trueclass_falseclass_property?(node) do |types|
47
+ corrector.replace(types.loc.expression, '[true, false]')
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,90 @@
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 ChefStyle
21
+ # Use the platform?() and platform_family?() helpers instead of a case statement that only includes a single when statement.
22
+ #
23
+ # @example
24
+ #
25
+ # # bad
26
+ # case node['platform']
27
+ # when 'ubuntu'
28
+ # log "We're on Ubuntu"
29
+ # apt_update
30
+ # end
31
+ #
32
+ # case node['platform_family']
33
+ # when 'rhel'
34
+ # include_recipe 'yum'
35
+ # end
36
+ #
37
+ # # good
38
+ # if platform?('ubuntu')
39
+ # log "We're on Ubuntu"
40
+ # apt_update
41
+ # end
42
+ #
43
+ # include_recipe 'yum' if platform_family?('rhel')
44
+ #
45
+ class UnnecessaryPlatformCaseStatement < Cop
46
+ include RangeHelp
47
+
48
+ MSG = 'Use the platform?() and platform_family?() helpers instead of a case statement that only includes a single when statement.'.freeze
49
+
50
+ def_node_matcher :platform_case?, <<-PATTERN
51
+ ( case $( send (send nil? :node) :[] $(str {"platform" "platform_family"})) ... )
52
+ PATTERN
53
+
54
+ def on_case(node)
55
+ platform_case?(node) do
56
+ add_offense(node, location: :expression, message: MSG, severity: :refactor) if node&.when_branches&.count == 1
57
+ end
58
+ end
59
+
60
+ def autocorrect(node)
61
+ lambda do |corrector|
62
+ platform_case?(node) do |node_, type|
63
+ condition_string = node.when_branches.first.conditions.map(&:source).join(', ')
64
+
65
+ # single line bodies without an else statement should be transformed into `X if platform?('ubuntu')` style statements
66
+ # while multiline statements should just have the case and when bits replace with `if platform?('ubuntu')`
67
+ if !node.else? && !node.when_branches.first.body.multiline?
68
+ new_source = "#{node.when_branches.first.body.source} if #{type.value}?(#{condition_string})"
69
+ corrector.replace(node.loc.expression, new_source)
70
+ else
71
+ # find the range from the beginning of the case to the end of the node['platform'] or node['platform_family']
72
+ case_range = node.loc.keyword.join(node_.loc.expression.end)
73
+
74
+ # replace the complete conditional range with a new if statement
75
+ corrector.replace(case_range, "if #{type.value}?(#{condition_string})")
76
+
77
+ # find the range from the start of the when to the end of the last argument
78
+ conditional_range = node.when_branches.first.conditions[-1].source_range.join(node.when_branches.first.loc.keyword.begin)
79
+
80
+ # remove the when XYZ condition along with any leading spaces so that we remove the whole empty line
81
+ corrector.remove(range_with_surrounding_space(range: conditional_range, side: :left))
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end