Food Critic is a lint tool for Chef cookbooks. It requires Ruby 1.9.3. It doesn't do very much at the moment.
$ bundle install
$ bundle exec rake
MIT - see the accompanying LICENSE file for details.
To see what has changed in recent versions see the CHANGELOG. Food Critic follows the Rubygems RationalVersioningPolicy.
Additional rules and bugfixes are welcome! Please fork and submit a pull request on an individual branch per change.
The rules are defined in a simple dsl here.
Each rule has a recipe block that defines the matching logic for the rule. The block accepts a
Nokogiri document that contains the Ripper parsed representation of your recipe. You can see
what this looks like by calling to_xml
on the AST document.
So given a recipe that contains a single log resource:
examples/recipes/default.rb
log "Chef is the business"
And a rule that does nothing except print the AST document to stdout:
rules.rb
rule "FC123", "Short description shown to the user" do
description "A longer description with more information."
recipe do |ast|
puts ast.to_xml
end
end
Then when you run foodcritic against the example recipe you will see the tree that represents the recipe as passed to your rule.
stdout
$ foodcritic example
<?xml version="1.0"?>
<opt>
<stmts_add>
<stmts_new/>
<command>
<ident value="log">
<pos line="1" column="0"/>
</ident>
<args_add_block value="false">
<args_add>
<args_new/>
<string_literal>
<string_add>
<string_content/>
<tstring_content value="Chef is the business">
<pos line="1" column="5"/>
</tstring_content>
</string_add>
</string_literal>
</args_add>
</args_add_block>
</command>
</stmts_add>
</opt>
You can use Nokogiri's great support for XPath or CSS selectors to match against statements within the tree.
So if you wanted to get all tstring_content
nodes that contained the word 'Chef' like our log statement above you
could do something like the following within the recipe block:
rules.rb
recipe do |ast|
puts ast.xpath("//tstring_content[contains(@value, 'Chef')]").to_xml
[]
end
And the output will be something like:
stdout
<tstring_content value="Chef is the business">
<pos line="1" column="5"/>
</tstring_content>
This node contains a pos
child node that defines its location within the recipe. Now lets finish our rule by adding
the matched node to the list of matches, which ensures the user will see a warning.
rules.rb
rule "FC123", "Short description shown to the user" do
description "A longer description with more information."
recipe do |ast|
ast.xpath("//tstring_content[contains(@value, 'Chef')]").map{|resource| match(resource)}
end
end
stdout
$ foodcritic example
FC123: Short description shown to the user: example/recipes/default.rb:1
That's it - have fun. Thanks!