Skip to content

Latest commit

 

History

History
134 lines (99 loc) · 3.58 KB

README.md

File metadata and controls

134 lines (99 loc) · 3.58 KB

Food Critic

Food Critic is a lint tool for Chef cookbooks. It requires Ruby 1.9.3. It doesn't do very much at the moment.

Building

$ bundle install
$ bundle exec rake

Continuous Integration

Food Critic on Travis CI

Built on Travis

License

MIT - see the accompanying LICENSE file for details.

Changelog

To see what has changed in recent versions see the CHANGELOG. Food Critic follows the Rubygems RationalVersioningPolicy.

Contributing

Additional rules and bugfixes are welcome! Please fork and submit a pull request on an individual branch per change.

Writing a new rule

The rules are defined in a simple dsl here.

The recipe block

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>

Matching within the recipe block

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!