Managing Your Chef Gem Dependencies More Easily in your
When writing Chef cookbooks, it's possible that we're going to want to use a gem as a dependency, for instance to interact with HashiCorp Vault using the vault gem.
To tell Chef that we want to have this gem installed before we perform a Chef run, we need to add it as a
gem to our
# other cookbook metadata gem 'vault', '~> 0.16'
However, this then causes issues for us, as if we want to do any local testing, such as unit testing with ChefSpec, we can't rely on Chef to install these gems, as we're not really executing a full Chef run.
The solution, previously mentioned in my post about Chef's dependency management tools, is that we need to add this i.e. to our
Gemfile, so Bundler can install the dependency:
source '...' gem 'vault', '~> 0.16'
This then has the problem of our
metadata.rb becoming misaligned, and can be quite annoying, as we may be testing against a different version than is installed by the cookbook. Fortunately, using the knowledge from my article Programatically Determining the Version of a Chef Cookbook, we can take advantage of the
Gemfile being a Ruby file, and replace the
source '...' require 'chef' m = Chef::Cookbook::Metadata.new m.from_file 'metadata.rb' m.gems.each do |name, version| gem name, version end
This allows us to manage our Chef Gem dependencies for Chef and local development with Bundler, and remove the need to keep both updated!
An alternative would be to monkey patch Bundler::Dsl, but this also works as-is, and doesn't require anything else to be globally installed.
I've also raised this upstream with the Bundler team to see their thoughts about this being a first-class citizen.