foodcritic 0.4.0 → 0.5.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.
- data/bin/foodcritic +14 -3
- data/lib/foodcritic/domain.rb +2 -1
- data/lib/foodcritic/dsl.rb +7 -0
- data/lib/foodcritic/helpers.rb +24 -0
- data/lib/foodcritic/linter.rb +6 -2
- data/lib/foodcritic/rules.rb +17 -0
- data/lib/foodcritic/version.rb +1 -1
- metadata +19 -8
data/bin/foodcritic
CHANGED
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
2
|
require 'foodcritic'
|
|
3
|
+
require 'optparse'
|
|
4
|
+
|
|
5
|
+
options = {}
|
|
6
|
+
options[:tags] = []
|
|
7
|
+
parser = OptionParser.new do |opts|
|
|
8
|
+
opts.banner = 'foodcritic [cookbook_path]'
|
|
9
|
+
opts.on("-t", "--tags TAGS", "Only check against rules with the specified tags.") {|t|options[:tags] << t}
|
|
10
|
+
end
|
|
11
|
+
parser.parse!
|
|
12
|
+
|
|
3
13
|
unless ARGV.length == 1 and Dir.exists?(ARGV[0])
|
|
4
|
-
|
|
14
|
+
puts parser.help
|
|
5
15
|
exit 1
|
|
6
16
|
end
|
|
7
|
-
|
|
8
|
-
|
|
17
|
+
|
|
18
|
+
review = FoodCritic::Linter.new.check(ARGV[0], options)
|
|
19
|
+
puts review unless review.warnings.empty?
|
data/lib/foodcritic/domain.rb
CHANGED
|
@@ -38,7 +38,7 @@ module FoodCritic
|
|
|
38
38
|
|
|
39
39
|
# A rule to be matched against.
|
|
40
40
|
class Rule
|
|
41
|
-
attr_accessor :code, :name, :description, :recipe
|
|
41
|
+
attr_accessor :code, :name, :description, :recipe, :tags
|
|
42
42
|
|
|
43
43
|
# Create a new rule
|
|
44
44
|
#
|
|
@@ -46,6 +46,7 @@ module FoodCritic
|
|
|
46
46
|
# @param [String] name The short descriptive name of this rule presented to the end user.
|
|
47
47
|
def initialize(code, name)
|
|
48
48
|
@code, @name = code, name
|
|
49
|
+
@tags = [code]
|
|
49
50
|
end
|
|
50
51
|
end
|
|
51
52
|
|
data/lib/foodcritic/dsl.rb
CHANGED
|
@@ -19,6 +19,13 @@ module FoodCritic
|
|
|
19
19
|
yield self
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
+
# Add tags to the rule which can be used to filter the rules to be applied.
|
|
23
|
+
#
|
|
24
|
+
# @param [Array] tags The tags associated with this rule.
|
|
25
|
+
def tags(tags)
|
|
26
|
+
rules.last.tags += tags
|
|
27
|
+
end
|
|
28
|
+
|
|
22
29
|
# Set the rule description
|
|
23
30
|
#
|
|
24
31
|
# @param [String] description Set the rule description.
|
data/lib/foodcritic/helpers.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require 'nokogiri'
|
|
2
|
+
require 'chef/solr_query/query_transform'
|
|
2
3
|
|
|
3
4
|
module FoodCritic
|
|
4
5
|
|
|
@@ -31,6 +32,29 @@ module FoodCritic
|
|
|
31
32
|
ast.xpath("//fcall/ident[@value = 'search']")
|
|
32
33
|
end
|
|
33
34
|
|
|
35
|
+
# Searches performed by the specified recipe that are literal strings. Searches with a query formed from a
|
|
36
|
+
# subexpression will be ignored.
|
|
37
|
+
#
|
|
38
|
+
# @param [Nokogiri::XML::Node] ast The AST of the cookbook recipe to check.
|
|
39
|
+
# @return [Nokogiri::XML::Node] The matching nodes
|
|
40
|
+
def literal_searches(ast)
|
|
41
|
+
ast.xpath("//method_add_arg[fcall/ident/@value = 'search' and count(descendant::string_embexpr) = 0]/descendant::tstring_content")
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Is this a valid Lucene query?
|
|
45
|
+
#
|
|
46
|
+
# @param [String] query The query to check for syntax errors
|
|
47
|
+
# @return [Boolean] True if the query is well-formed
|
|
48
|
+
def valid_query?(query)
|
|
49
|
+
# Exceptions for flow control. Alternatively we could re-implement the parse method.
|
|
50
|
+
begin
|
|
51
|
+
Chef::SolrQuery::QueryTransform.parse(query)
|
|
52
|
+
true
|
|
53
|
+
rescue Chef::Exceptions::QueryParseError
|
|
54
|
+
false
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
34
58
|
# Find Chef resources of the specified type.
|
|
35
59
|
# TODO: Include blockless resources
|
|
36
60
|
#
|
data/lib/foodcritic/linter.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require 'ripper'
|
|
2
|
+
require 'gherkin/tag_expression'
|
|
2
3
|
|
|
3
4
|
module FoodCritic
|
|
4
5
|
|
|
@@ -15,12 +16,15 @@ module FoodCritic
|
|
|
15
16
|
# Review the cookbooks at the provided path, identifying potential improvements.
|
|
16
17
|
#
|
|
17
18
|
# @param [String] cookbook_path The file path to an individual cookbook directory
|
|
19
|
+
# @param [Hash] options Options to apply to the linting
|
|
20
|
+
# @option options [Array] tags The tags to filter rules based on
|
|
18
21
|
# @return [FoodCritic::Review] A review of your cookbooks, with any warnings issued.
|
|
19
|
-
def check(cookbook_path)
|
|
22
|
+
def check(cookbook_path, options)
|
|
20
23
|
warnings = []
|
|
24
|
+
tag_expr = Gherkin::TagExpression.new(options[:tags])
|
|
21
25
|
files_to_process(cookbook_path).each do |file|
|
|
22
26
|
ast = read_file(file)
|
|
23
|
-
@rules.each do |rule|
|
|
27
|
+
@rules.select{|rule| tag_expr.eval(rule.tags)}.each do |rule|
|
|
24
28
|
matches = rule.recipe.yield(ast, file)
|
|
25
29
|
matches.each{|match| warnings << Warning.new(rule, {:filename => file}.merge(match))} unless matches.nil?
|
|
26
30
|
end
|
data/lib/foodcritic/rules.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
rule "FC002", "Avoid string interpolation where not required" do
|
|
2
|
+
tags %w{style strings}
|
|
2
3
|
description "When setting a resource value avoid string interpolation where not required."
|
|
3
4
|
recipe do |ast|
|
|
4
5
|
ast.xpath(%q{//string_literal[count(descendant::string_embexpr) = 1 and
|
|
@@ -7,6 +8,7 @@ rule "FC002", "Avoid string interpolation where not required" do
|
|
|
7
8
|
end
|
|
8
9
|
|
|
9
10
|
rule "FC003", "Check whether you are running with chef server before using server-specific features" do
|
|
11
|
+
tags %w{portability solo}
|
|
10
12
|
description "Ideally your cookbooks should be usable without requiring chef server."
|
|
11
13
|
recipe do |ast|
|
|
12
14
|
checks_for_chef_solo?(ast) ? [] : searches(ast).map{|s| match(s)}
|
|
@@ -14,6 +16,7 @@ rule "FC003", "Check whether you are running with chef server before using serve
|
|
|
14
16
|
end
|
|
15
17
|
|
|
16
18
|
rule "FC004", "Use a service resource to start and stop services" do
|
|
19
|
+
tags %w{style services}
|
|
17
20
|
description "Avoid use of execute to control services - use the service resource instead."
|
|
18
21
|
recipe do |ast|
|
|
19
22
|
find_resources(ast, 'execute').find_all do |cmd|
|
|
@@ -24,6 +27,7 @@ rule "FC004", "Use a service resource to start and stop services" do
|
|
|
24
27
|
end
|
|
25
28
|
|
|
26
29
|
rule "FC005", "Avoid repetition of resource declarations" do
|
|
30
|
+
tags %w{style}
|
|
27
31
|
description "Where you have a lot of resources that vary in only a single attribute wrap them in a loop for brevity."
|
|
28
32
|
recipe do |ast|
|
|
29
33
|
matches = []
|
|
@@ -39,6 +43,7 @@ rule "FC005", "Avoid repetition of resource declarations" do
|
|
|
39
43
|
end
|
|
40
44
|
|
|
41
45
|
rule "FC006", "Mode should be quoted or fully specified when setting file permissions" do
|
|
46
|
+
tags %w{correctness files}
|
|
42
47
|
description "Not quoting mode when setting permissions can lead to incorrect permissions being set."
|
|
43
48
|
recipe do |ast|
|
|
44
49
|
ast.xpath(%q{//ident[@value='mode']/parent::command/descendant::int[string-length(@value) < 4]/
|
|
@@ -47,6 +52,7 @@ rule "FC006", "Mode should be quoted or fully specified when setting file permis
|
|
|
47
52
|
end
|
|
48
53
|
|
|
49
54
|
rule "FC007", "Ensure recipe dependencies are reflected in cookbook metadata" do
|
|
55
|
+
tags %w{correctness metadata}
|
|
50
56
|
description "You are including a recipe that is not in the current cookbook and not defined as a dependency in your cookbook metadata."
|
|
51
57
|
recipe do |ast,filename|
|
|
52
58
|
metadata_path = Pathname.new(File.join(File.dirname(filename), '..', 'metadata.rb')).cleanpath
|
|
@@ -60,6 +66,7 @@ rule "FC007", "Ensure recipe dependencies are reflected in cookbook metadata" do
|
|
|
60
66
|
end
|
|
61
67
|
|
|
62
68
|
rule "FC008", "Generated cookbook metadata needs updating" do
|
|
69
|
+
tags %w{style metadata}
|
|
63
70
|
description "The cookbook metadata for this cookbook is boilerplate output from knife generate cookbook and needs updating with the real details of your cookbook."
|
|
64
71
|
recipe do |ast,filename|
|
|
65
72
|
metadata_path = Pathname.new(File.join(File.dirname(filename), '..', 'metadata.rb')).cleanpath
|
|
@@ -74,6 +81,7 @@ rule "FC008", "Generated cookbook metadata needs updating" do
|
|
|
74
81
|
end
|
|
75
82
|
|
|
76
83
|
rule "FC009", "Resource attribute not recognised" do
|
|
84
|
+
tags %w{correctness}
|
|
77
85
|
description "You appear to be using an unrecognised attribute on a standard Chef resource. Please check for typos."
|
|
78
86
|
recipe do |ast|
|
|
79
87
|
matches = []
|
|
@@ -90,4 +98,13 @@ rule "FC009", "Resource attribute not recognised" do
|
|
|
90
98
|
end
|
|
91
99
|
matches
|
|
92
100
|
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
rule "FC010", "Invalid search syntax" do
|
|
104
|
+
tags %w{correctness search}
|
|
105
|
+
description "The search expression in the recipe could not be parsed. Please check your syntax."
|
|
106
|
+
recipe do |ast|
|
|
107
|
+
# This only works for literal search strings
|
|
108
|
+
literal_searches(ast).reject{|search| valid_query?(search['value'])}.map{|search| match(search)}
|
|
109
|
+
end
|
|
93
110
|
end
|
data/lib/foodcritic/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: foodcritic
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
prerelease:
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
@@ -9,11 +9,11 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2011-12-
|
|
12
|
+
date: 2011-12-13 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: chef
|
|
16
|
-
requirement: &
|
|
16
|
+
requirement: &2152896120 !ruby/object:Gem::Requirement
|
|
17
17
|
none: false
|
|
18
18
|
requirements:
|
|
19
19
|
- - ~>
|
|
@@ -21,10 +21,21 @@ dependencies:
|
|
|
21
21
|
version: 0.10.4
|
|
22
22
|
type: :runtime
|
|
23
23
|
prerelease: false
|
|
24
|
-
version_requirements: *
|
|
24
|
+
version_requirements: *2152896120
|
|
25
|
+
- !ruby/object:Gem::Dependency
|
|
26
|
+
name: gherkin
|
|
27
|
+
requirement: &2152893520 !ruby/object:Gem::Requirement
|
|
28
|
+
none: false
|
|
29
|
+
requirements:
|
|
30
|
+
- - ~>
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: 2.7.1
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: *2152893520
|
|
25
36
|
- !ruby/object:Gem::Dependency
|
|
26
37
|
name: nokogiri
|
|
27
|
-
requirement: &
|
|
38
|
+
requirement: &2152891580 !ruby/object:Gem::Requirement
|
|
28
39
|
none: false
|
|
29
40
|
requirements:
|
|
30
41
|
- - ~>
|
|
@@ -32,7 +43,7 @@ dependencies:
|
|
|
32
43
|
version: 1.5.0
|
|
33
44
|
type: :runtime
|
|
34
45
|
prerelease: false
|
|
35
|
-
version_requirements: *
|
|
46
|
+
version_requirements: *2152891580
|
|
36
47
|
description: Lint tool for Opscode Chef cookbooks.
|
|
37
48
|
email:
|
|
38
49
|
executables:
|
|
@@ -69,12 +80,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
69
80
|
version: '0'
|
|
70
81
|
segments:
|
|
71
82
|
- 0
|
|
72
|
-
hash:
|
|
83
|
+
hash: -2449883706857306958
|
|
73
84
|
requirements: []
|
|
74
85
|
rubyforge_project:
|
|
75
86
|
rubygems_version: 1.8.10
|
|
76
87
|
signing_key:
|
|
77
88
|
specification_version: 3
|
|
78
|
-
summary: foodcritic-0.
|
|
89
|
+
summary: foodcritic-0.5.0
|
|
79
90
|
test_files: []
|
|
80
91
|
has_rdoc:
|