Last active
December 18, 2015 16:29
-
-
Save ssimeonov/5811992 to your computer and use it in GitHub Desktop.
Generalized Chef LWRP subclassing and inheritance example. Chef::LWRPFactory will even generate ChefSpec matchers for new resources.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# Cookbook Name:: rake-chef | |
# Recipe:: spec | |
# | |
# Copyright (C) 2013 Swoop, Inc. | |
# | |
include_recipe 'rvm' | |
# rake subclasses rvm_shell LWRP | |
rake 'db:seed' do | |
cwd '/app/root' | |
runner :foreman | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class ChefResourceRake | |
module Implementation | |
def lwrp_initialize(name, run_context=nil) | |
# Call parent's constructor Chef::Resource::RvmShell | |
yield name, run_context | |
@provider = Chef::Provider::RvmShell | |
@allowed_actions = [:nothing, :run] | |
@task = name | |
@arguments = [] | |
@bundler = true | |
@trace = true | |
@runner = nil | |
end | |
def task(arg=nil) | |
set_or_return(:task, arg, :kind_of => [String]) | |
end | |
def arguments(*args) | |
set_or_return(:arguments, args.empty? ? nil : args, :kind_of => [Array]).tap do |result| | |
if (index = result.find_index(nil)) | |
raise "argument ##{index} cannot be nil. (Arguments: #{result.inspect})" | |
end | |
end | |
end | |
def bundler(arg=nil) | |
set_or_return(:bundler, arg, :kind_of => [TrueClass, FalseClass]) | |
end | |
def trace(arg=nil) | |
set_or_return(:trace, arg, :kind_of => [TrueClass, FalseClass]) | |
end | |
def runner(arg=nil) | |
set_or_return(:runner, arg, :kind_of => [String, Symbol, NilClass]) | |
end | |
def code(arg=nil) | |
raise 'code attribute of rake resource is read-only' if arg | |
code_to_run = [ | |
runner ? "#{runner} run" : nil, | |
bundler ? 'bundle exec' : nil, | |
arguments.empty? ? | |
"rake #{task}" : | |
"rake #{task}[#{arguments.join(',').shellescape}]", | |
trace ? '--trace' : nil | |
].compact.join(' ') | |
super code_to_run | |
end | |
end | |
def self.register | |
Chef::LWRPFactory.subclass( | |
type: :resource, | |
name: :rake, | |
parent: :rvm_shell, | |
identity_attr: :task, | |
default_action: :run, | |
include: Implementation, | |
chefspec: { | |
matcher: :execute_rake, | |
resource_type: :rake, | |
attribute: :code | |
} | |
) | |
end | |
end | |
def rake(*args, &block) | |
ChefResourceRake.register | |
method_missing(:rake, *args, &block) | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require_relative 'spec_helper' | |
describe 'rake-chef::spec' do | |
let (:chef_run) { ChefSpec::ChefRunner.new.converge 'rake-chef::spec' } | |
specify { expect(chef_run).to execute_rake 'foreman run bundle exec rake db:seed --trace' } | |
describe 'rake resource' do | |
subject { ChefResourceRake.register.new('my:task') } | |
it { should be_kind_of Chef::Resource::LWRPBase } | |
its(:task) { should == 'my:task' } | |
its(:arguments) { should == [] } | |
its(:bundler) { should be_true } | |
its(:trace) { should be_true } | |
its(:runner) { should be_nil } | |
its(:code) { should == 'bundle exec rake my:task --trace'} | |
it 'does not allow nil arguments' do | |
expect { subject.arguments 1, nil, 'hi' }.to raise_error /cannot be nil/ | |
end | |
it 'does not allow setting the command attribute' do | |
expect { subject.code 'rake -T' }.to raise_error /read-only/ | |
end | |
context 'with arguments 1 & "hello" and no bundler' do | |
before do | |
subject.arguments 1, 'hello there' | |
subject.bundler false | |
end | |
its(:arguments) { should == [1, 'hello there'] } | |
its(:bundler) { should be_false } | |
its(:code) { should == 'rake my:task[1,hello\ there] --trace'} | |
end | |
context 'with foreman runner and no trace' do | |
before do | |
subject.runner :foreman | |
subject.trace false | |
end | |
its(:runner) { should == :foreman } | |
its(:code) { should == 'foreman run bundle exec rake my:task'} | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment