enhanced_migrations 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,9 @@
1
+ 2007-11-05 Sean Soper <sean.soper@revolutionhealth.com>
2
+ * Ripping out of plugems architecture to make this into a standard plugin
3
+
4
+ 2007-11-01 Sean Soper <sean.soper@revolutionhealth.com>
5
+ * Fixed bug where an empty migrations_info table would create a non-parseable schema.rb
6
+ * Made plugin database independent
7
+ * Added capability to step through migrations using VERSION=[previous, next, first and last]
8
+ * dump_schema_information now returns all migrations, not just latest (credit to François Beausolei at http://blog.teksol.info/2007/11/1/enhanced-migrations-plugin-enhancement)
9
+ * Added tests which use SQLite and a task (enhanced_migrations:clean_sqlite_db) to the harness's rakefile to help with testing
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2007 Revolution Health Group LLC. All rights reserved.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,51 @@
1
+ = Enhanced Rails Migrations
2
+
3
+ Enhanced Rails Migrations is a plugin that makes rails development easier in a large team with multiple code branches.
4
+
5
+ Native rails db migrations are great for most of the teams. The troubles begin when many developers try to add a migration or when code is merged between branches. Since native migrations are based on incremental numbers, the name clashing is frequent. Same happens with merged code on an even larger scale. This plugin was born at the Revolution Health Group team to address the problems with large multi-branched development (see our blog entry - http://revolutiononrails.blogspot.com/2007/01/db-migrations-usage-at-rhg.html) where it has been successfully used since February '07.
6
+
7
+
8
+ == The Solution
9
+
10
+ There are a couple of patches against the Edge rails approaching the problem from different angles. You might want to try them unless you work on 1.1.6 or prefer plugins to handle such things.
11
+
12
+ The plugin monkey-patches ActiveRecord classes to replace the sequential number based rails migration mechanism with the timestamp based one. That allows to avoid name collisions. In addition, it maintains a tracking table of already run migrations instead of the standard single number schema_info. The table is being used for decision whether to run a migration. The biggest difference from the standard way is that migrations below the current schema version are still applied if they have not been applied yet (not in the tracking table).
13
+
14
+ Important: See the First Run section for details how to use it in existing projects.
15
+
16
+
17
+ == Compatibility
18
+
19
+ The code has been used mostly on 1.1.6 and has been tested against 1.2.5.
20
+
21
+
22
+ == Setup
23
+
24
+ === Installation
25
+
26
+ Install as any other Rails plugin:
27
+
28
+ ruby script/plugin install svn://rubyforge.org/var/svn/enhanced-mgrtns/enhanced_migrations
29
+
30
+
31
+ === Usage
32
+
33
+ There is no difference in migration usage - use 'script/generate migration' to generate a new migration and 'rake db:migrate' for migration.
34
+
35
+ 'schema_version' is depreciated. If you need to find the last run migration, use:
36
+ 'SELECT MAX(id) FROM migrations_info'
37
+
38
+
39
+ === First Run
40
+
41
+ If you are adding the plugin in a middle of the development process, when some migrations have been created and applied, you need to mark those as already run or 'rake db:migrate' would try to apply them again. The project contains a sample zero-number migration which queries the DB for the last run migration number and marks those in the new tracking table. It also deletes the schema_version table. To use it, copy 'migrations/000_run_migrations_marker.rb' from the project to your rails 'db/migrate' directory.
42
+
43
+ == License
44
+
45
+ Enhanced Rails Migrations is released under the MIT license.
46
+
47
+
48
+ == Support
49
+
50
+ The plugin RubyForge page is http://rubyforge.org/projects/enhanced-mgrtns
51
+
@@ -0,0 +1,64 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/config/environment")
2
+ require File.expand_path(File.dirname(__FILE__) + "/lib/enhanced_migrations")
3
+
4
+ require 'rake'
5
+ require 'rake/testtask'
6
+ require 'rake/gempackagetask'
7
+ require 'rake/rdoctask'
8
+ require 'tasks/rails'
9
+
10
+ Dir[File.dirname(__FILE__) + '/tasks/*.rake'].each { |rake| load rake }
11
+
12
+ # Custom rake task used to clean sqlite db files
13
+ SQLITE_DB_FILES = FileList['db/*.db']
14
+
15
+ namespace :enhanced_migrations do
16
+ task :clean_sqlite_db do
17
+ rm SQLITE_DB_FILES
18
+ end
19
+ end
20
+
21
+ desc 'Default: run unit tests.'
22
+ task :default => :test
23
+
24
+ desc 'Test the enhanced_migrations plugin.'
25
+ Rake::TestTask.new(:test) do |t|
26
+ t.libs << 'lib'
27
+ t.pattern = 'test/*_test.rb'
28
+ t.verbose = true
29
+ end
30
+
31
+ dist_dirs = [ "config", "db", "lib", "migrations", "tasks", "test" ]
32
+
33
+ gem_spec = Gem::Specification.new do |s|
34
+ s.platform = Gem::Platform::RUBY
35
+ s.name = "enhanced_migrations"
36
+ s.version = "1.2.0"
37
+ s.author = "RHG Team"
38
+ s.email = "rails-trunk@revolution.com"
39
+ s.summary = "Rails Enhanced Migrations"
40
+ s.files = [ "Changelog", "MIT-LICENSE", "Rakefile", "README" ]
41
+ dist_dirs.each do |dir|
42
+ s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| /(\.[svn|log|db])|(schema\.rb)/ === item }
43
+ end
44
+ s.autorequire = 'enhanced_migrations'
45
+ s.require_path = "lib"
46
+ s.test_files = Dir.glob('test/*_test.rb')
47
+ s.has_rdoc = false
48
+ s.extra_rdoc_files = ["README", "Changelog"]
49
+ s.add_dependency('rails', '>= 1.1.6')
50
+ end
51
+
52
+ gem = Rake::GemPackageTask.new(gem_spec) do |pkg|
53
+ pkg.need_tar = true
54
+ pkg.need_zip = true
55
+ end
56
+
57
+ desc 'Generate documentation for the enhanced_migrations plugin.'
58
+ Rake::RDocTask.new(:rdoc) do |rdoc|
59
+ rdoc.rdoc_dir = 'rdoc'
60
+ rdoc.title = 'Enhanced Migrations'
61
+ rdoc.options << '--line-numbers' << '--inline-source'
62
+ rdoc.rdoc_files.include('README')
63
+ rdoc.rdoc_files.include('lib/*.rb')
64
+ end
@@ -0,0 +1,25 @@
1
+ unless defined?(RAILS_ROOT)
2
+ root_path = File.join(File.dirname(__FILE__), '..')
3
+
4
+ unless RUBY_PLATFORM =~ /mswin32/
5
+ require 'pathname'
6
+ root_path = Pathname.new(root_path).cleanpath(true).to_s
7
+ end
8
+
9
+ RAILS_ROOT = root_path
10
+ end
11
+
12
+ unless defined?(Rails::Initializer)
13
+ if File.directory?("#{RAILS_ROOT}/vendor/rails")
14
+ require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer"
15
+ else
16
+ require 'rubygems'
17
+
18
+ rails_gem = Gem.cache.search('rails').find_all { |g| g.name == 'rails' }.sort { |a,b| a.version <=> b.version }.last rescue nil
19
+ raise "Couldn't find rails(#{rails_gem_version}" unless rails_gem
20
+ require_gem rails_gem.name, rails_gem.version.version
21
+ require rails_gem.full_gem_path + '/lib/initializer'
22
+ end
23
+
24
+ Rails::Initializer.run(:set_load_path)
25
+ end
@@ -0,0 +1,11 @@
1
+ development:
2
+ adapter: sqlite3
3
+ dbfile: db/em_dev.db
4
+
5
+ test:
6
+ adapter: sqlite3
7
+ dbfile: db/em_test.db
8
+
9
+ production:
10
+ adapter: sqlite3
11
+ dbfile: db/em_prod.db
@@ -0,0 +1,10 @@
1
+ unless defined? HAS_LOADED_ENVIRONMENT
2
+ HAS_LOADED_ENVIRONMENT = 1
3
+ require File.join(File.dirname(__FILE__), 'boot')
4
+
5
+ Rails::Initializer.run do |config|
6
+ config.frameworks -= [ :action_web_service, :action_mailer ]
7
+ end
8
+
9
+ RAILS_DEFAULT_LOGGER.info "Rails version: #{Rails::VERSION}"
10
+ end
@@ -0,0 +1,21 @@
1
+ # Settings specified here will take precedence over those in config/environment.rb
2
+
3
+ # In the development environment your application's code is reloaded on
4
+ # every request. This slows down response time but is perfect for development
5
+ # since you don't have to restart the webserver when you make code changes.
6
+ config.cache_classes = false
7
+
8
+ # Log error messages when you accidentally call methods on nil.
9
+ config.whiny_nils = true
10
+
11
+ # Enable the breakpoint server that script/breakpointer connects to
12
+ config.breakpoint_server = true
13
+
14
+ # Show full error reports and disable caching
15
+ config.action_controller.consider_all_requests_local = true
16
+ config.action_controller.perform_caching = false
17
+ config.action_view.cache_template_extensions = false
18
+ config.action_view.debug_rjs = true
19
+
20
+ # Don't care if the mailer can't send
21
+ config.action_mailer.raise_delivery_errors = false
@@ -0,0 +1,18 @@
1
+ # Settings specified here will take precedence over those in config/environment.rb
2
+
3
+ # The production environment is meant for finished, "live" apps.
4
+ # Code is not reloaded between requests
5
+ config.cache_classes = true
6
+
7
+ # Use a different logger for distributed setups
8
+ # config.logger = SyslogLogger.new
9
+
10
+ # Full error reports are disabled and caching is turned on
11
+ config.action_controller.consider_all_requests_local = false
12
+ config.action_controller.perform_caching = true
13
+
14
+ # Enable serving of images, stylesheets, and javascripts from an asset server
15
+ # config.action_controller.asset_host = "http://assets.example.com"
16
+
17
+ # Disable delivery errors if you bad email addresses should just be ignored
18
+ # config.action_mailer.raise_delivery_errors = false
@@ -0,0 +1,19 @@
1
+ # Settings specified here will take precedence over those in config/environment.rb
2
+
3
+ # The test environment is used exclusively to run your application's
4
+ # test suite. You never need to work with it otherwise. Remember that
5
+ # your test database is "scratch space" for the test suite and is wiped
6
+ # and recreated between test runs. Don't rely on the data there!
7
+ config.cache_classes = true
8
+
9
+ # Log error messages when you accidentally call methods on nil.
10
+ config.whiny_nils = true
11
+
12
+ # Show full error reports and disable caching
13
+ config.action_controller.consider_all_requests_local = true
14
+ config.action_controller.perform_caching = false
15
+
16
+ # Tell ActionMailer not to deliver emails to the real world.
17
+ # The :test delivery method accumulates sent emails in the
18
+ # ActionMailer::Base.deliveries array.
19
+ config.action_mailer.delivery_method = :test
@@ -0,0 +1,22 @@
1
+ ActionController::Routing::Routes.draw do |map|
2
+ # The priority is based upon order of creation: first created -> highest priority.
3
+
4
+ # Sample of regular route:
5
+ # map.connect 'products/:id', :controller => 'catalog', :action => 'view'
6
+ # Keep in mind you can assign values other than :controller and :action
7
+
8
+ # Sample of named route:
9
+ # map.purchase 'products/:id/purchase', :controller => 'catalog', :action => 'purchase'
10
+ # This route can be invoked with purchase_url(:id => product.id)
11
+
12
+ # You can have the root of your site routed by hooking up ''
13
+ # -- just remember to delete public/index.html.
14
+ # map.connect '', :controller => "welcome"
15
+
16
+ # Allow downloading Web Service WSDL as a file with an extension
17
+ # instead of a file named 'wsdl'
18
+ map.connect ':controller/service.wsdl', :action => 'wsdl'
19
+
20
+ # Install the default route as the lowest priority.
21
+ map.connect ':controller/:action/:id'
22
+ end
@@ -0,0 +1,12 @@
1
+ class CreateRecipesTable < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :recipes do |t|
4
+ t.column :name, :string
5
+ t.column :owner, :string
6
+ end
7
+ end
8
+
9
+ def self.down
10
+ drop_table :recipes
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ class AddRecipesForUser1 < ActiveRecord::Migration
2
+ def self.up
3
+ execute "INSERT INTO recipes (name, owner) VALUES ('Lemon Meringue Pie', 'user1')"
4
+ execute "INSERT INTO recipes (name, owner) VALUES ('Blueberry Pie', 'user1')"
5
+ execute "INSERT INTO recipes (name, owner) VALUES ('Sugar Cream Pie', 'user1')"
6
+ end
7
+
8
+ def self.down
9
+ execute "DELETE FROM recipes WHERE owner = 'user1'"
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ class AddRecipesForUser2 < ActiveRecord::Migration
2
+ def self.up
3
+ execute "INSERT INTO recipes (name, owner) VALUES ('Steak and Kidney Pie', 'user2')"
4
+ execute "INSERT INTO recipes (name, owner) VALUES ('Shephards Pie', 'user2')"
5
+ execute "INSERT INTO recipes (name, owner) VALUES ('Pot Pie', 'user2')"
6
+ end
7
+
8
+ def self.down
9
+ execute "DELETE FROM recipes WHERE owner = 'user2'"
10
+ end
11
+ end
@@ -0,0 +1,115 @@
1
+ module ActiveRecord
2
+ class Migrator
3
+
4
+ def self.migrate(migrations_path, target_version = nil)
5
+
6
+ ActiveRecord::Base.connection.initialize_schema_information
7
+
8
+ if target_version.nil? || (current_version <= target_version)
9
+ up(migrations_path, target_version)
10
+ else
11
+ down(migrations_path, target_version)
12
+ end
13
+
14
+ end
15
+
16
+ def self.current_version
17
+ ActiveRecord::Base.connection.select_one("SELECT MAX(id) as max FROM #{schema_info_table_name}")["max"].to_i rescue 0
18
+ end
19
+
20
+ def self.schema_info_table_name
21
+ ActiveRecord::Base.table_name_prefix + "migrations_info" + ActiveRecord::Base.table_name_suffix
22
+ end
23
+
24
+
25
+ private
26
+
27
+ def already_migrated?(version)
28
+ ActiveRecord::Base.connection.select_one("SELECT id FROM #{self.class.schema_info_table_name} WHERE id = #{version}") != nil
29
+ end
30
+
31
+ def set_schema_version(version)
32
+ if down?
33
+ ActiveRecord::Base.connection.execute("DELETE FROM #{self.class.schema_info_table_name} WHERE id = #{version}")
34
+ else
35
+ ActiveRecord::Base.connection.execute("INSERT INTO #{self.class.schema_info_table_name} VALUES(#{version}, #{ActiveRecord::Base.connection.quote(Time.now)})")
36
+ end
37
+ end
38
+
39
+ def irrelevant_migration?(version)
40
+ (up? && already_migrated?(version)) || (down? && (not already_migrated?(version)))
41
+ end
42
+
43
+ end
44
+ end
45
+
46
+
47
+ ### Fixing all places where schema_info was used
48
+
49
+ ActiveRecord::ConnectionAdapters::SchemaStatements.send(:define_method, :initialize_schema_information) do
50
+ begin
51
+ ActiveRecord::Base.connection.execute "CREATE TABLE #{ActiveRecord::Migrator.schema_info_table_name} (id #{type_to_sql(:integer)}, created_at #{type_to_sql(:datetime)}, PRIMARY KEY (id))"
52
+ rescue ActiveRecord::StatementInvalid
53
+ # Migrations schema has been intialized
54
+ end
55
+ end
56
+ ActiveRecord::ConnectionAdapters::SchemaStatements.send(:public, :initialize_schema_information)
57
+
58
+
59
+ ActiveRecord::ConnectionAdapters::SchemaStatements.send(:define_method, :dump_schema_information) do
60
+ begin
61
+ select_all("SELECT * FROM #{ActiveRecord::Migrator.schema_info_table_name} ORDER BY created_at, id").map do |migration|
62
+ "INSERT INTO #{ActiveRecord::Migrator.schema_info_table_name} VALUES(#{migration["id"]}, '#{migration["created_at"]}');\n"
63
+ end
64
+ rescue ActiveRecord::StatementInvalid
65
+ # No Schema Info
66
+ end
67
+ end
68
+ ActiveRecord::ConnectionAdapters::SchemaStatements.send(:public, :dump_schema_information)
69
+
70
+
71
+ ActiveRecord::SchemaDumper.send(:define_method, :initialize) do |connection|
72
+ @connection = connection
73
+ @types = @connection.native_database_types
74
+ version_id = @connection.select_one("SELECT MAX(id) as max FROM migrations_info")["max"] rescue nil
75
+ @info = version_id ? {'version' => version_id} : nil
76
+ end
77
+
78
+
79
+ ActiveRecord::SchemaDumper.send(:define_method, :tables) do |stream|
80
+ @connection.tables.sort.each do |tbl|
81
+ next if ["migrations_info", ignore_tables].flatten.any? do |ignored|
82
+ case ignored
83
+ when String: tbl == ignored
84
+ when Regexp: tbl =~ ignored
85
+ else
86
+ raise StandardError, 'ActiveRecord::SchemaDumper.ignore_tables accepts an array of String and / or Regexp values.'
87
+ end
88
+ end
89
+ table(tbl, stream)
90
+ end
91
+ end
92
+
93
+ # For enhanced migrations schema define info does not do much since previous migrations are applied regardless of the current version
94
+ module ActiveRecord
95
+ class Schema < Migration
96
+
97
+ def self.define(info={}, &block)
98
+ instance_eval(&block)
99
+
100
+ if info[:version]
101
+ initialize_schema_information
102
+ if Base.connection.select_one("SELECT id FROM #{ActiveRecord::Migrator.schema_info_table_name} WHERE id = #{info[:version]}") == nil
103
+ Base.connection.execute("INSERT INTO #{ActiveRecord::Migrator.schema_info_table_name} VALUES(#{info[:version]}, #{ActiveRecord::Base.connection.quote(Time.now)})")
104
+ end
105
+ end
106
+ end
107
+
108
+ end
109
+ end
110
+
111
+ require 'rails_generator/base'
112
+ require 'rails_generator/commands'
113
+ Rails::Generator::Commands::Base.send(:define_method, :next_migration_number) do
114
+ Time.now.utc.to_i.to_s
115
+ end
@@ -0,0 +1,45 @@
1
+ class RunMigrationsMarker < ActiveRecord::Migration
2
+ class << self
3
+
4
+ def up
5
+
6
+ begin
7
+
8
+ migration_numbers.each do |migration_number|
9
+ break if migration_number > old_migration_number
10
+ mark_already_run_migration(migration_number) if migration_number > 0
11
+ end
12
+
13
+ drop_table old_schema_info_table_name
14
+
15
+ rescue ActiveRecord::ActiveRecordError => ex
16
+ say "Ignoring the exception: #{ ex }"
17
+ end
18
+
19
+ end
20
+
21
+ def down
22
+ # nothing to do
23
+ end
24
+
25
+
26
+ private
27
+
28
+ def old_schema_info_table_name
29
+ ActiveRecord::Base.table_name_prefix + "schema_info" + ActiveRecord::Base.table_name_suffix
30
+ end
31
+
32
+ def old_migration_number
33
+ @old_migration_number ||= ActiveRecord::Base.connection.select_one("SELECT version FROM #{old_schema_info_table_name}")['version'].to_i rescue 0
34
+ end
35
+
36
+ def migration_numbers
37
+ Dir["#{RAILS_ROOT}/db/migrate/[0-9]*_*.rb"].collect { |file| file[/(\d+)_[^\/]+\.rb$/][$1].to_i }.sort
38
+ end
39
+
40
+ def mark_already_run_migration(migration_number)
41
+ ActiveRecord::Base.connection.execute("INSERT INTO #{ActiveRecord::Migrator.schema_info_table_name} VALUES(#{migration_number}, NOW())")
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,38 @@
1
+ require 'rake'
2
+
3
+ def migration_numbers
4
+ Dir["#{RAILS_ROOT}/db/migrate/[0-9]*_*.rb"].collect { |file| file[/(\d+)_[^\/]+\.rb$/][$1].to_i }.sort
5
+ end
6
+
7
+ def previous_migration
8
+ raise "No migrations have been run yet" if ActiveRecord::Migrator.current_version == 0
9
+ return "0" if migration_numbers.first == ActiveRecord::Migrator.current_version
10
+ "#{migration_numbers.fetch(migration_numbers.index(ActiveRecord::Migrator.current_version) - 1)}" rescue nil
11
+ end
12
+
13
+ def next_migration
14
+ raise "Already at last migration" if ActiveRecord::Migrator.current_version == migration_numbers.last
15
+ return "#{migration_numbers.first}" if ActiveRecord::Migrator.current_version == 0
16
+ "#{migration_numbers.fetch(migration_numbers.index(ActiveRecord::Migrator.current_version) + 1)}" rescue nil
17
+ end
18
+
19
+ namespace :enhanced_migrations do
20
+ task :set_env do
21
+ ENV["VERSION"] = case ENV["VERSION"]
22
+ when "prev", "previous"
23
+ previous_migration
24
+ when "next"
25
+ next_migration
26
+ when "first"
27
+ "#{migration_numbers.first}"
28
+ when "last"
29
+ "#{migration_numbers.last}"
30
+ when /\d+/
31
+ ENV["VERSION"]
32
+ else
33
+ nil
34
+ end
35
+ end
36
+ end
37
+
38
+ task 'db:migrate' => 'enhanced_migrations:set_env'
@@ -0,0 +1,24 @@
1
+ require 'stringio'
2
+
3
+ # Mix-in for capturing standard output.
4
+ module CaptureStdout
5
+ def capture_stdout
6
+ s = StringIO.new
7
+ oldstdout = $stdout
8
+ $stdout = s
9
+ yield
10
+ s.string
11
+ ensure
12
+ $stdout = oldstdout
13
+ end
14
+
15
+ def capture_stderr
16
+ s = StringIO.new
17
+ oldstderr = $stderr
18
+ $stderr = s
19
+ yield
20
+ s.string
21
+ ensure
22
+ $stderr = oldstderr
23
+ end
24
+ end
@@ -0,0 +1,105 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class MigrationTest < Test::Unit::TestCase
4
+ include CaptureStdout
5
+
6
+ def setup
7
+ ENV["RAILS_ENV"] = "test"
8
+ capture_stdout do
9
+ Rake.application.handle_options
10
+ Rake.application.load_rakefile
11
+ end
12
+ ENV.delete("VERSION") if ENV["VERSION"]
13
+
14
+ migrate_db
15
+ @connection = ActiveRecord::Base.connection
16
+ end
17
+
18
+ def teardown
19
+ ENV["VERSION"] = "0"
20
+ migrate_db
21
+ end
22
+
23
+ def test_migrations_ran
24
+ recipes = @connection.select_all("SELECT * FROM recipes")
25
+ assert recipes.length > 0
26
+ end
27
+
28
+ def test_previous_migration_number_runs
29
+ # Simulate a migration with a lower migration number having not been run yet
30
+ @connection.execute "DELETE FROM migrations_info WHERE id = '1193800624'"
31
+ @connection.execute "DELETE FROM recipes WHERE owner = 'user1'"
32
+ recipes = @connection.select_all("SELECT * FROM recipes WHERE owner = 'user1'")
33
+ assert recipes.length == 0
34
+
35
+ migrate_db
36
+ recipes = @connection.select_all("SELECT * FROM recipes WHERE owner = 'user1'")
37
+ assert recipes.length > 0
38
+ end
39
+
40
+ def test_migrate_previous
41
+ ENV["VERSION"] = "previous"
42
+ migrate_db
43
+
44
+ recipes = @connection.select_all("SELECT * FROM recipes WHERE owner = 'user2'")
45
+ assert recipes.length == 0
46
+ end
47
+
48
+ def test_migrate_next
49
+ test_migrate_previous
50
+ ENV["VERSION"] = "next"
51
+ migrate_db
52
+
53
+ recipes = @connection.select_all("SELECT * FROM recipes WHERE owner = 'user2'")
54
+ assert recipes.length > 0
55
+ end
56
+
57
+ def test_migrate_first
58
+ ENV["VERSION"] = "first"
59
+ migrate_db
60
+
61
+ recipes = @connection.select_all("SELECT * FROM recipes WHERE owner = 'user1'")
62
+ assert recipes.length == 0
63
+ end
64
+
65
+ def test_migrate_last
66
+ test_migrate_first
67
+
68
+ ENV["VERSION"] = "last"
69
+ migrate_db
70
+ recipes = @connection.select_all("SELECT * FROM recipes WHERE owner = 'user2'")
71
+ assert recipes.length > 0
72
+ end
73
+
74
+ def test_migrate_previous_at_zero_migration
75
+ ENV["VERSION"] = "0"
76
+ migrate_db
77
+
78
+ ENV["VERSION"] = "previous"
79
+ assert_raises(RuntimeError) { migrate_db }
80
+ end
81
+
82
+ def test_migrate_next_at_last_migration
83
+ ENV["VERSION"] = "next"
84
+ assert_raises(RuntimeError) { migrate_db }
85
+ end
86
+
87
+ def test_schema_dump
88
+ assert ActiveRecord::Base.connection.dump_schema_information.length == 3
89
+ end
90
+
91
+ private
92
+
93
+ def migrate_db
94
+ reset_task_invocation('db:migrate')
95
+ capture_stdout do
96
+ Rake::Task['db:migrate'].invoke
97
+ end
98
+ end
99
+
100
+ def reset_task_invocation(task)
101
+ Rake::Task['enhanced_migrations:set_env'].instance_variable_set(:@already_invoked, false)
102
+ Rake::Task[task].instance_variable_set(:@already_invoked, false)
103
+ end
104
+
105
+ end
@@ -0,0 +1,13 @@
1
+ ENV["RAILS_ENV"] = "test"
2
+ require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
3
+ require File.expand_path(File.dirname(__FILE__) + "/../lib/enhanced_migrations")
4
+ require 'test/unit'
5
+ require 'test_help'
6
+ require File.dirname(__FILE__) + '/capture_stdout'
7
+
8
+ Dir[File.dirname(__FILE__) + '/../tasks/*.rake'].each { |rake| load rake }
9
+
10
+ class Test::Unit::TestCase
11
+ self.use_transactional_fixtures = true if self.respond_to?(:use_transactional_fixtures)
12
+ self.use_instantiated_fixtures = false if self.respond_to?(:use_instantiated_fixtures)
13
+ end
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.4
3
+ specification_version: 1
4
+ name: enhanced_migrations
5
+ version: !ruby/object:Gem::Version
6
+ version: 1.2.0
7
+ date: 2007-11-06 00:00:00 -05:00
8
+ summary: Rails Enhanced Migrations
9
+ require_paths:
10
+ - lib
11
+ email: rails-trunk@revolution.com
12
+ homepage:
13
+ rubyforge_project:
14
+ description:
15
+ autorequire: enhanced_migrations
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: false
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - RHG Team
31
+ files:
32
+ - Changelog
33
+ - MIT-LICENSE
34
+ - Rakefile
35
+ - README
36
+ - config/boot.rb
37
+ - config/database.yml
38
+ - config/environment.rb
39
+ - config/environments
40
+ - config/routes.rb
41
+ - config/environments/development.rb
42
+ - config/environments/production.rb
43
+ - config/environments/test.rb
44
+ - db/migrate
45
+ - db/migrate/1193798832_create_recipes_table.rb
46
+ - db/migrate/1193800624_add_recipes_for_user1.rb
47
+ - db/migrate/1193842239_add_recipes_for_user2.rb
48
+ - lib/enhanced_migrations.rb
49
+ - migrations/000_run_migrations_marker.rb
50
+ - tasks/enhanced_migrations.rake
51
+ - test/capture_stdout.rb
52
+ - test/migration_test.rb
53
+ - test/test_helper.rb
54
+ test_files:
55
+ - test/migration_test.rb
56
+ rdoc_options: []
57
+
58
+ extra_rdoc_files:
59
+ - README
60
+ - Changelog
61
+ executables: []
62
+
63
+ extensions: []
64
+
65
+ requirements: []
66
+
67
+ dependencies:
68
+ - !ruby/object:Gem::Dependency
69
+ name: rails
70
+ version_requirement:
71
+ version_requirements: !ruby/object:Gem::Version::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: 1.1.6
76
+ version: