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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -1
- data/Gemfile +2 -2
- data/features/031_check_for_metadata_existence.feature +2 -2
- data/features/choose_rules_to_apply.feature +27 -27
- data/features/continuous_integration_support.feature +2 -2
- data/features/support/command_helpers.rb +2 -2
- data/lib/foodcritic/api.rb +29 -3
- data/lib/foodcritic/linter.rb +1 -1
- data/lib/foodcritic/rules/fc001.rb +7 -0
- data/lib/foodcritic/rules/fc002.rb +8 -0
- data/lib/foodcritic/rules/fc004.rb +12 -0
- data/lib/foodcritic/rules/fc005.rb +29 -0
- data/lib/foodcritic/rules/fc006.rb +11 -0
- data/lib/foodcritic/rules/fc007.rb +19 -0
- data/lib/foodcritic/rules/fc008.rb +12 -0
- data/lib/foodcritic/rules/fc009.rb +18 -0
- data/lib/foodcritic/rules/fc010.rb +7 -0
- data/lib/foodcritic/rules/fc011.rb +8 -0
- data/lib/foodcritic/rules/fc012.rb +8 -0
- data/lib/foodcritic/rules/fc013.rb +10 -0
- data/lib/foodcritic/rules/fc014.rb +10 -0
- data/lib/foodcritic/rules/fc015.rb +8 -0
- data/lib/foodcritic/rules/fc016.rb +10 -0
- data/lib/foodcritic/rules/fc017.rb +29 -0
- data/lib/foodcritic/rules/fc018.rb +9 -0
- data/lib/foodcritic/rules/fc019.rb +34 -0
- data/lib/foodcritic/rules/fc021.rb +13 -0
- data/lib/foodcritic/rules/fc022.rb +33 -0
- data/lib/foodcritic/rules/fc024.rb +31 -0
- data/lib/foodcritic/rules/fc025.rb +17 -0
- data/lib/foodcritic/rules/fc026.rb +14 -0
- data/lib/foodcritic/rules/fc027.rb +9 -0
- data/lib/foodcritic/rules/fc028.rb +8 -0
- data/lib/foodcritic/rules/fc029.rb +14 -0
- data/lib/foodcritic/rules/fc030.rb +11 -0
- data/lib/foodcritic/rules/fc031.rb +8 -0
- data/lib/foodcritic/rules/fc032.rb +15 -0
- data/lib/foodcritic/rules/fc033.rb +26 -0
- data/lib/foodcritic/rules/fc034.rb +31 -0
- data/lib/foodcritic/rules/fc037.rb +14 -0
- data/lib/foodcritic/rules/fc038.rb +17 -0
- data/lib/foodcritic/rules/fc039.rb +19 -0
- data/lib/foodcritic/rules/fc040.rb +12 -0
- data/lib/foodcritic/rules/fc041.rb +9 -0
- data/lib/foodcritic/rules/fc042.rb +6 -0
- data/lib/foodcritic/rules/fc043.rb +8 -0
- data/lib/foodcritic/rules/fc044.rb +22 -0
- data/lib/foodcritic/rules/fc045.rb +13 -0
- data/lib/foodcritic/rules/fc046.rb +8 -0
- data/lib/foodcritic/rules/fc047.rb +16 -0
- data/lib/foodcritic/rules/fc048.rb +13 -0
- data/lib/foodcritic/rules/fc049.rb +10 -0
- data/lib/foodcritic/rules/fc050.rb +8 -0
- data/lib/foodcritic/rules/fc051.rb +15 -0
- data/lib/foodcritic/rules/fc052.rb +6 -0
- data/lib/foodcritic/rules/fc053.rb +6 -0
- data/lib/foodcritic/rules/fc055.rb +6 -0
- data/lib/foodcritic/rules/fc056.rb +6 -0
- data/lib/foodcritic/rules/fc057.rb +8 -0
- data/lib/foodcritic/rules/fc058.rb +9 -0
- data/lib/foodcritic/rules/fc059.rb +10 -0
- data/lib/foodcritic/rules/fc060.rb +10 -0
- data/lib/foodcritic/rules/fc061.rb +10 -0
- data/lib/foodcritic/rules/fc062.rb +6 -0
- data/lib/foodcritic/rules/fc063.rb +8 -0
- data/lib/foodcritic/rules/fc064.rb +6 -0
- data/lib/foodcritic/rules/fc065.rb +6 -0
- data/lib/foodcritic/version.rb +1 -1
- data/spec/foodcritic/api_spec.rb +62 -0
- data/spec/foodcritic/coverage/assets/0.10.0/application.css +799 -0
- data/spec/foodcritic/coverage/assets/0.10.0/application.js +1707 -0
- data/spec/foodcritic/coverage/assets/0.10.0/colorbox/border.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/colorbox/controls.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/colorbox/loading.gif +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/colorbox/loading_background.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/favicon_green.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/favicon_red.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/favicon_yellow.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/loading.gif +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/magnify.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/spec/foodcritic/coverage/index.html +72 -0
- data/spec/foodcritic/linter_spec.rb +7 -6
- data/spec/regression/expected-output.txt +0 -12
- data/spec/spec_helper.rb +3 -1
- metadata +88 -6
- data/features/023_check_for_condition_around_resource.feature +0 -52
- data/lib/foodcritic/rules.rb +0 -852
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d13edaa29dc5980c6783c28bdfa72c6ae5624ecd
|
|
4
|
+
data.tar.gz: 95e285806cc9168efa32ab6e1511e291bff66e3e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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.
|
|
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
|
|
14
|
-
| FC002,FC004,FC005 |
|
|
15
|
-
| FC002 | -t FC002
|
|
16
|
-
| FC002,FC004,FC005 | --tags FC002
|
|
17
|
-
| FC002,FC004,FC005 | --tags fc002
|
|
18
|
-
| FC002,FC004,FC005 | --tags FC006
|
|
19
|
-
| FC002,FC004,FC005 | --tags ~FC002
|
|
20
|
-
| | --tags FC002
|
|
21
|
-
| FC002,FC004,FC005 | --tags @FC002
|
|
22
|
-
| FC002,FC004,FC005 | --tags style
|
|
23
|
-
| FC002,FC004,FC005 | --tags FC002 --tags FC004
|
|
24
|
-
| FC002,FC004,FC005 | --tags
|
|
25
|
-
| FC002,FC004,FC005 | --tags style,services
|
|
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
|
|
35
|
-
| FC002,FC004 |
|
|
36
|
-
| FC002 | FC002
|
|
37
|
-
| FC002 | ~FC002
|
|
38
|
-
| FC002 | fc002
|
|
39
|
-
| FC002,FC004 | FC005
|
|
40
|
-
| FC002,FC004 | FC005
|
|
41
|
-
| FC002,FC004 | ~FC002
|
|
42
|
-
| FC002,FC004 | ~FC002
|
|
43
|
-
| | FC002
|
|
44
|
-
| FC002,FC004 | @FC002
|
|
45
|
-
| FC002,FC004 | style
|
|
46
|
-
| FC002,FC004 | FC002
|
|
47
|
-
| FC002,FC004 | style,
|
|
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
|
|
22
|
-
| FC002,FC004 | -t style -f ~any | FC002
|
|
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
|
-
|
|
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",
|
data/lib/foodcritic/api.rb
CHANGED
|
@@ -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
|
-
#
|
|
56
|
-
#
|
|
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?
|
data/lib/foodcritic/linter.rb
CHANGED
|
@@ -157,7 +157,7 @@ module FoodCritic
|
|
|
157
157
|
end
|
|
158
158
|
|
|
159
159
|
def load_rules!(options)
|
|
160
|
-
rule_files =
|
|
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,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,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,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
|