chef-gen-flavors
- home :: https://github.com/jf647/chef-gen-flavors
- license :: Apache2
- gem version ::
- build status ::
- code climate ::
- docs ::
DESCRIPTION
chef-gen-flavors is a framework for creating custom templates for the 'chef generate' command provided by ChefDK.
This gem simply provides a framework; templates are provided by separate gems, which you can host privately for use within your organization or publicly for the Chef community to use.
chef-gen-flavor-base is a base class that makes it easy to compose a flavor from reusable snippets of functionality, and using it is highly recommended. Using chef-gen-flavors on its own is only suitable if you already have a template which is a copy of the skeleton provided by ChefDK.
At present this is focused primarily on providing templates for generation of cookbooks, as this is where most organization-specific customization takes place. Support for the other artifacts that ChefDK can generate may work, but is not the focus of early releases.
BREAKING API CHANGES
v0.9.0 of chef-gen-flavors is very different from chef-gen-flavors v0.8.x. Flavors will need to be re-worked, and the base flavor class and associated snippets have been extracted to their own gem.
v0.8.6 contained a warning about this change; if you are not ready to upgrade your flavor you can pin to this version to keep the old API.
INSTALLATION
You should not install this gem directly; it will be installed as a dependency of a flavor gem. If you are developing a flavor, declare this gem a dependency of your gem in your gemspec file:
Gem::Specification.new do |s|
s.name = 'chef-gen-flavor-awesome'
s.add_runtime_dependency('chef-gen-flavors', ['~> 0.9'])
...
end
Then make bundler read your gemspec:
source 'https://rubygems.org/'
gemspec
And use bundler to install your dependencies:
$ bundle
PREREQUISITES
This gem requires that you have ChefDK (at least version 0.3.6) installed. chef-dk is not a dependency of this gem because chef-dk should always be installed using the omnibus packages provided by Chef, not as a gem.
CONFIGURATION
In your knife.rb
file, add this snippet:
# only load ChefGen::Flavors if we're being called from the ChefDK CLI
if defined?(ChefDK::CLI)
require 'chef_gen/flavors'
chefdk.generator_cookbook = ChefGen::Flavors.path
end
When you run chef generate
, all available plugins will be loaded. If more
than one plugin is found, you will be prompted as to which you want to use:
$ chef generate cookbook my_app
If you set the environment variable CHEFGEN_FLAVOR
to the name of a
plugin, it will be chosen instead of presenting a prompt:
$ CHEFGEN_FLAVOR=mytemplate chef generate cookbook my_app
USING THE BUILT-IN CHEFDK TEMPLATE
By default, this gem does not offer the built-in ChefDK template as an
option. By setting the environment variable CHEFDK_FLAVOR, the
option builtin
will be offered.
FLAVORS
This gem uses little-plugger to make adding template flavors easy. Each flavor is defined by a plugin named using little-pluggers's rules.
The plugin must define a class inside the naming hierarchy
ChefGen::Flavor::
. The class name should be the filename converted to
CamelCase (e.g. foo_bar.rb
= FooBar
)
The name of the class must not be in all caps, as little-plugger ignores these (assuming that they are constants).
You do not have to require
your plugin; little-plugger searches all
installed gems for files matching the globspec.
Flavor classes must also:
- define a NAME constant which is the name of the flavor in lowercase
- provide an
#add_content
method, which is responsible for copying content to the temporary directory created by chef-gen-flavors
EXAMPLE FLAVOR STRUCTURE
This example defines a flavor named Example
. It can only generate
cookbooks, as its code_generator cookbook contains no other recipes.
A functional copy of this plugin is available on rubygems as
chef-gen-flavor-example
.
The directory structure of a plugin looks like this:
chef-gen-flavor-example
├── lib
│ └── chef_gen
│ └── flavor
│ └── example.rb
└── shared
└── flavor
└── example
├── metadata.rb
└── recipes
└── cookbook.rb
It is important that the name of the flavor matches the name in metadata.rb. ChefDK uses the last element of the path as the cookbook name, so if you put your cookbook in a folder called 'cookbook' but your metadata.rb declares the name as 'example', ChefDK won't be able to find your recipe.
COPYING CONTENT
When #path is called, chef-gen-flavors creates a temporary directory, which is passes as an argument to the flavor class' constructor:
class ChefGen
module Flavor
class Awesome
NAME = 'awesome'
def initialize(temp_path:)
@temp_path = temp_path
end
end
end
end
The flavor is responsible for copying everything required to run
generation to that path by defining a #add_content
method. For a
simple flavor, that might be just a recursive copy:
class ChefGen
module Flavor
class Awesome
...
def add_content
FileUtils.cp_r(
File.expand_path(
File.join(
File.dirname(__FILE__),
'..', '..', '..', 'shared', 'flavor', NAME
)
) + '/.',
@temp_path
)
end
end
end
end
Once the add_content method has been called, it is returned as the
value of chefdk.generator_cookbook
, and generation proceeds as if
you had given chef generate
and alternate path by passing -g.
This path is cleaned up at exit unless the environment
variable CHEFGEN_NOCLEANTMP
is set.
When using ChefGen::FlavorBase, there are helper functions to compose the temporary directory from files that come from a mix of flavors and reusable components.
FEATURE TESTING FLAVORS
chef-gen-flavors provides a number of useful step definitions for Aruba
(a CLI driver for Cucumber) to make it easier to test flavors. To
access these definitions, add the following line to your
features/support/env.rb
file:
require 'chef_gen/flavors/cucumber'
For an example of how to use these steps in your features, refer to the reference implementation of a flavor: chef-gen-flavor-example.
Documentation for the steps themselves is in the file ARUBA_STEPS.md
AUTHOR
LICENSE
Copyright 2015 Nordstrom, Inc.
Copyright 2015 James FitzGibbon
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.