implement switching back to prior env on post-commit, should fix #2

This commit is contained in:
John Bintz 2012-01-09 10:48:47 -05:00
parent 9354fed2dc
commit b30d56819e
16 changed files with 327 additions and 27 deletions

View File

@ -5,7 +5,11 @@ gemspec
gem 'guard' gem 'guard'
gem 'guard-rspec' gem 'guard-rspec'
gem 'guard-cucumber'
gem 'mocha' gem 'mocha'
gem 'fakefs' gem 'fakefs'
gem 'rspec', '~> 2.6.0' gem 'rspec', '~> 2.6.0'
gem 'rake' gem 'rake'
gem 'cucumber'

View File

@ -1,9 +1,18 @@
# A sample Guardfile # A sample Guardfile
# More info at https://github.com/guard/guard#readme # More info at https://github.com/guard/guard#readme
guard 'rspec', :cli => '-c', :version => 2 do group :rspec do
watch(%r{^spec/.+_spec\.rb$}) guard 'rspec', :cli => '-c', :version => 2 do
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" } watch(%r{^spec/.+_spec\.rb$})
watch('spec/spec_helper.rb') { "spec" } watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
watch('spec/spec_helper.rb') { "spec" }
end
end end
group :cucumber do
guard 'cucumber' do
watch(%r{^features/.+\.feature$})
watch(%r{^features/support/.+$}) { 'features' }
watch(%r{^features/step_definitions/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'features' }
end
end

View File

@ -9,5 +9,24 @@ rescue LoadError
"#$! - no rspec" "#$! - no rspec"
end end
task :default => :spec begin
require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new(:spec)
rescue LoadError
"#$! - no rspec"
end
begin
require 'cucumber'
require 'cucumber/rake/task'
Cucumber::Rake::Task.new(:cucumber) do |t|
t.cucumber_opts = "features --format pretty"
end
rescue LoadError
"#$! - no cucumber"
end
task :default => [ :spec, :cucumber ]

View File

@ -29,11 +29,19 @@ class PenchantCLI < Thor
end end
method_options :deployment => false method_options :deployment => false
method_options :switch_back => false
desc "gemfile ENV", "Switch the gemfile environment, or rebuild the current environment if not given" desc "gemfile ENV", "Switch the gemfile environment, or rebuild the current environment if not given"
def gemfile(env = get_current_env) def gemfile(env = get_current_env)
if env if env
puts "[penchant] Rebunding for #{env} environment#{options[:deployment] ? ", deployment mode" : ''}..." if options[:switch_back]
Penchant::Gemfile.do_full_env_switch!(env, options[:deployment]) puts "[penchant] Switching back, fallback: #{env}..."
Penchant::Gemfile.switch_back!(env)
else
puts "[penchant] Rebunding for #{env} environment#{options[:deployment] ? ", deployment mode" : ''}..."
Penchant::Gemfile.do_full_env_switch!(env, options[:deployment])
end
end end
gemfile = Penchant::Gemfile.new gemfile = Penchant::Gemfile.new

18
features/cli.feature Normal file
View File

@ -0,0 +1,18 @@
Feature: CLI
Scenario: Switch back to the original pre-deployment environment
Given I have the file "tmp/Gemfile.erb" with the content:
"""
gem 'rake'
"""
And I have the file "tmp/Gemfile" with the content:
"""
# generated by penchant, environment: production, deployment mode (was local)
"""
When I run "bin/penchant gemfile other --switch-back" in the "tmp" directory
Then the file "tmp/Gemfile" should have the following content:
"""
# generated by penchant, environment: local
gem 'rake'
"""
And the output should include "fallback: other"

33
features/gemfile.feature Normal file
View File

@ -0,0 +1,33 @@
@fakefs
Feature: Gemfiles
Scenario: When rebuilding for deployment, save the original state
Given I have the file "Gemfile.erb" with the content:
"""
this is content
"""
And I have the file "Gemfile" with the content:
"""
# generated by penchant, environment: local
"""
When I rebuild the Gemfile for "production" mode with deployment
Then the file "Gemfile" should have the following content:
"""
# generated by penchant, environment: production, deployment mode (was local)
this is content
"""
Scenario: When unbundling from deployment with an original state, switch to that state
Given I have the file "Gemfile.erb" with the content:
"""
this is content
"""
And I have the file "Gemfile" with the content:
"""
# generated by penchant, environment: production, deployment mode (was local)
"""
When I rebuild the Gemfile asking to switch back to the previous state
Then the file "Gemfile" should have the following content:
"""
# generated by penchant, environment: local
this is content
"""

View File

@ -0,0 +1,5 @@
Given /^I have the file "([^"]*)" with the content:$/ do |file, string|
FileUtils.mkdir_p File.dirname(file)
File.open(file, 'wb') { |fh| fh.print string }
end

View File

@ -0,0 +1,3 @@
Then /^the file "([^"]*)" should have the following content:$/ do |file, string|
File.read(file).should == string
end

View File

@ -0,0 +1,3 @@
Then /^the output should include "([^"]*)"$/ do |text|
@output.should include(text)
end

View File

@ -0,0 +1,3 @@
When /^I rebuild the Gemfile asking to switch back to the previous state$/ do
Penchant::Gemfile.switch_back!("remote")
end

View File

@ -0,0 +1,3 @@
When /^I rebuild the Gemfile for "([^"]*)" mode with deployment$/ do |env|
Penchant::Gemfile.do_full_env_switch!(env, true)
end

View File

@ -0,0 +1,3 @@
When /^I run "([^"]*)" in the "([^"]*)" directory$/ do |command, dir|
@output = %x{bash -c 'opwd=$PWD; cd #{dir} && $opwd/#{command}'}
end

13
features/support/env.rb Normal file
View File

@ -0,0 +1,13 @@
require 'fakefs/safe'
require 'penchant'
Before('@fakefs') do
FakeFS.activate!
end
After do
FakeFS.deactivate!
FileUtils.rm_rf 'tmp'
end

View File

@ -2,21 +2,30 @@ require 'erb'
module Penchant module Penchant
class Gemfile class Gemfile
attr_reader :path attr_reader :path, :is_deployment
class << self def self.do_full_env_switch!(env, deployment = false)
def do_full_env_switch!(env, deployment = false) return false if !(gemfile = pre_switch(env, deployment))
gemfile = Penchant::Gemfile.new
gemfile.run_dot_penchant!(env, deployment)
if !gemfile.has_gemfile_erb? gemfile.switch_to!(env, deployment)
return false
end
gemfile.switch_to!(env, deployment)
end
end end
def self.switch_back!(fallback_env)
return false if !(gemfile = pre_switch(fallback_env))
gemfile.switch_back!(fallback_env)
end
def self.pre_switch(env, deployment = false)
gemfile = Penchant::Gemfile.new
return false if !gemfile.has_gemfile_erb?
gemfile.run_dot_penchant!(env, deployment)
gemfile
end
def current_env ; @env ; end
def initialize(path = Dir.pwd) def initialize(path = Dir.pwd)
@path = path @path = path
end end
@ -26,7 +35,7 @@ module Penchant
end end
def has_gemfile? def has_gemfile?
File.file?('Gemfile') File.file?(gemfile_path)
end end
def has_dot_penchant? def has_dot_penchant?
@ -42,33 +51,52 @@ module Penchant
end end
def environment def environment
File.readlines(gemfile_path).first.strip[%r{environment: ([^, ]*)}, 1] gemfile_header.strip[%r{environment: ([^, ]*)}, 1]
end end
def deployment? def deployment?
File.readlines(gemfile_path).first['deployment mode'] != nil gemfile_header['deployment mode'] != nil
end end
def switch_to!(gemfile_env = nil, deployment = false) def switch_to!(gemfile_env = nil, deployment = false)
@env, @is_deployment = gemfile_env, deployment @env, @is_deployment = gemfile_env, deployment
template = File.read(gemfile_erb_path)
File.open(gemfile_path, 'wb') do |fh| output = [ header, ERB.new(template).result(binding) ]
fh.puts "# generated by penchant, environment: #{@env || "none"}#{@is_deployment ? " , deployment mode" : ""}"
fh.print ERB.new(template).result(binding) File.open(gemfile_path, 'wb') { |fh| fh.print output.join("\n") }
end
end end
def run_dot_penchant!(env, deployment) def run_dot_penchant!(env, deployment)
DotPenchant.run(env || environment, deployment) if has_dot_penchant? DotPenchant.run(env || environment, deployment) if has_dot_penchant?
end end
def header
header = [ "# generated by penchant, environment: #{current_env}" ]
if is_deployment
header << ", deployment mode (was #{environment})"
end
header.join
end
def prior_environment
gemfile_header[%r{\(was (.+)\)}, 1]
end
def switch_back!(fallback_env)
switch_to!(prior_environment || fallback_env)
end
private private
def file_in_path(file) def file_in_path(file)
File.join(@path, file) File.join(@path, file)
end end
def template
File.read(gemfile_erb_path)
end
def env(check, &block) def env(check, &block)
instance_eval(&block) if check.to_s == @env.to_s instance_eval(&block) if check.to_s == @env.to_s
end end
@ -76,6 +104,10 @@ module Penchant
def no_deployment(&block) def no_deployment(&block)
instance_eval(&block) if !@is_deployment instance_eval(&block) if !@is_deployment
end end
def gemfile_header
(has_gemfile? and File.readlines(gemfile_path).first) or ""
end
end end
end end

View File

@ -146,5 +146,149 @@ ERB
end end
end end
end end
describe '#switch_to!' do
let(:template) { 'template' }
let(:gemfile_path) { 'gemfile path' }
let(:header) { 'header' }
let(:gemfile_out) { File.read(gemfile_path) }
before do
gemfile.stubs(:template).returns(template)
gemfile.stubs(:gemfile_path).returns(gemfile_path)
gemfile.expects(:header).returns(header)
end
it 'should write out the new gemfile' do
gemfile.switch_to!
gemfile_out.should include(template)
gemfile_out.should include(header)
end
end
describe '#header' do
subject { gemfile.header }
let(:env) { 'env' }
let(:prior_environment) { 'prior' }
before do
gemfile.stubs(:current_env).returns(env)
gemfile.stubs(:environment).returns(prior_environment)
end
context 'not deployment' do
before do
gemfile.stubs(:is_deployment).returns(false)
end
it { should == "# generated by penchant, environment: #{env}" }
end
context 'deployment' do
before do
gemfile.stubs(:is_deployment).returns(true)
end
it { should == "# generated by penchant, environment: #{env}, deployment mode (was #{prior_environment})" }
end
end
describe '#prior_environment' do
subject { gemfile.prior_environment }
let(:prior) { 'prior' }
before do
gemfile.stubs(:gemfile_header).returns("# header (was #{prior})")
end
it { should == prior }
end
describe '.switch_back!' do
let(:gemfile) { stub }
let(:fallback_env) { 'env' }
context 'pre_switch fails' do
before do
described_class.stubs(:pre_switch).returns(false)
gemfile.expects(:switch_back!).never
end
it 'should not switch back' do
described_class.switch_back!(fallback_env).should be_false
end
end
context 'pre_switch succeeds' do
before do
described_class.stubs(:pre_switch).returns(gemfile)
gemfile.expects(:switch_back!).with(fallback_env)
end
it 'should switch back' do
described_class.switch_back!(fallback_env)
end
end
end
describe '.pre_switch' do
subject { described_class.pre_switch(env, deployment) }
let(:env) { 'env' }
let(:deployment) { 'deployment' }
context 'no Gemfile.erb' do
before do
described_class.any_instance.expects(:has_gemfile_erb?).returns(false)
end
it { should be_false }
end
context 'Gemfile.erb' do
before do
described_class.any_instance.expects(:has_gemfile_erb?).returns(true)
described_class.any_instance.expects(:run_dot_penchant!).with(env, deployment)
end
it { should be_a_kind_of(described_class) }
end
end
describe '#switch_back!' do
let(:fallback_env) { 'fallback' }
let(:prior) { 'prior' }
context 'no prior' do
before do
gemfile.stubs(:prior_environment).returns(nil)
gemfile.expects(:switch_to!).with(fallback_env)
end
it 'should proxy through to switch_to!' do
gemfile.switch_back!(fallback_env)
end
end
context 'prior' do
before do
gemfile.stubs(:prior_environment).returns(prior)
gemfile.expects(:switch_to!).with(prior)
end
it 'should proxy through to switch_to!' do
gemfile.switch_back!(fallback_env)
end
end
end
end end

View File

@ -1,4 +1,4 @@
#!/bin/bash #!/bin/bash
penchant gemfile remote penchant gemfile remote --switch-back