seed_migration 1.0.0
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.
- checksums.yaml +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +209 -0
- data/Rakefile +29 -0
- data/app/models/seed_migration/data_migration.rb +5 -0
- data/db/migrate/20140310150145_create_data_migrations.rb +13 -0
- data/lib/extra_tasks.rb +19 -0
- data/lib/generators/seed_migration/seed_migration_generator.rb +19 -0
- data/lib/seed_migration.rb +25 -0
- data/lib/seed_migration/engine.rb +37 -0
- data/lib/seed_migration/migration.rb +11 -0
- data/lib/seed_migration/migrator.rb +232 -0
- data/lib/seed_migration/register_entry.rb +29 -0
- data/lib/seed_migration/version.rb +3 -0
- data/lib/tasks/seed_migration_tasks.rake +25 -0
- metadata +144 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0b54739a076acaa3fc85f4683abb4d40b4c2ecff
|
4
|
+
data.tar.gz: f0f5e426abb6a780124c484ddd0ff93a233892f7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 48e288fcec4d8b6d6d683f8ef2915435bb0c31db0cc8ae03cf5434380d8c5da4c05778a5b0a65324c4b980e4e0d840fbf636f9fddb365856e7fcfa96bc1fb0d6
|
7
|
+
data.tar.gz: 36a349a3aecc231a3374c27c153ddcc4809cae68de74f845a993c99561e6e382c145f5fb24185f4e3b8fb43d7135ada4a43d73e4115c4bc99c1f2f7f5877ac57
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Andy O'Neill <aoneill@harrys.com>
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,209 @@
|
|
1
|
+
TODO : Add travis configuration, and then badge, eventually gemfury badge too.
|
2
|
+
|
3
|
+
# SeedMigration
|
4
|
+
|
5
|
+
Harry's Data Migrations are a way to manage changes to seed data in a rails app in a similar way to how schema migrations are handled.
|
6
|
+
|
7
|
+
|
8
|
+
## Intro
|
9
|
+
A data migration library, similar to rails built-in schema migration. It also auto generates a `db/seeds.rb` file, similar to how schema migrations generate the `db/schema.rb` file.
|
10
|
+
Using this auto generated seed file makes it quick and easy to setup new environments, usually development or test.
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
|
14
|
+
Add `gem 'seed_migration'` to your `Gemfile`:
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
gem 'seed_migration', :github => 'harrystech/seed_migration'
|
18
|
+
```
|
19
|
+
|
20
|
+
Note : It'll soon be released on rubygems.org.
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
### Install and run the internal migrations
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
rake seed_migration:install:migrations
|
28
|
+
rake db:migrate
|
29
|
+
```
|
30
|
+
|
31
|
+
That will create the table to keep track of data migrations.
|
32
|
+
|
33
|
+
### Generate a new migration
|
34
|
+
|
35
|
+
`SeedMigration` adds a new rails generator :
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
rails g seed_migration AddFoo
|
39
|
+
```
|
40
|
+
A new file will be created under `db/data/` using rails migration convention:
|
41
|
+
|
42
|
+
```
|
43
|
+
db/data/20140407162007_add_foo.rb
|
44
|
+
```
|
45
|
+
|
46
|
+
You'll need to implement the `#up` method and if you need to be able to rollback, the `#down` method.
|
47
|
+
|
48
|
+
### Running the migrations
|
49
|
+
|
50
|
+
To run all pending migrations, simply use
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
rake seed:migrate
|
54
|
+
```
|
55
|
+
|
56
|
+
If needed, you can run a specific migration:
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
rake seed:migrate MIGRATION=20140407162007_add_foo.rb
|
60
|
+
```
|
61
|
+
|
62
|
+
### Rollback
|
63
|
+
|
64
|
+
Rolling back the last migration is as simple as:
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
rake seed:rollback
|
68
|
+
```
|
69
|
+
|
70
|
+
You can rollback more than one migration at the same time:
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
rake seed:rollback STEPS=3 # rollback last 3 migrations
|
74
|
+
```
|
75
|
+
|
76
|
+
Or rollback a specific migration:
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
rake seed:rollback MIGRATION=20140407162007_add_foo.rb
|
80
|
+
```
|
81
|
+
|
82
|
+
### Registering models
|
83
|
+
|
84
|
+
By default, `SeedMigration` won't seen any data after running `seed:migrate`. You have to manually register the models in the configuration file.
|
85
|
+
|
86
|
+
Simply register a model:
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
SeedMigration.register Product
|
90
|
+
```
|
91
|
+
|
92
|
+
You can customize the 'seeded' attribute list:
|
93
|
+
|
94
|
+
```ruby
|
95
|
+
SeedMigration.register User do
|
96
|
+
exclude :id, :password
|
97
|
+
end
|
98
|
+
```
|
99
|
+
|
100
|
+
This will create a `seeds.rb` containing all User and Product in the database:
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
# encoding: UTF-8
|
104
|
+
# This file is auto-generated from the current content of the database. Instead
|
105
|
+
# of editing this file, please use the migrations feature of Seed Migration to
|
106
|
+
# incrementally modify your database, and then regenerate this seed file.
|
107
|
+
#
|
108
|
+
# If you need to create see the database on another system, you should be using
|
109
|
+
# db:seed, not running all the migrations from scratch. The latter is a flawed
|
110
|
+
# and unsustainable approach (the more migrations you'll amass, the slower
|
111
|
+
# it'll run and the greater likelihood for issues).
|
112
|
+
#
|
113
|
+
# It's strongly recommended to check this file into your version control system.
|
114
|
+
|
115
|
+
ActiveRecord::Base.transaction do
|
116
|
+
Product.create("id"=>1, "name"=>"foo", "created_at"=>"2014-04-04T15:42:24Z", "updated_at"=>"2014-04-04T15:42:24Z")
|
117
|
+
Product.create("id"=>2, "name"=>"bar", "created_at"=>"2014-04-04T15:42:24Z", "updated_at"=>"2014-04-04T15:42:24Z")
|
118
|
+
# ...
|
119
|
+
User.create("id"=>1, "name"=>"admin", "created_at"=>"2014-04-04T15:42:24Z", "updated_at"=>"2014-04-04T15:42:24Z")
|
120
|
+
# ...
|
121
|
+
end
|
122
|
+
|
123
|
+
SeedMigration::Migrator.bootstrap(20140404193326)
|
124
|
+
```
|
125
|
+
|
126
|
+
|
127
|
+
### Deployment notes
|
128
|
+
|
129
|
+
It is recommended to add the `rake seed:migrate` to your deploy script, so each new data migrations is ran upon new deploys.
|
130
|
+
You can enable the `extend_native_migration_task` option to automatically run `rake seed:migrate` after `rake db:migrate`.
|
131
|
+
|
132
|
+
## Example
|
133
|
+
|
134
|
+
```ruby
|
135
|
+
rails g seed_migration AddADummyProduct
|
136
|
+
```
|
137
|
+
|
138
|
+
```ruby
|
139
|
+
class AddADummyProduct < SeedMigration::Migration
|
140
|
+
def up
|
141
|
+
Product.create!({
|
142
|
+
:asset_path => "valentines-day.jpg",
|
143
|
+
:title => "Valentine's Day II: the revenge!",
|
144
|
+
:active => false,
|
145
|
+
:default => false,
|
146
|
+
}, :without_protection => true)
|
147
|
+
end
|
148
|
+
|
149
|
+
def down
|
150
|
+
Product.destroy_all(:title => "Valentine's Day II: the revenge!")
|
151
|
+
end
|
152
|
+
end
|
153
|
+
```
|
154
|
+
|
155
|
+
## Configuration
|
156
|
+
|
157
|
+
`SeedMigration` can be configured using an initializer file.
|
158
|
+
|
159
|
+
### List of available configurations :
|
160
|
+
|
161
|
+
- `extend_native_migration_task (default=false)`
|
162
|
+
- `pending_migrations_warning_level (default=:warn)`
|
163
|
+
- `ignore_ids (default=false)`
|
164
|
+
- `migration_table_name (default='seed_migration_data_migrations')`: Override the table name for the internal model that holds the migrations
|
165
|
+
|
166
|
+
#### example:
|
167
|
+
|
168
|
+
```ruby
|
169
|
+
# config/initializers/seed_migration.rb
|
170
|
+
|
171
|
+
SeedMigration.config do |c|
|
172
|
+
c.migration_table_name = 'data_migrations'
|
173
|
+
c.extend_native_migration_task = true
|
174
|
+
c.pending_migrations_warning_level = :error
|
175
|
+
end
|
176
|
+
|
177
|
+
SeedMigration.register User do
|
178
|
+
exclude :id, :password
|
179
|
+
end
|
180
|
+
SeedMigration.register Product
|
181
|
+
```
|
182
|
+
|
183
|
+
## Compatibility
|
184
|
+
|
185
|
+
At the moment, we rely by default on
|
186
|
+
|
187
|
+
```
|
188
|
+
ActiveRecord::Base.connection.reset_pk_sequence!
|
189
|
+
```
|
190
|
+
which is `pg` only.
|
191
|
+
|
192
|
+
If you need to use this gem with another database, use the `ignore_ids` configuration.
|
193
|
+
|
194
|
+
|
195
|
+
## Runnings tests
|
196
|
+
|
197
|
+
|
198
|
+
```ruby
|
199
|
+
RAILS_ENV=test bundle exec rake app:db:reset
|
200
|
+
bundle exec rspec spec
|
201
|
+
```
|
202
|
+
|
203
|
+
## Contributing
|
204
|
+
|
205
|
+
1. Fork it
|
206
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
207
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
208
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
209
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'rdoc/task'
|
9
|
+
rescue LoadError
|
10
|
+
require 'rdoc/rdoc'
|
11
|
+
require 'rake/rdoctask'
|
12
|
+
RDoc::Task = Rake::RDocTask
|
13
|
+
end
|
14
|
+
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
17
|
+
rdoc.title = 'SeedMigration'
|
18
|
+
rdoc.options << '--line-numbers'
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
+
end
|
22
|
+
|
23
|
+
APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
|
24
|
+
load 'rails/tasks/engine.rake'
|
25
|
+
|
26
|
+
|
27
|
+
|
28
|
+
Bundler::GemHelper.install_tasks
|
29
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class CreateDataMigrations < ActiveRecord::Migration
|
2
|
+
def up
|
3
|
+
create_table SeedMigration.migration_table_name do |t|
|
4
|
+
t.string :version
|
5
|
+
t.integer :runtime
|
6
|
+
t.datetime :migrated_on
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def down
|
11
|
+
drop_table SeedMigration.migration_table_name
|
12
|
+
end
|
13
|
+
end
|
data/lib/extra_tasks.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# This task is manually loaded after the engine has been initialized
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
# If a rake task is ran from the parent applicatiom, all Rails rasks are
|
6
|
+
# already loaded.
|
7
|
+
# But if `rails {s|c}` is ran from the parent application, then tasks are not
|
8
|
+
# loaded
|
9
|
+
Rake::Task['db:migrate']
|
10
|
+
rescue RuntimeError
|
11
|
+
Rails.application.load_tasks
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
if SeedMigration.extend_native_migration_task
|
16
|
+
Rake::Task['db:migrate'].enhance do
|
17
|
+
Rake::Task['seed:migrate'].invoke
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
require 'rails/generators/named_base'
|
3
|
+
|
4
|
+
module SeedMigration
|
5
|
+
module Generators
|
6
|
+
class SeedMigrationGenerator < Rails::Generators::NamedBase
|
7
|
+
|
8
|
+
namespace "seed_migration"
|
9
|
+
desc "Creates a seed migration"
|
10
|
+
class_option :migration_name, :type => :string, :default => nil
|
11
|
+
argument :timestamp, :type => :string, :required => false, :default => Time.now.utc.strftime("%Y%m%d%H%M%S")
|
12
|
+
|
13
|
+
def create_seed_migration_file
|
14
|
+
path = SeedMigration::Migrator::DATA_MIGRATION_DIRECTORY
|
15
|
+
create_file path.join("#{timestamp}_#{file_name.gsub(/([A-Z])/, '_\1').downcase}.rb"),"class #{file_name.camelize} < SeedMigration::Migration\n def up\n \n end\n\n def down\n \n end\nend"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "seed_migration/version"
|
2
|
+
require "seed_migration/engine"
|
3
|
+
|
4
|
+
module SeedMigration
|
5
|
+
autoload :Migrator, "seed_migration/migrator" # Is it needed ?
|
6
|
+
autoload :Migration, "seed_migration/migration"
|
7
|
+
autoload :RegisterEntry, "seed_migration/register_entry"
|
8
|
+
|
9
|
+
@@registrar = Set.new
|
10
|
+
mattr_accessor :registrar
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def register(model, &block)
|
14
|
+
unregister model
|
15
|
+
entry = RegisterEntry.new(model)
|
16
|
+
entry.instance_eval &block if block_given?
|
17
|
+
|
18
|
+
self.registrar << entry
|
19
|
+
end
|
20
|
+
|
21
|
+
def unregister(model)
|
22
|
+
self.registrar.delete_if { |entry| entry.model == model }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'rails'
|
2
|
+
|
3
|
+
module SeedMigration
|
4
|
+
|
5
|
+
class << self
|
6
|
+
mattr_accessor :extend_native_migration_task
|
7
|
+
mattr_accessor :migration_table_name
|
8
|
+
mattr_accessor :ignore_ids
|
9
|
+
|
10
|
+
self.migration_table_name = 'seed_migration_data_migrations' # Hardcoded, evil!
|
11
|
+
self.extend_native_migration_task = false
|
12
|
+
self.ignore_ids = false
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.config(&block)
|
16
|
+
yield self
|
17
|
+
after_config
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.after_config
|
21
|
+
if self.extend_native_migration_task
|
22
|
+
require_relative '../extra_tasks.rb'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class Engine < ::Rails::Engine
|
27
|
+
isolate_namespace SeedMigration
|
28
|
+
|
29
|
+
config.generators do |g|
|
30
|
+
g.test_framework :rspec, :fixture => false
|
31
|
+
g.fixture_replacement :factory_girl, :dir => 'spec/factories'
|
32
|
+
g.assets false
|
33
|
+
g.helper false
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,232 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
module SeedMigration
|
4
|
+
class Migrator
|
5
|
+
DATA_MIGRATION_DIRECTORY = Rails.root.join("db", "data")
|
6
|
+
SEEDS_FILE_PATH = Rails.root.join('db', 'seeds.rb')
|
7
|
+
|
8
|
+
def self.migration_path(filename)
|
9
|
+
DATA_MIGRATION_DIRECTORY.join(filename).to_s
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(migration_path)
|
13
|
+
@path = Pathname.new(migration_path)
|
14
|
+
raise "Can't find migration at #{@path.to_s}." if !@path.exist?
|
15
|
+
end
|
16
|
+
|
17
|
+
def up
|
18
|
+
# Check if we already migrated this file
|
19
|
+
klass = class_from_path
|
20
|
+
version = @path.basename.to_s.split("_", 2).first
|
21
|
+
raise "#{klass} has already been migrated." if SeedMigration::DataMigration.where(version: version).first
|
22
|
+
|
23
|
+
start_time = Time.now
|
24
|
+
announce("#{klass}: migrating")
|
25
|
+
klass.new.up
|
26
|
+
end_time = Time.now
|
27
|
+
runtime = (end_time - start_time).to_d.round(2)
|
28
|
+
|
29
|
+
# Create record
|
30
|
+
migration = SeedMigration::DataMigration.new
|
31
|
+
migration.version = version
|
32
|
+
migration.runtime = runtime.to_i
|
33
|
+
migration.migrated_on = DateTime.now
|
34
|
+
begin
|
35
|
+
migration.save!
|
36
|
+
rescue Exception => e
|
37
|
+
puts e
|
38
|
+
end
|
39
|
+
announce("#{klass}: migrated (#{runtime}s)")
|
40
|
+
end
|
41
|
+
|
42
|
+
def down
|
43
|
+
klass = class_from_path
|
44
|
+
version = @path.basename.to_s.split("_", 2).first
|
45
|
+
|
46
|
+
# Get migration record
|
47
|
+
migration = SeedMigration::DataMigration.where(version: version).first
|
48
|
+
|
49
|
+
# Do not proceed without it!
|
50
|
+
raise "#{klass} hasn't been migrated." if migration.nil?
|
51
|
+
|
52
|
+
# Revert
|
53
|
+
start_time = Time.now
|
54
|
+
announce("#{klass}: reverting")
|
55
|
+
klass.new.down
|
56
|
+
end_time = Time.now
|
57
|
+
runtime = (end_time - start_time).to_d.round(2)
|
58
|
+
|
59
|
+
# Delete record of migration
|
60
|
+
migration.destroy
|
61
|
+
announce("#{klass}: reverted (#{runtime}s)")
|
62
|
+
end
|
63
|
+
|
64
|
+
# Rake methods
|
65
|
+
def self.run_new_migrations
|
66
|
+
# TODO : Add warning about empty registered_models
|
67
|
+
get_new_migrations.each do |migration|
|
68
|
+
migration = migration_path(migration)
|
69
|
+
new(migration).up
|
70
|
+
end
|
71
|
+
create_seed_file
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.last_migration
|
75
|
+
return SeedMigration::DataMigration.maximum("version")
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.rollback_migrations(steps = 1)
|
79
|
+
to_run = get_last_x_migrations(steps)
|
80
|
+
to_run.each do |migration|
|
81
|
+
new(migration).down
|
82
|
+
end
|
83
|
+
create_seed_file
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.bootstrap(last_timestamp = nil)
|
87
|
+
# replace with logger ?
|
88
|
+
p "Assume migrated up to #{last_timestamp}"
|
89
|
+
files = SeedMigration::Migrator.get_migration_files(last_timestamp.to_s)
|
90
|
+
files.each do |file|
|
91
|
+
name = file.split('/').last
|
92
|
+
version = name.split('_').first
|
93
|
+
migration = SeedMigration::DataMigration.new
|
94
|
+
migration.version = version
|
95
|
+
migration.runtime = 0
|
96
|
+
migration.migrated_on = DateTime.now
|
97
|
+
migration.save!
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
def class_from_path
|
104
|
+
announce("Loading migration class at '#{@path}'")
|
105
|
+
require @path.to_s
|
106
|
+
filename = @path.basename.to_s
|
107
|
+
classname_and_extension = filename.split("_", 2).last
|
108
|
+
classname = classname_and_extension.split(".").first.camelize
|
109
|
+
classname.constantize
|
110
|
+
end
|
111
|
+
|
112
|
+
def announce(text)
|
113
|
+
length = [0, 75 - text.length].max
|
114
|
+
puts "== %s %s" % [text, "=" * length]
|
115
|
+
end
|
116
|
+
|
117
|
+
def self.get_new_migrations
|
118
|
+
migrations = []
|
119
|
+
files = get_migration_files
|
120
|
+
|
121
|
+
# If there is no last migration, all migrations are new
|
122
|
+
if get_last_migration_date.nil?
|
123
|
+
return files
|
124
|
+
end
|
125
|
+
|
126
|
+
all_migration_versions = SeedMigration::DataMigration.all.map(&:version)
|
127
|
+
|
128
|
+
files.each do |file|
|
129
|
+
filename = file.split('/').last
|
130
|
+
version = filename.split('_').first
|
131
|
+
if !all_migration_versions.include?(version)
|
132
|
+
migrations << filename
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Sort the files so they execute in order
|
137
|
+
migrations.sort!
|
138
|
+
|
139
|
+
return migrations
|
140
|
+
end
|
141
|
+
|
142
|
+
def self.get_last_x_migrations(x = 1)
|
143
|
+
# Grab data from DB
|
144
|
+
migrations = SeedMigration::DataMigration.order("version DESC").limit(x).pluck("version")
|
145
|
+
|
146
|
+
# Get actual files to load
|
147
|
+
to_rollback = []
|
148
|
+
files = get_migration_files
|
149
|
+
migrations.each do |migration|
|
150
|
+
files.each do |file|
|
151
|
+
if !file.split('/').last[migration].nil?
|
152
|
+
to_rollback << file
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
return to_rollback
|
158
|
+
end
|
159
|
+
|
160
|
+
def self.get_last_migration_date
|
161
|
+
return nil if SeedMigration::DataMigration.count == 0
|
162
|
+
DateTime.parse(last_migration)
|
163
|
+
end
|
164
|
+
|
165
|
+
def self.get_migration_files(last_timestamp = nil)
|
166
|
+
files = Dir.glob(SeedMigration::Migrator.migration_path("*_*.rb"))
|
167
|
+
if last_timestamp.present?
|
168
|
+
files.delete_if do |file|
|
169
|
+
timestamp = File.basename(file).split('_').first
|
170
|
+
timestamp > last_timestamp
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
# Just in case
|
175
|
+
files.sort!
|
176
|
+
end
|
177
|
+
|
178
|
+
def self.create_seed_file
|
179
|
+
if !Rails.env.development?
|
180
|
+
return
|
181
|
+
end
|
182
|
+
File.open(SEEDS_FILE_PATH, 'w') do |file|
|
183
|
+
file.write <<-eos
|
184
|
+
# encoding: UTF-8
|
185
|
+
# This file is auto-generated from the current content of the database. Instead
|
186
|
+
# of editing this file, please use the migrations feature of Seed Migration to
|
187
|
+
# incrementally modify your database, and then regenerate this seed file.
|
188
|
+
#
|
189
|
+
# If you need to create see the database on another system, you should be using
|
190
|
+
# db:seed, not running all the migrations from scratch. The latter is a flawed
|
191
|
+
# and unsustainable approach (the more migrations you'll amass, the slower
|
192
|
+
# it'll run and the greater likelihood for issues).
|
193
|
+
#
|
194
|
+
# It's strongly recommended to check this file into your version control system.
|
195
|
+
|
196
|
+
ActiveRecord::Base.transaction do
|
197
|
+
eos
|
198
|
+
SeedMigration.registrar.each do |register_entry|
|
199
|
+
register_entry.model.order('id').each do |instance|
|
200
|
+
file.write generate_model_creation_string(instance, register_entry)
|
201
|
+
end
|
202
|
+
|
203
|
+
if !SeedMigration.ignore_ids
|
204
|
+
file.write <<-eos
|
205
|
+
ActiveRecord::Base.connection.reset_pk_sequence!('#{register_entry.model.table_name}')
|
206
|
+
eos
|
207
|
+
end
|
208
|
+
end
|
209
|
+
file.write <<-eos
|
210
|
+
end
|
211
|
+
|
212
|
+
SeedMigration::Migrator.bootstrap(#{last_migration})
|
213
|
+
eos
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def self.generate_model_creation_string(instance, register_entry)
|
218
|
+
attributes = instance.attributes.select {|key| register_entry.attributes.include?(key) }
|
219
|
+
if SeedMigration.ignore_ids
|
220
|
+
attributes.delete('id')
|
221
|
+
end
|
222
|
+
sorted_attributes = {}
|
223
|
+
attributes.sort.each do |key, value|
|
224
|
+
sorted_attributes[key] = value
|
225
|
+
end
|
226
|
+
return <<-eos
|
227
|
+
|
228
|
+
#{instance.class}.create(#{JSON.parse(sorted_attributes.to_json).to_s}, :without_protection => true)
|
229
|
+
eos
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module SeedMigration
|
2
|
+
class RegisterEntry
|
3
|
+
attr_reader :model
|
4
|
+
attr_accessor :attributes
|
5
|
+
|
6
|
+
def initialize(model)
|
7
|
+
@model = model
|
8
|
+
@attributes = model.attribute_names.dup
|
9
|
+
end
|
10
|
+
|
11
|
+
def exclude(*attrs)
|
12
|
+
attrs.map(&:to_s).each { |attr| exclude_single_attributes attr }
|
13
|
+
end
|
14
|
+
|
15
|
+
def eql?(object)
|
16
|
+
object.class == self.class && object.model == self.model
|
17
|
+
end
|
18
|
+
|
19
|
+
def hash
|
20
|
+
model.hash
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def exclude_single_attributes(attr)
|
26
|
+
@attributes.delete attr
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
namespace :seed do
|
2
|
+
desc "Run new data migrations."
|
3
|
+
task :migrate => :environment do
|
4
|
+
filename = ENV["MIGRATION"]
|
5
|
+
if filename.blank?
|
6
|
+
# Run any outstanding migrations
|
7
|
+
SeedMigration::Migrator.run_new_migrations
|
8
|
+
else
|
9
|
+
path = SeedMigration::Migrator.migration_path(filename)
|
10
|
+
SeedMigration::Migrator.new(path).up
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
desc "Revert last data migration."
|
15
|
+
task :rollback => :environment do
|
16
|
+
filename = ENV["MIGRATION"]
|
17
|
+
if filename.blank?
|
18
|
+
steps = ENV["STEP"] || 1
|
19
|
+
SeedMigration::Migrator.rollback_migrations(steps)
|
20
|
+
else
|
21
|
+
path = SeedMigration::Migrator.migration_path(filename)
|
22
|
+
SeedMigration::Migrator.new(path).down
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: seed_migration
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Andy O'Neill
|
8
|
+
- Daniel Schwartz
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-04-29 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rails
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ~>
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: 3.2.17
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ~>
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 3.2.17
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: sqlite3
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - '>='
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0'
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - '>='
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: pg
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - '>='
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: pry
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: rspec-rails
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - '>='
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: rspec-mocks
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - '>='
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - '>='
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
description: Rails gem for Data Migrations
|
99
|
+
email:
|
100
|
+
- aoneill@harrys.com
|
101
|
+
- daniel@harrys.com
|
102
|
+
executables: []
|
103
|
+
extensions: []
|
104
|
+
extra_rdoc_files: []
|
105
|
+
files:
|
106
|
+
- app/models/seed_migration/data_migration.rb
|
107
|
+
- db/migrate/20140310150145_create_data_migrations.rb
|
108
|
+
- lib/extra_tasks.rb
|
109
|
+
- lib/generators/seed_migration/seed_migration_generator.rb
|
110
|
+
- lib/seed_migration/engine.rb
|
111
|
+
- lib/seed_migration/migration.rb
|
112
|
+
- lib/seed_migration/migrator.rb
|
113
|
+
- lib/seed_migration/register_entry.rb
|
114
|
+
- lib/seed_migration/version.rb
|
115
|
+
- lib/seed_migration.rb
|
116
|
+
- lib/tasks/seed_migration_tasks.rake
|
117
|
+
- LICENSE.txt
|
118
|
+
- Rakefile
|
119
|
+
- README.md
|
120
|
+
homepage: http://github.com/harrystech/seed_migration
|
121
|
+
licenses:
|
122
|
+
- MIT
|
123
|
+
metadata: {}
|
124
|
+
post_install_message:
|
125
|
+
rdoc_options: []
|
126
|
+
require_paths:
|
127
|
+
- lib
|
128
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - '>='
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '0'
|
133
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - '>='
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: '0'
|
138
|
+
requirements: []
|
139
|
+
rubyforge_project:
|
140
|
+
rubygems_version: 2.0.14
|
141
|
+
signing_key:
|
142
|
+
specification_version: 4
|
143
|
+
summary: Rails Data Migration
|
144
|
+
test_files: []
|