foodcritic 10.0.0 → 10.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 (101) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -1
  3. data/Gemfile +2 -2
  4. data/features/031_check_for_metadata_existence.feature +2 -2
  5. data/features/choose_rules_to_apply.feature +27 -27
  6. data/features/continuous_integration_support.feature +2 -2
  7. data/features/support/command_helpers.rb +2 -2
  8. data/lib/foodcritic/api.rb +29 -3
  9. data/lib/foodcritic/linter.rb +1 -1
  10. data/lib/foodcritic/rules/fc001.rb +7 -0
  11. data/lib/foodcritic/rules/fc002.rb +8 -0
  12. data/lib/foodcritic/rules/fc004.rb +12 -0
  13. data/lib/foodcritic/rules/fc005.rb +29 -0
  14. data/lib/foodcritic/rules/fc006.rb +11 -0
  15. data/lib/foodcritic/rules/fc007.rb +19 -0
  16. data/lib/foodcritic/rules/fc008.rb +12 -0
  17. data/lib/foodcritic/rules/fc009.rb +18 -0
  18. data/lib/foodcritic/rules/fc010.rb +7 -0
  19. data/lib/foodcritic/rules/fc011.rb +8 -0
  20. data/lib/foodcritic/rules/fc012.rb +8 -0
  21. data/lib/foodcritic/rules/fc013.rb +10 -0
  22. data/lib/foodcritic/rules/fc014.rb +10 -0
  23. data/lib/foodcritic/rules/fc015.rb +8 -0
  24. data/lib/foodcritic/rules/fc016.rb +10 -0
  25. data/lib/foodcritic/rules/fc017.rb +29 -0
  26. data/lib/foodcritic/rules/fc018.rb +9 -0
  27. data/lib/foodcritic/rules/fc019.rb +34 -0
  28. data/lib/foodcritic/rules/fc021.rb +13 -0
  29. data/lib/foodcritic/rules/fc022.rb +33 -0
  30. data/lib/foodcritic/rules/fc024.rb +31 -0
  31. data/lib/foodcritic/rules/fc025.rb +17 -0
  32. data/lib/foodcritic/rules/fc026.rb +14 -0
  33. data/lib/foodcritic/rules/fc027.rb +9 -0
  34. data/lib/foodcritic/rules/fc028.rb +8 -0
  35. data/lib/foodcritic/rules/fc029.rb +14 -0
  36. data/lib/foodcritic/rules/fc030.rb +11 -0
  37. data/lib/foodcritic/rules/fc031.rb +8 -0
  38. data/lib/foodcritic/rules/fc032.rb +15 -0
  39. data/lib/foodcritic/rules/fc033.rb +26 -0
  40. data/lib/foodcritic/rules/fc034.rb +31 -0
  41. data/lib/foodcritic/rules/fc037.rb +14 -0
  42. data/lib/foodcritic/rules/fc038.rb +17 -0
  43. data/lib/foodcritic/rules/fc039.rb +19 -0
  44. data/lib/foodcritic/rules/fc040.rb +12 -0
  45. data/lib/foodcritic/rules/fc041.rb +9 -0
  46. data/lib/foodcritic/rules/fc042.rb +6 -0
  47. data/lib/foodcritic/rules/fc043.rb +8 -0
  48. data/lib/foodcritic/rules/fc044.rb +22 -0
  49. data/lib/foodcritic/rules/fc045.rb +13 -0
  50. data/lib/foodcritic/rules/fc046.rb +8 -0
  51. data/lib/foodcritic/rules/fc047.rb +16 -0
  52. data/lib/foodcritic/rules/fc048.rb +13 -0
  53. data/lib/foodcritic/rules/fc049.rb +10 -0
  54. data/lib/foodcritic/rules/fc050.rb +8 -0
  55. data/lib/foodcritic/rules/fc051.rb +15 -0
  56. data/lib/foodcritic/rules/fc052.rb +6 -0
  57. data/lib/foodcritic/rules/fc053.rb +6 -0
  58. data/lib/foodcritic/rules/fc055.rb +6 -0
  59. data/lib/foodcritic/rules/fc056.rb +6 -0
  60. data/lib/foodcritic/rules/fc057.rb +8 -0
  61. data/lib/foodcritic/rules/fc058.rb +9 -0
  62. data/lib/foodcritic/rules/fc059.rb +10 -0
  63. data/lib/foodcritic/rules/fc060.rb +10 -0
  64. data/lib/foodcritic/rules/fc061.rb +10 -0
  65. data/lib/foodcritic/rules/fc062.rb +6 -0
  66. data/lib/foodcritic/rules/fc063.rb +8 -0
  67. data/lib/foodcritic/rules/fc064.rb +6 -0
  68. data/lib/foodcritic/rules/fc065.rb +6 -0
  69. data/lib/foodcritic/version.rb +1 -1
  70. data/spec/foodcritic/api_spec.rb +62 -0
  71. data/spec/foodcritic/coverage/assets/0.10.0/application.css +799 -0
  72. data/spec/foodcritic/coverage/assets/0.10.0/application.js +1707 -0
  73. data/spec/foodcritic/coverage/assets/0.10.0/colorbox/border.png +0 -0
  74. data/spec/foodcritic/coverage/assets/0.10.0/colorbox/controls.png +0 -0
  75. data/spec/foodcritic/coverage/assets/0.10.0/colorbox/loading.gif +0 -0
  76. data/spec/foodcritic/coverage/assets/0.10.0/colorbox/loading_background.png +0 -0
  77. data/spec/foodcritic/coverage/assets/0.10.0/favicon_green.png +0 -0
  78. data/spec/foodcritic/coverage/assets/0.10.0/favicon_red.png +0 -0
  79. data/spec/foodcritic/coverage/assets/0.10.0/favicon_yellow.png +0 -0
  80. data/spec/foodcritic/coverage/assets/0.10.0/loading.gif +0 -0
  81. data/spec/foodcritic/coverage/assets/0.10.0/magnify.png +0 -0
  82. data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  83. data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  84. data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  85. data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  86. data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  87. data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  88. data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  89. data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  90. data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-icons_222222_256x240.png +0 -0
  91. data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  92. data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-icons_454545_256x240.png +0 -0
  93. data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-icons_888888_256x240.png +0 -0
  94. data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  95. data/spec/foodcritic/coverage/index.html +72 -0
  96. data/spec/foodcritic/linter_spec.rb +7 -6
  97. data/spec/regression/expected-output.txt +0 -12
  98. data/spec/spec_helper.rb +3 -1
  99. metadata +88 -6
  100. data/features/023_check_for_condition_around_resource.feature +0 -52
  101. data/lib/foodcritic/rules.rb +0 -852
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 47f475c9716a5e803b5bd2053fdc626e9188fe8c
4
- data.tar.gz: bbe14738574ad807ac48599579a97d600a5dbc5b
3
+ metadata.gz: d13edaa29dc5980c6783c28bdfa72c6ae5624ecd
4
+ data.tar.gz: 95e285806cc9168efa32ab6e1511e291bff66e3e
5
5
  SHA512:
6
- metadata.gz: 14843dbd1a39130a6cdaeebf63f377e4d6bbd99d57d4043e6e839819198ce0c45980901744631cd26df0bdf5c8465015c229505f600d8f41ac7f11798c50bd85
7
- data.tar.gz: 956f88ef2ba32f4d59c8c2ae2944ef7c2eb83e6c86c37744984e5be4de77fb3a558aeed84d596640294d32d6ec821b87b6001caa2e60d0243f0299512beb8f62
6
+ metadata.gz: b1d7d8da69d8092724ccc970aa9a236175af58bb2c76a77582e6792ae3732efc924b98496faefecc3f02be8ce8315f61a412f2b71e80916c066956a1e7f5b5e9
7
+ data.tar.gz: 22c4676382a67e8c685af190bd473f22cdb161397e84479f4fa76666e4f89fff60d64fc88d121e808d3bbf9a32aea9fa754a79f9232abe08553afc42bd9b8112
data/CHANGELOG.md CHANGED
@@ -1,6 +1,17 @@
1
1
  # Foodcritic Changelog:
2
2
 
3
- ## [10.0.0](https://github.com/acrmp/foodcritic/tree/v10.0.0) (2017-03-14)
3
+ ## [10.1.0](https://github.com/acrmp/foodcritic/tree/10.1.0) (2017-03-29)
4
+
5
+ [Full Changelog](https://github.com/acrmp/foodcritic/compare/v10.0.0...v10.1.0)
6
+
7
+ **Implemented enhancements:**
8
+
9
+ - Remove FC023 which is no longer considered best practice [#523](https://github.com/acrmp/foodcritic/pull/523) ([tas50](https://github.com/tas50))
10
+ - Add basic testing of the metadata_field api [#522](https://github.com/acrmp/foodcritic/pull/522) ([tas50](https://github.com/tas50))
11
+ - Add a more robust cookbook_base_path helper to the API [#520](https://github.com/acrmp/foodcritic/pull/520) ([tas50](https://github.com/tas50))
12
+ - Update various tags to better align the rules with the tag categories [#517](https://github.com/acrmp/foodcritic/pull/517) ([tas50](https://github.com/tas50))
13
+
14
+ ## [v10.0.0](https://github.com/acrmp/foodcritic/tree/v10.0.0) (2017-03-14)
4
15
 
5
16
  [Full Changelog](https://github.com/acrmp/foodcritic/compare/v9.0.0...v10.0.0)
6
17
 
data/Gemfile CHANGED
@@ -6,12 +6,12 @@ group :test do
6
6
  gem "aruba", "~> 0.5"
7
7
  gem "cucumber", ">= 2"
8
8
  gem "minitest", "~> 5.3"
9
+ gem "minitest-reporters"
9
10
  gem "simplecov", "~> 0.8"
11
+ gem "chefstyle", "~> 0.5"
10
12
  end
11
13
 
12
14
  group :development do
13
- gem "chef", "~> 12.1"
14
- gem "chefstyle", "~> 0.4"
15
15
  gem "ronn", "~> 0.7"
16
16
  end
17
17
 
@@ -4,12 +4,12 @@ Feature: Check for metadata existence
4
4
  As a developer
5
5
  I want to verify that the metadata file exist
6
6
 
7
- Scenario: Cookbook without metadata file
7
+ Scenario: Cookbook without metadata.rb file
8
8
  Given a cookbook that does not have defined metadata
9
9
  When I check the cookbook
10
10
  Then the non existing metadata warning 031 should be displayed against the metadata file
11
11
 
12
- Scenario: Cookbook with metadata file
12
+ Scenario: Cookbook with metadata.rb file
13
13
  Given a cookbook that has the default boilerplate metadata generated by knife
14
14
  When I check the cookbook
15
15
  Then the non existing metadata warning 031 should not be displayed against the metadata file
@@ -10,19 +10,19 @@ Feature: Choose rules to apply
10
10
  Then the warnings shown should be <warnings_shown>
11
11
 
12
12
  Examples:
13
- | cookbook_matches | tag_arguments | warnings_shown |
14
- | FC002,FC004,FC005 | | FC002,FC004,FC005 |
15
- | FC002 | -t FC002 | FC002 |
16
- | FC002,FC004,FC005 | --tags FC002 | FC002 |
17
- | FC002,FC004,FC005 | --tags fc002 | |
18
- | FC002,FC004,FC005 | --tags FC006 | |
19
- | FC002,FC004,FC005 | --tags ~FC002 | FC004,FC005 |
20
- | | --tags FC002 | |
21
- | FC002,FC004,FC005 | --tags @FC002 | |
22
- | FC002,FC004,FC005 | --tags style | FC002,FC004 |
23
- | FC002,FC004,FC005 | --tags FC002 --tags FC004 | |
24
- | FC002,FC004,FC005 | --tags style --tags services | FC004 |
25
- | FC002,FC004,FC005 | --tags style,services | FC002,FC004 |
13
+ | cookbook_matches | tag_arguments | warnings_shown |
14
+ | FC002,FC004,FC005 | | FC002,FC004,FC005 |
15
+ | FC002 | -t FC002 | FC002 |
16
+ | FC002,FC004,FC005 | --tags FC002 | FC002 |
17
+ | FC002,FC004,FC005 | --tags fc002 | |
18
+ | FC002,FC004,FC005 | --tags FC006 | |
19
+ | FC002,FC004,FC005 | --tags ~FC002 | FC004,FC005 |
20
+ | | --tags FC002 | |
21
+ | FC002,FC004,FC005 | --tags @FC002 | |
22
+ | FC002,FC004,FC005 | --tags style | FC002 |
23
+ | FC002,FC004,FC005 | --tags FC002 --tags FC004 | |
24
+ | FC002,FC004,FC005 | --tags portability --tags services | FC004 |
25
+ | FC002,FC004,FC005 | --tags style,services,portability | FC002,FC004 |
26
26
 
27
27
  Scenario Outline: Specified tags in cookbook .foodcritic file
28
28
  Given a cookbook that matches rules <cookbook_matches>
@@ -31,17 +31,17 @@ Feature: Choose rules to apply
31
31
  Then the warnings shown should be <warnings_shown>
32
32
 
33
33
  Examples:
34
- | cookbook_matches | tag_file | tag_arguments | warnings_shown |
35
- | FC002,FC004 | | | FC002,FC004 |
36
- | FC002 | FC002 | | FC002 |
37
- | FC002 | ~FC002 | --tags FC002 | FC002 |
38
- | FC002 | fc002 | | |
39
- | FC002,FC004 | FC005 | | |
40
- | FC002,FC004 | FC005 | -t FC002 | FC002 |
41
- | FC002,FC004 | ~FC002 | | FC004 |
42
- | FC002,FC004 | ~FC002 | -t FC002 | FC002 |
43
- | | FC002 | | |
44
- | FC002,FC004 | @FC002 | | |
45
- | FC002,FC004 | style | | FC002,FC004 |
46
- | FC002,FC004 | FC002 | | |
47
- | FC002,FC004 | style,services | | FC002,FC004 |
34
+ | cookbook_matches | tag_file | tag_arguments | warnings_shown |
35
+ | FC002,FC004 | | | FC002,FC004 |
36
+ | FC002 | FC002 | | FC002 |
37
+ | FC002 | ~FC002 | --tags FC002 | FC002 |
38
+ | FC002 | fc002 | | |
39
+ | FC002,FC004 | FC005 | | |
40
+ | FC002,FC004 | FC005 | -t FC002 | FC002 |
41
+ | FC002,FC004 | ~FC002 | | FC004 |
42
+ | FC002,FC004 | ~FC002 | -t FC002 | FC002 |
43
+ | | FC002 | | |
44
+ | FC002,FC004 | @FC002 | | |
45
+ | FC002,FC004 | style | | FC002 |
46
+ | FC002,FC004 | FC002 | | |
47
+ | FC002,FC004 | style,portability | | FC002,FC004 |
@@ -18,8 +18,8 @@ Feature: Continuous Integration Support
18
18
  Examples:
19
19
  | cookbook_matches | tag_arguments | warnings_shown | build_status |
20
20
  | FC002,FC004 | | FC002,FC004 | failed |
21
- | FC002,FC004 | -t style | FC002,FC004 | failed |
22
- | FC002,FC004 | -t style -f ~any | FC002,FC004 | successful |
21
+ | FC002,FC004 | -t style | FC002 | failed |
22
+ | FC002,FC004 | -t style -f ~any | FC002 | successful |
23
23
  | FC002,FC004 | -f FC005 | FC002,FC004 | successful |
24
24
  | FC002,FC004 | -f FC004 | FC002,FC004 | failed |
25
25
  | FC002,FC004 | --epic-fail FC002 | FC002,FC004 | failed |
@@ -35,7 +35,7 @@ module FoodCritic
35
35
  "FC019" => "Access node attributes in a consistent manner",
36
36
  "FC021" => "Resource condition in provider may not behave as expected",
37
37
  "FC022" => "Resource condition within loop may not behave as expected",
38
- "FC023" => "Prefer conditional attributes",
38
+ # FC023 was yanked and is considered reserved, do not reuse it
39
39
  "FC024" => "Consider adding platform equivalents",
40
40
  "FC025" => "Prefer chef_gem to compile-time gem install",
41
41
  "FC026" => "Conditional execution block attribute contains only string",
@@ -43,7 +43,7 @@ module FoodCritic
43
43
  "FC028" => "Incorrect #platform? usage",
44
44
  "FC029" => "No leading cookbook name in recipe metadata",
45
45
  "FC030" => "Cookbook contains debugger breakpoints",
46
- "FC031" => "Cookbook without metadata file",
46
+ "FC031" => "Cookbook without metadata.rb file",
47
47
  "FC032" => "Invalid notification timing",
48
48
  "FC033" => "Missing template",
49
49
  "FC034" => "Unused template variables",
@@ -33,7 +33,11 @@ module FoodCritic
33
33
  end
34
34
 
35
35
  # Does the specified recipe check for Chef Solo?
36
+ #
37
+ # @deprecated chef-solo functionality in Chef has been replaced with local-mode
38
+ # so this helper is no longer necessary and will be removed in Foodcritic 11.0
36
39
  def checks_for_chef_solo?(ast)
40
+ puts "the checks_for_chef_solo? helper is deprecated and will be removed from the next release of Foodcritic"
37
41
  raise_unless_xpath!(ast)
38
42
  # TODO: This expression is too loose, but also will fail to match other
39
43
  # types of conditionals.
@@ -51,10 +55,13 @@ module FoodCritic
51
55
  end == %w{Chef Config}
52
56
  end
53
57
 
54
- # Is the
55
- # [chef-solo-search library](https://github.com/edelight/chef-solo-search)
56
- # available?
58
+ # Is the chef-solo-search library available?
59
+ #
60
+ # @see https://github.com/edelight/chef-solo-search
61
+ # @deprecated chef-solo functionality in Chef has been replaced with local-mode
62
+ # so this helper is no longer necessary and will be removed in Foodcritic 11.0
57
63
  def chef_solo_search_supported?(recipe_path)
64
+ puts "the chef_solo_search_supported? helper is deprecated and will be removed from the next release of Foodcritic"
58
65
  return false if recipe_path.nil? || !File.exist?(recipe_path)
59
66
 
60
67
  # Look for the chef-solo-search library.
@@ -75,6 +82,25 @@ module FoodCritic
75
82
  end
76
83
  end
77
84
 
85
+ # The absolute path of a cookbook from the specified file.
86
+ #
87
+ # @author Tim Smith - tsmith@chef.io
88
+ # @since 11.0
89
+ # @param file [String, Pathname] relative or absolute path to a file in the cookbook
90
+ # @return [String] the absolute path to the base of the cookbook
91
+ def cookbook_base_path(file)
92
+ file = File.expand_path(file) # make sure we get an absolute path
93
+ file = File.dirname(file) unless File.directory?(file) # get the dir only
94
+
95
+ # get list of items in the dir and intersect with metadata array.
96
+ # until we get an interfact (we have a metadata) walk up the dir structure
97
+ until (Dir.entries(file) & %w{metadata.rb metadata.json}).any?
98
+ file = File.dirname(file)
99
+ end
100
+
101
+ file
102
+ end
103
+
78
104
  # Support function to retrieve a metadata field
79
105
  def metadata_field(file, field)
80
106
  until (file.split(File::SEPARATOR) & standard_cookbook_subdirs).empty?
@@ -157,7 +157,7 @@ module FoodCritic
157
157
  end
158
158
 
159
159
  def load_rules!(options)
160
- rule_files = [File.join(File.dirname(__FILE__), "rules.rb")]
160
+ rule_files = Dir.glob(File.join(File.dirname(__FILE__), "rules", "*"))
161
161
  rule_files << options[:include_rules]
162
162
  rule_files << rule_files_in_gems if options[:search_gems]
163
163
  @rules = RuleDsl.load(rule_files.flatten.compact, chef_version)
@@ -0,0 +1,7 @@
1
+ rule "FC001",
2
+ "Use strings in preference to symbols to access node attributes" do
3
+ tags %w{style attributes}
4
+ recipe do |ast|
5
+ attribute_access(ast, type: :symbol)
6
+ end
7
+ end
@@ -0,0 +1,8 @@
1
+ rule "FC002", "Avoid string interpolation where not required" do
2
+ tags %w{style strings}
3
+ recipe do |ast|
4
+ ast.xpath(%q{//*[self::string_literal | self::assoc_new]/string_add[
5
+ count(descendant::string_embexpr) = 1 and
6
+ count(string_add) = 0]})
7
+ end
8
+ end
@@ -0,0 +1,12 @@
1
+ rule "FC004", "Use a service resource to start and stop services" do
2
+ tags %w{portability services}
3
+ recipe do |ast|
4
+ find_resources(ast, type: "execute").find_all do |cmd|
5
+ cmd_str = (resource_attribute(cmd, "command") || resource_name(cmd)).to_s
6
+ (cmd_str.include?("/etc/init.d") || ["service ", "/sbin/service ",
7
+ "start ", "stop ", "invoke-rc.d "].any? do |service_cmd|
8
+ cmd_str.start_with?(service_cmd)
9
+ end) && %w{start stop restart reload}.any? { |a| cmd_str.include?(a) }
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,29 @@
1
+ rule "FC005", "Avoid repetition of resource declarations" do
2
+ tags %w{style}
3
+ recipe do |ast|
4
+ resources = find_resources(ast).map do |res|
5
+ resource_attributes(res).merge({ type: resource_type(res),
6
+ ast: res })
7
+ end.chunk do |res|
8
+ res[:type] +
9
+ res[:ast].xpath("ancestor::*[self::if | self::unless | self::elsif |
10
+ self::else | self::when | self::method_add_block/call][position() = 1]/
11
+ descendant::pos[position() = 1]").to_s +
12
+ res[:ast].xpath("ancestor::method_add_block/command[
13
+ ident/@value='action']/args_add_block/descendant::ident/@value").to_s
14
+ end.reject { |res| res[1].size < 3 }
15
+ resources.map do |cont_res|
16
+ first_resource = cont_res[1][0][:ast]
17
+ # we have contiguous resources of the same type, but do they share the
18
+ # same attributes?
19
+ sorted_atts = cont_res[1].map do |atts|
20
+ atts.delete_if { |k| k == :ast }.to_a.sort do |x, y|
21
+ x.first.to_s <=> y.first.to_s
22
+ end
23
+ end
24
+ first_resource if sorted_atts.all? do |att|
25
+ (att - sorted_atts.inject { |atts, a| atts & a }).length == 1
26
+ end
27
+ end.compact
28
+ end
29
+ end
@@ -0,0 +1,11 @@
1
+ rule "FC006", "Mode should be quoted or fully specified when "\
2
+ "setting file permissions" do
3
+ tags %w{correctness files}
4
+ recipe do |ast|
5
+ ast.xpath(%q{//ident[@value='mode']/parent::command/
6
+ descendant::int[string-length(@value) < 5
7
+ and not(starts-with(@value, "0")
8
+ and string-length(@value) = 4)][count(ancestor::aref) = 0]/
9
+ ancestor::method_add_block})
10
+ end
11
+ end
@@ -0,0 +1,19 @@
1
+ rule "FC007", "Ensure recipe dependencies are reflected in cookbook metadata" do
2
+ tags %w{correctness metadata}
3
+ recipe do |ast, filename|
4
+ metadata_path = Pathname.new(
5
+ File.join(File.dirname(filename), "..", "metadata.rb")).cleanpath
6
+ next unless File.exist? metadata_path
7
+ actual_included = included_recipes(ast, with_partial_names: false)
8
+ undeclared = actual_included.keys.map do |recipe|
9
+ recipe.split("::").first
10
+ end - [cookbook_name(filename)] -
11
+ declared_dependencies(read_ast(metadata_path))
12
+ actual_included.map do |recipe, include_stmts|
13
+ if undeclared.include?(recipe) ||
14
+ undeclared.any? { |u| recipe.start_with?("#{u}::") }
15
+ include_stmts
16
+ end
17
+ end.flatten.compact
18
+ end
19
+ end
@@ -0,0 +1,12 @@
1
+ rule "FC008", "Generated cookbook metadata needs updating" do
2
+ tags %w{metadata supermarket}
3
+ metadata do |ast, filename|
4
+ {
5
+ "maintainer" => "YOUR_COMPANY_NAME",
6
+ "maintainer_email" => "YOUR_EMAIL",
7
+ }.map do |field, value|
8
+ ast.xpath(%Q{//command[ident/@value='#{field}']/
9
+ descendant::tstring_content[@value='#{value}']})
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,18 @@
1
+ rule "FC009", "Resource attribute not recognised" do
2
+ tags %w{correctness}
3
+ recipe do |ast|
4
+ matches = []
5
+ resource_attributes_by_type(ast).each do |type, resources|
6
+ resources.each do |resource|
7
+ resource.keys.map(&:to_sym).reject do |att|
8
+ resource_attribute?(type.to_sym, att)
9
+ end.each do |invalid_att|
10
+ matches << find_resources(ast, type: type).find do |res|
11
+ resource_attributes(res).include?(invalid_att.to_s)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ matches
17
+ end
18
+ end
@@ -0,0 +1,7 @@
1
+ rule "FC010", "Invalid search syntax" do
2
+ tags %w{correctness search}
3
+ recipe do |ast|
4
+ # This only works for literal search strings
5
+ literal_searches(ast).reject { |search| valid_query?(search["value"]) }
6
+ end
7
+ end
@@ -0,0 +1,8 @@
1
+ rule "FC011", "Missing README in markdown format" do
2
+ tags %w{readme supermarket}
3
+ cookbook do |filename|
4
+ unless File.exist?(File.join(filename, "README.md"))
5
+ [file_match(File.join(filename, "README.md"))]
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ rule "FC012", "Use Markdown for README rather than RDoc" do
2
+ tags %w{supermarket readme}
3
+ cookbook do |filename|
4
+ if File.exist?(File.join(filename, "README.rdoc"))
5
+ [file_match(File.join(filename, "README.rdoc"))]
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,10 @@
1
+ rule "FC013", "Use file_cache_path rather than hard-coding tmp paths" do
2
+ tags %w{files portability}
3
+ recipe do |ast|
4
+ find_resources(ast, type: "remote_file").find_all do |download|
5
+ path = (resource_attribute(download, "path") ||
6
+ resource_name(download)).to_s
7
+ path.start_with?("/tmp/")
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ rule "FC014", "Consider extracting long ruby_block to library" do
2
+ tags %w{style libraries}
3
+ recipe do |ast|
4
+ find_resources(ast, type: "ruby_block").find_all do |rb|
5
+ lines = rb.xpath("descendant::fcall[ident/@value='block']/../../
6
+ descendant::*[@line]/@line").map { |n| n.value.to_i }.sort
7
+ (!lines.empty?) && (lines.last - lines.first) > 15
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,8 @@
1
+ rule "FC015", "Consider converting definition to a Custom Resource" do
2
+ tags %w{style definitions}
3
+ cookbook do |dir|
4
+ Dir[File.join(dir, "definitions", "*.rb")].reject do |entry|
5
+ [".", ".."].include? entry
6
+ end.map { |entry| file_match(entry) }
7
+ end
8
+ end
@@ -0,0 +1,10 @@
1
+ rule "FC016", "LWRP does not declare a default action" do
2
+ tags %w{correctness lwrp}
3
+ resource do |ast, filename|
4
+ unless ["//ident/@value='default_action'",
5
+ "//def/bodystmt/descendant::assign/
6
+ var_field/ivar/@value='@action'"].any? { |expr| ast.xpath(expr) }
7
+ [file_match(filename)]
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,29 @@
1
+ rule "FC017", "LWRP does not notify when updated" do
2
+ tags %w{correctness lwrp}
3
+ provider do |ast, filename|
4
+
5
+ use_inline_resources = !ast.xpath('//*[self::vcall or self::var_ref]/ident
6
+ [@value="use_inline_resources"]').empty?
7
+
8
+ unless use_inline_resources
9
+ actions = ast.xpath('//method_add_block/command[ident/@value="action"]/
10
+ args_add_block/descendant::symbol/ident')
11
+
12
+ actions.reject do |action|
13
+ blk = action.xpath('ancestor::command[1]/
14
+ following-sibling::*[self::do_block or self::brace_block]')
15
+ empty = !blk.xpath("stmts_add/void_stmt").empty?
16
+ converge_by = !blk.xpath('descendant::*[self::command or self::fcall]
17
+ /ident[@value="converge_by"]').empty?
18
+
19
+ updated_by_last_action = !blk.xpath('descendant::*[self::call or
20
+ self::command_call]/*[self::vcall or self::var_ref/ident/
21
+ @value="new_resource"]/../ident[@value="updated_by_last_action"]
22
+ ').empty?
23
+
24
+ empty || converge_by || updated_by_last_action
25
+ end
26
+ end
27
+
28
+ end
29
+ end