foodcritic 10.4.1 → 11.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +26 -1
- data/Rakefile +7 -1
- data/features/step_definitions/cookbook_steps.rb +0 -96
- data/lib/foodcritic/api.rb +77 -79
- data/lib/foodcritic/rules/fc008.rb +2 -2
- data/lib/foodcritic/rules/fc029.rb +1 -1
- data/lib/foodcritic/rules/fc042.rb +1 -1
- data/lib/foodcritic/rules/fc052.rb +1 -1
- data/lib/foodcritic/rules/fc053.rb +1 -1
- data/lib/foodcritic/rules/fc057.rb +1 -1
- data/lib/foodcritic/rules/fc058.rb +1 -1
- data/lib/foodcritic/rules/fc060.rb +1 -1
- data/lib/foodcritic/rules/fc061.rb +3 -3
- data/lib/foodcritic/rules/fc063.rb +1 -2
- data/lib/foodcritic/rules/fc069.rb +2 -4
- data/lib/foodcritic/rules/fc078.rb +2 -3
- data/lib/foodcritic/rules/fc079.rb +6 -0
- data/lib/foodcritic/rules/fc080.rb +6 -0
- data/lib/foodcritic/rules/fc081.rb +6 -0
- data/lib/foodcritic/rules/fc082.rb +9 -0
- data/lib/foodcritic/rules/fc083.rb +6 -0
- data/lib/foodcritic/rules/fc084.rb +9 -0
- data/lib/foodcritic/rules/fc085.rb +12 -0
- data/lib/foodcritic/version.rb +1 -1
- data/spec/functional/fc007_spec.rb +127 -0
- data/spec/functional/fc049_spec.rb +56 -0
- data/spec/functional/fc050_spec.rb +85 -0
- data/spec/functional/fc066_spec.rb +20 -0
- data/spec/functional/fc069_spec.rb +15 -0
- data/spec/functional/fc070_spec.rb +9 -0
- data/spec/functional/fc076_spec.rb +2 -2
- data/spec/functional/fc077_spec.rb +2 -2
- data/spec/functional/fc078_spec.rb +14 -4
- data/spec/functional/fc079_spec.rb +21 -0
- data/spec/functional/fc080_spec.rb +68 -0
- data/spec/functional/fc081_spec.rb +25 -0
- data/spec/functional/fc082_spec.rb +23 -0
- data/spec/functional/fc083_spec.rb +34 -0
- data/spec/functional/fc084_spec.rb +49 -0
- data/spec/functional/fc085_spec.rb +58 -0
- data/spec/regression/expected/aix.txt +1 -0
- data/spec/regression/expected/aws.txt +3 -0
- data/spec/regression/expected/chef-client.txt +2 -0
- data/spec/regression/expected/chef.txt +67 -0
- data/spec/regression/expected/database.txt +1 -0
- data/spec/regression/expected/drbd.txt +1 -0
- data/spec/regression/expected/jetty.txt +1 -0
- data/spec/regression/expected/mysql.txt +4 -0
- data/spec/regression/expected/openssh.txt +1 -0
- data/spec/regression/expected/postfix.txt +1 -0
- data/spec/regression/expected/rsyslog.txt +1 -0
- data/spec/regression/expected/smokeping.txt +1 -0
- data/spec/regression/expected/sql_server.txt +1 -0
- data/spec/regression/expected/ufw.txt +1 -0
- data/spec/regression/expected/users.txt +2 -0
- data/spec/regression/expected/xml.txt +1 -0
- data/spec/regression/expected/yum.txt +0 -1
- data/spec/regression/regression_spec.rb +2 -2
- data/spec/unit/api_spec.rb +130 -149
- metadata +20 -32
- data/features/007_check_for_undeclared_recipe_dependencies.feature +0 -59
- data/features/049_check_for_role_name_mismatch_with_file_name.feature +0 -31
- data/features/050_check_for_invalid_name.feature +0 -33
- data/man/foodcritic.1 +0 -81
- data/spec/foodcritic/coverage/assets/0.10.0/application.css +0 -799
- data/spec/foodcritic/coverage/assets/0.10.0/application.js +0 -1707
- 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 +0 -72
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c5c06e37056b5db3985f94fea5101961eeec4164
|
4
|
+
data.tar.gz: 610fe94a45ecd4412e77ac18abcd66129fe3d75d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6471cb860d9e922e4ee238b9b88647cb68c7c161123d7ad223dfec4733b3c741683db9173889a19f524f8269ae223483a3aec21eaaef020ac3681942f890efe4
|
7
|
+
data.tar.gz: 31ba9be090cafd5935d660ed91456da49a8efbff002f3301ec5e81466b2c9295a7a07a4982b1b58334adb05da5ed3419de54faaba99ebdd3303173ecdcb6978f
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,31 @@
|
|
1
1
|
# Foodcritic Changelog:
|
2
2
|
|
3
|
-
## [
|
3
|
+
## [11.0.0](https://github.com/acrmp/foodcritic/tree/v11.0.0) (2017-04-24)
|
4
|
+
|
5
|
+
[Full Changelog](https://github.com/acrmp/foodcritic/compare/v10.4.1...v11.0.0)
|
6
|
+
|
7
|
+
**Implemented enhancements:**
|
8
|
+
|
9
|
+
- Added `FC079` to detect the usage of the easy_install_package resource which is deprecated in Chef 13\. Tags: deprecated, chef13.
|
10
|
+
- Added `FC080` to detect user resources that include the supports property, which is deprecated in Chef 13\. Tags: deprecated, chef13.
|
11
|
+
- Added `FC081` to detect a cookbook that depends on the partial_search cookbook as partial search functionality is built into Chef 12 and later. Tags: chef12.
|
12
|
+
- Added `FC082` to detect the usage of node.set and node.set_unless which will be removed in Chef 14\. Tags: deprecated, chef14.
|
13
|
+
- Added `FC083` to detect execute resources that include the path property, which is deprecated in Chef 12\. Tags: deprecated, chef13.
|
14
|
+
- Added `FC084` to detect usage of the deprecated Chef::REST class. Tags: deprecated, chef13.
|
15
|
+
- Added `FC085` to detect usage of new_resource.updated_by_last_action to converge resources. Tags: deprecated, chef13.
|
16
|
+
- Updated and refactored API methods `declared_dependencies`, `supported_platforms`, and `word_list_values`
|
17
|
+
- Deprecated API methods `checks_for_chef_solo` and `chef_solo_search_supported?` have been removed.
|
18
|
+
- Added a new API method `json_file_to_hash` for loading json files as a hash.
|
19
|
+
- Added a new rake command to run the regression test on just a single cookbook
|
20
|
+
|
21
|
+
**Fixed bugs:**
|
22
|
+
|
23
|
+
- Multiple rules have been rewritten to use Foodcritic APIs instead of using XPATH queries directly. This avoids false positives created by overly simplistic queries.
|
24
|
+
- Fixed FC069 to skip if the license metadata is any formatting of 'All Rights Reserved'.
|
25
|
+
- Added the `license` and `supermarket` tag to FC078.
|
26
|
+
- Updated the `field` and `field_value` API methods to correctly recognize additional formats of data in the metdata.
|
27
|
+
|
28
|
+
## [10.4.1](https://github.com/acrmp/foodcritic/tree/v10.4.1) (2017-04-17)
|
4
29
|
|
5
30
|
[Full Changelog](https://github.com/acrmp/foodcritic/compare/v10.4.0...v10.4.1)
|
6
31
|
|
data/Rakefile
CHANGED
@@ -10,7 +10,7 @@ RSpec::Core::RakeTask.new(:spec, :tag) do |t, args|
|
|
10
10
|
a << "--format #{ENV['CI'] ? 'documentation' : 'Fuubar'}"
|
11
11
|
a << "--backtrace" if ENV["DEBUG"]
|
12
12
|
a << "--seed #{ENV['SEED']}" if ENV["SEED"]
|
13
|
-
a << "--tag ~regression" unless ENV["CI"] || args[:tag]
|
13
|
+
a << "--tag ~regression" unless ENV["CI"] || args[:tag].to_s =~ /regression/
|
14
14
|
a << "--tag #{args[:tag]}" if args[:tag]
|
15
15
|
end.join(" ")
|
16
16
|
end
|
@@ -65,3 +65,9 @@ task :regen_regression do
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
end
|
68
|
+
|
69
|
+
desc "Run one regression test (or all of them)"
|
70
|
+
task :regression, [:cookbook] do |t, args|
|
71
|
+
tag = args[:cookbook] ? "regression_#{args[:cookbook]}" : "regression"
|
72
|
+
Rake::Task["spec"].invoke(tag)
|
73
|
+
end
|
@@ -409,61 +409,6 @@ Given 'a cookbook recipe that has a confusingly named local variable "default"'
|
|
409
409
|
}
|
410
410
|
end
|
411
411
|
|
412
|
-
Given /^a cookbook recipe that includes a local recipe(.*)$/ do |diff_name|
|
413
|
-
cookbook = diff_name.empty? ? "example" : "foo"
|
414
|
-
write_recipe %Q{
|
415
|
-
include_recipe '#{cookbook}::server'
|
416
|
-
}
|
417
|
-
write_metadata %Q{
|
418
|
-
name '#{cookbook}'
|
419
|
-
}
|
420
|
-
end
|
421
|
-
|
422
|
-
Given /^a cookbook recipe that includes a recipe name from an( embedded)? expression(.*)$/ do |embedded, expr|
|
423
|
-
if embedded
|
424
|
-
write_recipe %Q{
|
425
|
-
include_recipe "#{expr.strip}"
|
426
|
-
}
|
427
|
-
else
|
428
|
-
write_recipe %q{
|
429
|
-
include_recipe node['foo']['bar']
|
430
|
-
}
|
431
|
-
end
|
432
|
-
|
433
|
-
write_metadata %q{
|
434
|
-
depends "foo"
|
435
|
-
}
|
436
|
-
end
|
437
|
-
|
438
|
-
Given /^a cookbook recipe that includes a(n un| )?declared recipe dependency(?: {0,1})(unscoped)?( with parentheses)?$/ do |undeclared, unscoped, parens|
|
439
|
-
recipe_with_dependency(:is_declared => undeclared.strip.empty?,
|
440
|
-
:is_scoped => unscoped.nil?, :parentheses => parens)
|
441
|
-
end
|
442
|
-
|
443
|
-
Given "a cookbook recipe that includes both declared and undeclared recipe dependencies" do
|
444
|
-
write_recipe %q{
|
445
|
-
include_recipe "foo::default"
|
446
|
-
include_recipe "bar::default"
|
447
|
-
file "/tmp/something" do
|
448
|
-
action :delete
|
449
|
-
end
|
450
|
-
include_recipe "baz::default"
|
451
|
-
}
|
452
|
-
write_metadata %q{
|
453
|
-
['foo', 'bar'].each{|cbk| depends cbk}
|
454
|
-
}
|
455
|
-
end
|
456
|
-
|
457
|
-
Given "a cookbook that uses the include_recipe shorthand syntax" do
|
458
|
-
write_recipe %q{
|
459
|
-
include_recipe "::some_recipe"
|
460
|
-
}
|
461
|
-
end
|
462
|
-
|
463
|
-
Given /^a cookbook recipe that includes several declared recipe dependencies - (brace|block)$/ do |brace_or_block|
|
464
|
-
cookbook_declares_dependencies(brace_or_block.to_sym)
|
465
|
-
end
|
466
|
-
|
467
412
|
Given /a cookbook recipe that (install|upgrade)s (a gem|multiple gems)(.*)$/ do |action, arity, approach|
|
468
413
|
if arity == "a gem"
|
469
414
|
if approach.empty?
|
@@ -942,12 +887,6 @@ Given /^a cookbook that does not contain a definition and has (no|a) definitions
|
|
942
887
|
}
|
943
888
|
end
|
944
889
|
|
945
|
-
Given "a cookbook that does not have defined metadata" do
|
946
|
-
write_recipe %q{
|
947
|
-
include_recipe "foo::default"
|
948
|
-
}
|
949
|
-
end
|
950
|
-
|
951
890
|
Given /^a cookbook that has ([^ ]+) problems$/ do |problems|
|
952
891
|
cookbook_that_matches_rules(
|
953
892
|
problems.split(",").map do |problem|
|
@@ -1132,14 +1071,6 @@ Given /^a directory that contains a role file ([^ ]+) in (json|ruby) that define
|
|
1132
1071
|
role(:role_name => %Q{"#{role_name}"}, :file_name => file_name, :format => format.to_sym)
|
1133
1072
|
end
|
1134
1073
|
|
1135
|
-
Given "a directory that contains a ruby role that declares the role name more than once" do
|
1136
|
-
role(:role_name => ['"webserver"', '"apache"'], :file_name => "webserver.rb")
|
1137
|
-
end
|
1138
|
-
|
1139
|
-
Given "a directory that contains a ruby role with an expression as its name" do
|
1140
|
-
role(:role_name => '"#{foo}#{bar}"', :file_name => "webserver.rb")
|
1141
|
-
end
|
1142
|
-
|
1143
1074
|
Given /^a directory that contains an environment file (.*) in ruby that defines environment name (.*)$/ do |file_name, env_name|
|
1144
1075
|
environment(:environment_name => %Q{"#{env_name}"}, :file_name => "production.rb")
|
1145
1076
|
end
|
@@ -1411,10 +1342,6 @@ Given "the gems have been vendored" do
|
|
1411
1342
|
vendor_gems
|
1412
1343
|
end
|
1413
1344
|
|
1414
|
-
Given "the last role name declared does not match the containing filename" do
|
1415
|
-
|
1416
|
-
end
|
1417
|
-
|
1418
1345
|
Given /^the inferred template contains the expression (.*)$/ do |expr|
|
1419
1346
|
write_file "cookbooks/example/templates/default/config.conf.erb", %Q{
|
1420
1347
|
<%= #{expr} %>
|
@@ -1489,10 +1416,6 @@ Given "a recipe that tries to mask a systemd service" do
|
|
1489
1416
|
}
|
1490
1417
|
end
|
1491
1418
|
|
1492
|
-
Given /^a ruby environment file that defines an environment with name (.*)$/ do |env_name|
|
1493
|
-
environment(:environment_name => %Q{"#{env_name}"}, :file_name => "production.rb")
|
1494
|
-
end
|
1495
|
-
|
1496
1419
|
Given /^a ruby environment that triggers FC050 with comment (.*)$/ do |comment|
|
1497
1420
|
write_file "environments/production.rb", %Q{
|
1498
1421
|
name "Production (eu-west-1)" #{comment}
|
@@ -1500,10 +1423,6 @@ Given /^a ruby environment that triggers FC050 with comment (.*)$/ do |comment|
|
|
1500
1423
|
}.strip
|
1501
1424
|
end
|
1502
1425
|
|
1503
|
-
Given /^a ruby role file that defines a role with name (.*)$/ do |role_name|
|
1504
|
-
role(:role_name => [%Q{"#{role_name}"}], :file_name => "webserver.rb")
|
1505
|
-
end
|
1506
|
-
|
1507
1426
|
Given /^a ruby role that triggers FC049 with comment (.*)$/ do |comment|
|
1508
1427
|
write_file "roles/webserver.rb", %Q{
|
1509
1428
|
name "apache" #{comment}
|
@@ -1634,15 +1553,6 @@ When "I check the role directory" do
|
|
1634
1553
|
run_lint ["--no-progress", "-R", "roles"]
|
1635
1554
|
end
|
1636
1555
|
|
1637
|
-
When /^I check the role directory as a (default|cookbook|role) path$/ do |path_type|
|
1638
|
-
options = case path_type
|
1639
|
-
when "default" then ["--no-progress", "roles"]
|
1640
|
-
when "cookbook" then ["--no-progress", "-B", "roles"]
|
1641
|
-
when "role" then ["--no-progress", "-R", "roles"]
|
1642
|
-
end
|
1643
|
-
run_lint(options)
|
1644
|
-
end
|
1645
|
-
|
1646
1556
|
When "I check the webserver role only" do
|
1647
1557
|
run_lint ["--no-progress", "-R", "roles/webserver.rb"]
|
1648
1558
|
end
|
@@ -1945,12 +1855,6 @@ Then /^the template partials loop indefinitely warning 051 should (not )?be disp
|
|
1945
1855
|
:expect_warning => ! not_shown)
|
1946
1856
|
end
|
1947
1857
|
|
1948
|
-
Then "the undeclared dependency warning 007 should be displayed only for the undeclared dependencies" do
|
1949
|
-
expect_warning("FC007", :file => "recipes/default.rb", :line => 1, :expect_warning => false)
|
1950
|
-
expect_warning("FC007", :file => "recipes/default.rb", :line => 2, :expect_warning => false)
|
1951
|
-
expect_warning("FC007", :file => "recipes/default.rb", :line => 6, :expect_warning => true)
|
1952
|
-
end
|
1953
|
-
|
1954
1858
|
Then /^the unused template variables warning 034 should (not )?be displayed against the (?:inferred )?template(.*)?$/ do |not_shown, ext|
|
1955
1859
|
file = if ext.empty?
|
1956
1860
|
"templates/default/config.conf.erb"
|
data/lib/foodcritic/api.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require "nokogiri"
|
2
2
|
require "rufus-lru"
|
3
|
+
require "json"
|
3
4
|
|
4
5
|
module FoodCritic
|
5
6
|
# Helper methods that form part of the Rules DSL.
|
@@ -44,56 +45,6 @@ module FoodCritic
|
|
44
45
|
end
|
45
46
|
end
|
46
47
|
|
47
|
-
# Does the specified recipe check for Chef Solo?
|
48
|
-
#
|
49
|
-
# @deprecated chef-solo functionality in Chef has been replaced with local-mode
|
50
|
-
# so this helper is no longer necessary and will be removed in Foodcritic 11.0
|
51
|
-
def checks_for_chef_solo?(ast)
|
52
|
-
$stderr.puts "the checks_for_chef_solo? helper is deprecated and will be removed from the next release of Foodcritic"
|
53
|
-
raise_unless_xpath!(ast)
|
54
|
-
# TODO: This expression is too loose, but also will fail to match other
|
55
|
-
# types of conditionals.
|
56
|
-
(!ast.xpath(%q{//*[self::if or self::ifop or self::unless]/
|
57
|
-
*[self::aref or child::aref or self::call]
|
58
|
-
[count(descendant::const[@value = 'Chef' or @value = 'Config']) = 2
|
59
|
-
and
|
60
|
-
( count(descendant::ident[@value='solo']) > 0
|
61
|
-
or count(descendant::tstring_content[@value='solo']) > 0
|
62
|
-
)
|
63
|
-
]}).empty?) ||
|
64
|
-
ast.xpath('//if_mod[return][aref/descendant::ident/@value="solo"]/aref/
|
65
|
-
const_path_ref/descendant::const').map do |c|
|
66
|
-
c["value"]
|
67
|
-
end == %w{Chef Config}
|
68
|
-
end
|
69
|
-
|
70
|
-
# Is the chef-solo-search library available?
|
71
|
-
#
|
72
|
-
# @see https://github.com/edelight/chef-solo-search
|
73
|
-
# @deprecated chef-solo functionality in Chef has been replaced with local-mode
|
74
|
-
# so this helper is no longer necessary and will be removed in Foodcritic 11.0
|
75
|
-
def chef_solo_search_supported?(recipe_path)
|
76
|
-
$stderr.puts "the chef_solo_search_supported? helper is deprecated and will be removed from the next release of Foodcritic"
|
77
|
-
return false if recipe_path.nil? || !File.exist?(recipe_path)
|
78
|
-
|
79
|
-
# Look for the chef-solo-search library.
|
80
|
-
#
|
81
|
-
# TODO: This will not work if the cookbook that contains the library
|
82
|
-
# is not under the same `cookbook_path` as the cookbook being checked.
|
83
|
-
cbk_tree_path = Pathname.new(File.join(recipe_path, "../../.."))
|
84
|
-
search_libs = Dir[File.join(cbk_tree_path.realpath,
|
85
|
-
"*/libraries/search.rb")]
|
86
|
-
|
87
|
-
# True if any of the candidate library files match the signature:
|
88
|
-
#
|
89
|
-
# class Chef
|
90
|
-
# def search
|
91
|
-
search_libs.any? do |lib|
|
92
|
-
!read_ast(lib).xpath(%q{//class[count(descendant::const[@value='Chef']
|
93
|
-
) = 1]/descendant::def/ident[@value='search']}).empty?
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
48
|
# The absolute path of a cookbook from the specified file.
|
98
49
|
#
|
99
50
|
# @author Tim Smith - tsmith@chef.io
|
@@ -113,7 +64,11 @@ module FoodCritic
|
|
113
64
|
file
|
114
65
|
end
|
115
66
|
|
116
|
-
#
|
67
|
+
# Retrieves a value of a metadata field.
|
68
|
+
#
|
69
|
+
# @author Miguel Fonseca
|
70
|
+
# @since 7.0.0
|
71
|
+
# @return [String] the value of the metadata field
|
117
72
|
def metadata_field(file, field)
|
118
73
|
until (file.split(File::SEPARATOR) & standard_cookbook_subdirs).empty?
|
119
74
|
file = File.absolute_path(File.dirname(file.to_s))
|
@@ -133,6 +88,9 @@ module FoodCritic
|
|
133
88
|
end
|
134
89
|
|
135
90
|
# The name of the cookbook containing the specified file.
|
91
|
+
#
|
92
|
+
# @param file [String] file within a cookbook
|
93
|
+
# @return [String] name of the cookbook
|
136
94
|
def cookbook_name(file)
|
137
95
|
raise ArgumentError, "File cannot be nil or empty" if file.to_s.empty?
|
138
96
|
|
@@ -149,14 +107,20 @@ module FoodCritic
|
|
149
107
|
end
|
150
108
|
end
|
151
109
|
|
152
|
-
#
|
110
|
+
# Return metadata maintainer property given any file in the cookbook
|
111
|
+
#
|
112
|
+
# @param file [String] file within a cookbook
|
113
|
+
# @return [String] the maintainer of the cookbook
|
153
114
|
def cookbook_maintainer(file)
|
154
115
|
raise ArgumentError, "File cannot be nil or empty" if file.to_s.empty?
|
155
116
|
|
156
117
|
metadata_field(file, "maintainer")
|
157
118
|
end
|
158
119
|
|
159
|
-
#
|
120
|
+
# Return metadata maintainer_email property given any file in the cookbook
|
121
|
+
#
|
122
|
+
# @param file [String] file within a cookbook
|
123
|
+
# @return [String] email of the maintainer of the cookbook
|
160
124
|
def cookbook_maintainer_email(file)
|
161
125
|
raise ArgumentError, "File cannot be nil or empty" if file.to_s.empty?
|
162
126
|
|
@@ -167,33 +131,38 @@ module FoodCritic
|
|
167
131
|
def declared_dependencies(ast)
|
168
132
|
raise_unless_xpath!(ast)
|
169
133
|
|
134
|
+
deps = []
|
170
135
|
# String literals.
|
171
136
|
#
|
172
137
|
# depends 'foo'
|
173
|
-
deps
|
174
|
-
descendant::args_add/descendant::tstring_content[1]})
|
138
|
+
deps += field(ast, "depends").xpath("descendant::args_add/descendant::tstring_content[1]")
|
175
139
|
|
176
140
|
# Quoted word arrays are also common.
|
177
141
|
#
|
178
142
|
# %w{foo bar baz}.each do |cbk|
|
179
143
|
# depends cbk
|
180
144
|
# end
|
181
|
-
deps
|
182
|
-
|
183
|
-
deps.
|
145
|
+
deps += word_list_values(field(ast, "depends"))
|
146
|
+
deps.uniq!
|
147
|
+
deps.map! { |dep| dep["value"].strip }
|
148
|
+
deps
|
184
149
|
end
|
185
150
|
|
186
|
-
#
|
151
|
+
# Look for a method call with a given name.
|
152
|
+
#
|
153
|
+
# @param ast [Nokogiri::XML::Node] Document to search under
|
154
|
+
# @param field_name [String] Method name to search for
|
155
|
+
# @return [Nokogiri::XML::NodeSet]
|
187
156
|
def field(ast, field_name)
|
188
157
|
if field_name.nil? || field_name.to_s.empty?
|
189
158
|
raise ArgumentError, "Field name cannot be nil or empty"
|
190
159
|
end
|
191
|
-
ast.xpath("
|
160
|
+
ast.xpath("(.//command[ident/@value='#{field_name}']|.//fcall[ident/@value='#{field_name}']/..)")
|
192
161
|
end
|
193
162
|
|
194
163
|
# The value for a specific key in an environment or role ruby file
|
195
164
|
def field_value(ast, field_name)
|
196
|
-
field(ast, field_name).xpath('args_add_block
|
165
|
+
field(ast, field_name).xpath('.//args_add_block//tstring_content
|
197
166
|
[count(ancestor::args_add) = 1][count(ancestor::string_add) = 1]
|
198
167
|
/@value').map { |a| a.to_s }.last
|
199
168
|
end
|
@@ -376,25 +345,33 @@ module FoodCritic
|
|
376
345
|
end
|
377
346
|
|
378
347
|
# The list of standard cookbook sub-directories.
|
348
|
+
#
|
349
|
+
# @since 1.0.0
|
350
|
+
# @return [array] array of all default sub-directories in a cookbook
|
379
351
|
def standard_cookbook_subdirs
|
380
352
|
%w{attributes definitions files libraries providers recipes resources
|
381
353
|
templates}
|
382
354
|
end
|
383
355
|
|
384
|
-
# Platforms declared as supported in cookbook metadata
|
356
|
+
# Platforms declared as supported in cookbook metadata. Returns an array
|
357
|
+
# of hashes containing the name and version constraints for each platform.
|
358
|
+
#
|
359
|
+
# @param ast [Nokogiri::XML::Node] Document to search from.
|
360
|
+
# @return [Array<Hash>]
|
385
361
|
def supported_platforms(ast)
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
362
|
+
# Find the supports() method call.
|
363
|
+
platforms_ast = field(ast, "supports")
|
364
|
+
# Look for the first argument (the node next to the top args_new) and
|
365
|
+
# filter out anything with a string_embexpr since that can't be parsed
|
366
|
+
# statically. Then grab the static value for both strings and symbols, and
|
367
|
+
# finally combine it with the word list (%w{}) analyzer.
|
368
|
+
platforms = platforms_ast.xpath("(.//args_new)[1]/../*[not(.//string_embexpr)]").xpath(".//tstring_content|.//symbol/ident") | word_list_values(platforms_ast)
|
393
369
|
platforms.map do |platform|
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
370
|
+
# For each platform value, look for all arguments after the first, then
|
371
|
+
# extract the string literal value.
|
372
|
+
versions = platform.xpath("ancestor::args_add[not(args_new)]/*[position()=2]//tstring_content/@value")
|
373
|
+
{ platform: platform["value"].lstrip, versions: versions.map(&:to_s) }
|
374
|
+
end.sort_by { |p| p[:platform] }
|
398
375
|
end
|
399
376
|
|
400
377
|
# Template filename
|
@@ -436,6 +413,23 @@ module FoodCritic
|
|
436
413
|
end
|
437
414
|
end
|
438
415
|
|
416
|
+
# Give a filename path it returns the hash of the JSON contents
|
417
|
+
#
|
418
|
+
# @author Tim Smith - tsmith@chef.io
|
419
|
+
# @since 11.0
|
420
|
+
# @param filename [String] path to a file in JSON format
|
421
|
+
# @return [Hash] hash of JSON content
|
422
|
+
def json_file_to_hash(filename)
|
423
|
+
raise "File #{filename} not found" unless File.exist?(filename)
|
424
|
+
|
425
|
+
file = File.read(filename)
|
426
|
+
begin
|
427
|
+
JSON.parse(file)
|
428
|
+
rescue RuntimeError
|
429
|
+
raise "File #{filename} does not appear to contain valid JSON"
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
439
433
|
private
|
440
434
|
|
441
435
|
def block_attributes(resource)
|
@@ -642,14 +636,18 @@ module FoodCritic
|
|
642
636
|
end.sort
|
643
637
|
end
|
644
638
|
|
645
|
-
def word_list_values(ast, xpath)
|
646
|
-
|
639
|
+
def word_list_values(ast, xpath = nil)
|
640
|
+
# Find the node for the field argument variable. (e.g. given `foo d`, find `d`)
|
641
|
+
var_ref = ast.xpath("#{xpath ? xpath + '/' : ''}descendant::var_ref/ident")
|
647
642
|
if var_ref.empty?
|
648
|
-
|
643
|
+
# The field is either a static value, or took no arguments, or something
|
644
|
+
# more complex than we care to evaluate.
|
645
|
+
Nokogiri::XML::NodeSet.new(ast.document)
|
649
646
|
else
|
650
|
-
|
651
|
-
|
652
|
-
|
647
|
+
# Look back out the tree for a method_add_block which contains a block
|
648
|
+
# variable matching the field argument variable, and then drill down to
|
649
|
+
# all the literal content nodes.
|
650
|
+
ast.xpath(%Q{ancestor::method_add_block[//block_var//ident/@value='#{var_ref.first['value']}']/call//tstring_content})
|
653
651
|
end
|
654
652
|
end
|
655
653
|
end
|