foodcritic 10.0.0 → 10.1.0

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