flipp 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,17 @@
1
+ # flipp
2
+
3
+ To alleviate issues around highly divergent development databases on feature/refactor branches, flipp helps switch databases upon new branch checkouts.
4
+
5
+ # Database Support
6
+
7
+ Current support is for MySQL only.
8
+
9
+ # Installation & Usage
10
+
11
+ 1. Add `gem 'flipp'` to your Gemfile or do `gem install flipp`.
12
+ 2. Run `rake flipp:install` from your project's root directory to install the git hook
13
+ 3. Normal git workflow, ie. switch branches normally
14
+
15
+ # License
16
+
17
+ flipp is released under the MIT license
@@ -0,0 +1,2 @@
1
+ $:.unshift File.expand_path('..', __FILE__)
2
+ require 'tasks/flipp'
@@ -0,0 +1,24 @@
1
+ lib = File.expand_path('../lib/', __FILE__)
2
+ $:.unshift lib unless $:.include?(lib)
3
+
4
+ require 'bundler'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "flipp"
8
+ s.version = '0.0.1'
9
+ s.platform = Gem::Platform::RUBY
10
+ s.authors = ["Mike Pack"]
11
+ s.email = ["mikepackdev@gmail.com"]
12
+ s.homepage = "http://www.mikepackdev.com"
13
+ s.summary = %q{Switch development databases upon branch checkouts.}
14
+ s.description = %q{To alleviate issues around highly divergent development databases on feature/refactor branches, flipp helps switch databases upon new branch checkouts.}
15
+
16
+ s.required_rubygems_version = ">= 1.3.6"
17
+
18
+ s.add_runtime_dependency 'active_record'
19
+ s.add_runtime_dependency 'database_exporter'
20
+
21
+ s.files = %w( README.md Rakefile flipp.gemspec tasks/flipp.rb ) + Dir["lib/**/*.rb"]
22
+ s.test_files = Dir["spec/**/*.rb"]
23
+ s.require_paths = ["lib"]
24
+ end
@@ -0,0 +1,2 @@
1
+ require 'flipp/flipp'
2
+ require 'flipp/railties/reestablish_connection' if defined?(Rails)
@@ -0,0 +1,56 @@
1
+ require 'rubygems'
2
+ require 'active_record'
3
+ require 'database_exporter'
4
+ require File.join(File.dirname(__FILE__), '../helpers/git_helper')
5
+
6
+ # The Flipp class orchestrates the actual switching of databaseses
7
+ class Flipp
8
+ def initialize(branch = GitHelper.current_branch)
9
+ @branch = branch
10
+ end
11
+
12
+ def switch_databases
13
+ current_config = ActiveRecord::Base.connection_pool.spec.config
14
+ new_config = current_config.merge!({:database => new_database_name(current_config)})
15
+
16
+ puts "Switching databases (#{new_config[:database]})..."
17
+
18
+ # Try connecting to the new database
19
+ begin
20
+ ActiveRecord::Base.establish_connection new_config
21
+ rescue
22
+ create_new_db_or_fallback current_config, new_config
23
+ end
24
+ end
25
+
26
+ def create_new_db_or_fallback(current_config, new_config)
27
+ # Try creating then connecting to the new database
28
+ begin
29
+ create_and_copy_data! current_config, new_config
30
+ rescue => exception
31
+ # Fallback and use the original config
32
+ puts "Could not use the new database, falling back to your normal development database..."
33
+ ActiveRecord::Base.establish_connection current_config
34
+ end
35
+ end
36
+
37
+ def new_database_name(config)
38
+ # The new name for the database
39
+ # eg. if the original dev database is dev_db and the branch was "new_feature",
40
+ # the new database would be db_db_new_feature
41
+ config[:database] + '_' + @branch
42
+ end
43
+
44
+ def create_and_copy_data!(current_config, new_config)
45
+ # Copy the current development database's data to the new database
46
+ puts "Copying data to the new database (this could take a minute but will only run once)..."
47
+ copy_data current_config, new_config
48
+
49
+ # Try out the new database
50
+ ActiveRecord::Base.establish_connection new_config
51
+ end
52
+
53
+ def copy_data(current_config, new_config)
54
+ DatabaseExporter.new(current_config).copy(new_config)
55
+ end
56
+ end
@@ -0,0 +1,11 @@
1
+ require 'flipp'
2
+
3
+ class ReestablishConnection < Rails::Railtie
4
+ initializer "restablish_connection.configure_rails_initialization" do
5
+ if Rails.env.development? and GitHelper.hook_installed?
6
+ # Use the connection determined by flipp
7
+ flipp = Flipp.new
8
+ flipp.switch_databases
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,33 @@
1
+ require 'fileutils'
2
+
3
+ module GitHelper
4
+ def self.hook_installed?
5
+ File.exists? '.git/hooks/post-checkout'
6
+ end
7
+
8
+ def self.install_hook
9
+ # Check for the .git directory
10
+ if File.directory? '.git'
11
+ unless File.directory? '.git/hooks'
12
+ # Create hooks directory
13
+ end
14
+
15
+ # Copy the file to the git hooks
16
+ puts 'Moving git hook into place...'
17
+ FileUtils.cp 'lib/git_hooks/post-checkout', File.expand_path('.git/hooks/post-checkout')
18
+ # And give it execute permissions
19
+ FileUtils.chmod 0755, '.git/hooks/post-checkout'
20
+ else
21
+ puts "Can't find your .git directory. Are you at the root of your project?"
22
+ end
23
+ end
24
+
25
+ def self.uninstall_hook
26
+ puts 'Removing git hook...'
27
+ FileUtils.rm File.expand_path('.git/hooks/post-checkout')
28
+ end
29
+
30
+ def self.current_branch
31
+ `git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e 's/* /\1/'`.chomp[1..-1] # Remove control character
32
+ end
33
+ end
@@ -0,0 +1,66 @@
1
+ require 'spec_helper'
2
+
3
+ describe Flipp do
4
+ let(:flipp) { Flipp.new('new_feature_branch') }
5
+ let(:old_db) { {:adapter => 'mysql2', :host => 'localhost', :username => 'root', :database => 'old_db'} }
6
+ let(:new_db) { {:adapter => 'mysql2', :host => 'localhost', :username => 'root', :database => 'new_db'} }
7
+
8
+ describe '#switch_databases' do
9
+ before do
10
+ # Stub the current connection
11
+ ActiveRecord::Base.stub_chain(:connection_pool, :spec, :config).and_return({:adapter => 'mysql2', :host => 'localhost', :username => 'root', :database => 'old_db'})
12
+ end
13
+
14
+ it 'tries to connect to the new database' do
15
+ ActiveRecord::Base.should_receive(:establish_connection).with(an_instance_of(Hash))
16
+ flipp.switch_databases
17
+ end
18
+
19
+ it 'tries to create and copy data to new database, then connect' do
20
+ ActiveRecord::Base.stub(:establish_connection) { raise }
21
+ flipp.should_receive(:create_new_db_or_fallback).with(an_instance_of(Hash), an_instance_of(Hash))
22
+ flipp.switch_databases
23
+ end
24
+ end
25
+
26
+ describe '#create_new_db_or_fallback' do
27
+ it 'falls back on the original connection if the new database can not be formed' do
28
+ flipp.stub(:create_and_copy_data!) { raise }
29
+ flipp.should_receive(:create_and_copy_data!).with(old_db, new_db)
30
+ ActiveRecord::Base.should_receive(:establish_connection).with(old_db)
31
+ flipp.create_new_db_or_fallback(old_db, new_db)
32
+ end
33
+ end
34
+
35
+ describe '#new_database_name' do
36
+ it 'constructs a database name consisting of the current dev db and the branch name' do
37
+ flipp.new_database_name({:database => 'dev_db'}).should == 'dev_db_new_feature_branch'
38
+ end
39
+ end
40
+
41
+ describe '#create_and_copy_data!' do
42
+ it 'copies the database' do
43
+ flipp.should_receive(:copy_data).with(old_db, new_db)
44
+ flipp.create_and_copy_data!(old_db, new_db)
45
+ end
46
+
47
+ it 'tries to connect to the new database' do
48
+ ActiveRecord::Base.should_receive(:establish_connection).with(new_db)
49
+ flipp.create_and_copy_data!(old_db, new_db)
50
+ end
51
+ end
52
+
53
+ describe '#copy_data' do
54
+ it 'invokes the database adapter and makes a copy' do
55
+ # Mock DatabaseExporter so we can access the #copy method
56
+ mock = double(DatabaseExporter)
57
+ DatabaseExporter.stub(:new).and_return(mock)
58
+
59
+ # Expect it to instantiate and call the #copy method
60
+ DatabaseExporter.should_receive(:new).with(old_db)
61
+ mock.should_receive(:copy).with(new_db)
62
+
63
+ flipp.copy_data(old_db, new_db)
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ describe GitHelper do
4
+ describe '#hook_installed?' do
5
+ it 'returns true when the hook exists' do
6
+ FileUtils.touch '.git/hooks/post-checkout'
7
+ GitHelper.hook_installed?.should be_true
8
+ end
9
+
10
+ it 'returns false when the hook does not exists' do
11
+ FileUtils.rm '.git/hooks/post-checkout'
12
+ GitHelper.hook_installed?.should be_false
13
+ end
14
+ end
15
+
16
+ describe '#install_hook' do
17
+ it 'moves the git hook into place' do
18
+ GitHelper.install_hook
19
+ FileUtils.compare_file('.git/hooks/post-checkout', File.expand_path('../../../../lib/git_hooks/post-checkout', __FILE__))
20
+ end
21
+ end
22
+
23
+ describe '#uninstall_hook' do
24
+ before { GitHelper.install_hook }
25
+
26
+ it 'remove the git hook' do
27
+ GitHelper.uninstall_hook
28
+ GitHelper.hook_installed?.should be_false
29
+ end
30
+ end
31
+
32
+ describe '#current_branch' do
33
+ it 'returns the name of the current git branch' do
34
+ `git checkout -b new_and_fun_branch`
35
+ GitHelper.current_branch.should == 'new_and_fun_branch'
36
+
37
+ # Cleanup
38
+ `git checkout master && git branch -d new_and_fun_branch`
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,3 @@
1
+ $:.unshift File.expand_path('../..', __FILE__)
2
+ require 'lib/helpers/git_helper'
3
+ require 'lib/flipp/flipp'
@@ -0,0 +1,15 @@
1
+ require File.join(File.dirname(__FILE__), '../lib/helpers/git_helper')
2
+
3
+ namespace :flipp do
4
+ desc 'Install flipp'
5
+ task :install do
6
+ # Move git hook into place
7
+ GitHelper.install_hook
8
+ end
9
+
10
+ desc 'Uninstall flipp'
11
+ task :uninstall do
12
+ # Remove git hook
13
+ GitHelper.uninstall_hook
14
+ end
15
+ end
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: flipp
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Mike Pack
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-02-19 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: active_record
16
+ requirement: &70345674000980 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70345674000980
25
+ - !ruby/object:Gem::Dependency
26
+ name: database_exporter
27
+ requirement: &70345673999500 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70345673999500
36
+ description: To alleviate issues around highly divergent development databases on
37
+ feature/refactor branches, flipp helps switch databases upon new branch checkouts.
38
+ email:
39
+ - mikepackdev@gmail.com
40
+ executables: []
41
+ extensions: []
42
+ extra_rdoc_files: []
43
+ files:
44
+ - README.md
45
+ - Rakefile
46
+ - flipp.gemspec
47
+ - tasks/flipp.rb
48
+ - lib/flipp/flipp.rb
49
+ - lib/flipp/railties/reestablish_connection.rb
50
+ - lib/flipp.rb
51
+ - lib/helpers/git_helper.rb
52
+ - spec/lib/flipp/flipp_spec.rb
53
+ - spec/lib/helpers/git_helper_spec.rb
54
+ - spec/spec_helper.rb
55
+ homepage: http://www.mikepackdev.com
56
+ licenses: []
57
+ post_install_message:
58
+ rdoc_options: []
59
+ require_paths:
60
+ - lib
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ! '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ! '>='
71
+ - !ruby/object:Gem::Version
72
+ version: 1.3.6
73
+ requirements: []
74
+ rubyforge_project:
75
+ rubygems_version: 1.8.10
76
+ signing_key:
77
+ specification_version: 3
78
+ summary: Switch development databases upon branch checkouts.
79
+ test_files:
80
+ - spec/lib/flipp/flipp_spec.rb
81
+ - spec/lib/helpers/git_helper_spec.rb
82
+ - spec/spec_helper.rb