migrer 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.
data/.gitignore ADDED
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .idea/
6
+ .yardoc
7
+ .rvmrc
8
+ Gemfile.lock
9
+ InstalledFiles
10
+ _yardoc
11
+ coverage
12
+ doc/
13
+ lib/bundler/man
14
+ pkg
15
+ rdoc
16
+ spec/reports
17
+ test_app
18
+ test/tmp
19
+ test/version_tmp
20
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in migrer.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Sathya Sekaran
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,103 @@
1
+ # Migrer
2
+ #### The polite data migration valet.
3
+
4
+ ### What's with the name?
5
+
6
+ Migrer (me-gray) is French for migrate. My wife suggested the name, and it was much
7
+ less obnoxious than `morphin_time` or `flying_v`, say. - @sfsekaran
8
+
9
+ ## What is it?
10
+
11
+ Migrer creates migration-like tasks for running application scripts. It is primarily useful for updating database
12
+ records or running one-time tasks against separate environments.
13
+
14
+ **What is the difference between this and ActiveRecord migrations?**
15
+
16
+ Migrations should always be stable and are primarily for altering the structure of a database. Migrer is intended for
17
+ data migrations, or manipulating the data within that structure. Such tasks can become error-prone since they depend on
18
+ the state of models in the codebase, and are best not included in ActiveRecord migrations.
19
+
20
+ **Why not just create a regular rake task or use a script runner?**
21
+
22
+ Although Migrer data migrations can be run multiple times, they are primarily suited for one-time tasks (and often for
23
+ tasks that are not intended to be run more than once). Migrer not only creates a structure for these one-time tasks,
24
+ but also keeps track of which data migrations have already been processed. This is especially useful when managing
25
+ such tasks among multiple environments.
26
+
27
+ ## Installation
28
+
29
+ Add this line to your application's Gemfile:
30
+
31
+ gem 'migrer'
32
+
33
+ And then execute:
34
+
35
+ $ bundle
36
+
37
+ Or install it yourself as:
38
+
39
+ $ gem install migrer
40
+
41
+ And install database migrations like so:
42
+
43
+ $ bundle exec rake railties:install:migrations FROM=migrer
44
+ $ bundle exec rake db:migrate
45
+
46
+ ## Usage
47
+
48
+ # 1) Create the data migration
49
+
50
+ Create a data migration:
51
+
52
+ $ bundle exec rails generate MyFirstDataMigration "optional description"
53
+
54
+ This will create the file: lib/tasks/data_migrations/<timestamp>_my_first_data_migration.rb
55
+
56
+ Open this file and replace "TODO" with your data migration code!
57
+
58
+ # 2) Run a task
59
+
60
+ Unless you have the RAILS_ENV environment variable already set, prepend this to all of the following commands (replace
61
+ <environment> with the correct Rails environment (development, staging, production, etc.):
62
+
63
+ RAILS_ENV=<environment>
64
+
65
+ All the following commands will ask for confirmation before executing.
66
+
67
+ **Run all unprocessed data migrations:**
68
+
69
+ bundle exec rake data:migrate
70
+
71
+ **Run a single data migration (&lt;version&gt; is the timestamp at the beginning of the data migration file, just like
72
+ ActiveRecord migrations):**
73
+
74
+ bundle exec rake data:migration VERSION=<version>
75
+
76
+ **Mark all data migrations as already processed:**
77
+
78
+ bundle exec rake data:mark_all
79
+
80
+ **Mark a single data migration as already processed:**
81
+
82
+ bundle exec rake data:mark VERSION=<version>
83
+
84
+ **Mark all data migrations as unprocessed (so they are included again when running data:migrate):**
85
+
86
+ bundle exec rake data:unmark_all
87
+
88
+ **Mark a single data migration as unprocessed:**
89
+
90
+ bundle exec rake data:unmark VERSION=<version>
91
+
92
+ ## Contributing
93
+
94
+ 1. Fork it
95
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
96
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
97
+ 4. Push to the branch (`git push origin my-new-feature`)
98
+ 5. Create new Pull Request
99
+
100
+ ## Contributors
101
+
102
+ * *Sathya Sekaran* ([sfsekaran](https://github.com/sfsekaran))
103
+ * *Michael Durnhofer* ([mdurn](https://github.com/mdurn))
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,8 @@
1
+ class CreateMigrerTable < ActiveRecord::Migration
2
+ def change
3
+ create_table :data_migration_versions do |t|
4
+ t.string :version
5
+ t.timestamps
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,26 @@
1
+ class DataMigration
2
+ def self.all
3
+ filenames = Dir.entries("#{Rails.root}/lib/tasks/data_migrations").select { |f| /^\d+.*\.rb$/ === f }
4
+ data_migrations = {}
5
+
6
+ filenames.each do |f|
7
+ match_data = /^(?<version>\d+)_(?<name>.+)\.rb$/.match(f)
8
+
9
+ record = ActiveRecord::Base.connection.execute(
10
+ "SELECT * FROM data_migration_versions WHERE version = #{match_data[:version]}").first
11
+
12
+ data_migrations.merge!(
13
+ match_data[:version] => {
14
+ basefilename: "#{match_data[:version]}_#{match_data[:name]}",
15
+ class_name: match_data[:name].classify,
16
+ filename: "#{match_data[:version]}_#{match_data[:name]}.rb",
17
+ name: match_data[:name],
18
+ processed: (record != nil),
19
+ created_at: record.try(:[], :created_at),
20
+ updated_at: record.try(:[], :updated_at)
21
+ })
22
+ end
23
+
24
+ data_migrations
25
+ end
26
+ end
@@ -0,0 +1,11 @@
1
+ Description:
2
+ Data migration generator
3
+
4
+ Optional Arguments:
5
+ DESCRIPTION # a commented description in the created data migration file
6
+
7
+ Example:
8
+ rails generate data_migration DataMigrationName "Optional description"
9
+
10
+ This will create:
11
+ lib/tasks/data_migrations/<timestamp>_data_migration_name.rb
@@ -0,0 +1,16 @@
1
+ class DataMigrationGenerator < Rails::Generators::NamedBase
2
+ require "rails/generators/active_record"
3
+
4
+ source_root File.expand_path('../templates', __FILE__)
5
+ argument :description, type: :string, default: nil, required: false
6
+
7
+ def generate_data_migration
8
+ template "data_migration.rb",
9
+ "lib/tasks/data_migrations/#{file_name}"
10
+ end
11
+
12
+ private
13
+ def file_name
14
+ "#{ActiveRecord::Generators::Base.next_migration_number('lib/tasks/data_migrations')}_#{name.underscore}.rb"
15
+ end
16
+ end
@@ -0,0 +1,8 @@
1
+ class <%= name %> < DataMigration
2
+
3
+ <%= "# #{description}" %>
4
+
5
+ def self.run
6
+ #TODO: data_migration code
7
+ end
8
+ end
@@ -0,0 +1,7 @@
1
+ module Migrer
2
+
3
+ class Engine < ::Rails::Engine
4
+ isolate_namespace Migrer
5
+ end
6
+
7
+ end
@@ -0,0 +1,3 @@
1
+ module Migrer
2
+ VERSION = "0.0.1"
3
+ end
data/lib/migrer.rb ADDED
@@ -0,0 +1,7 @@
1
+ require "migrer/version"
2
+
3
+ module Migrer
4
+ end
5
+
6
+ # Require our engine
7
+ require "migrer/engine"
@@ -0,0 +1,155 @@
1
+ require 'data_migration'
2
+
3
+ namespace :data do
4
+ desc "Data migration tasks"
5
+
6
+ task migrate: :environment do
7
+ data_migrations = DataMigration.all
8
+
9
+ if (version = ENV['VERSION'])
10
+ data_migration = data_migrations[version]
11
+
12
+ if data_migration.present?
13
+ if data_migration[:processed]
14
+ puts "Data migration already processed. Do you want to run it anyway? (responses other than 'yes' will exit)"
15
+ else
16
+ puts "Starting data migration #{data_migration[:class_name]}. Do you wish to continue? (responses other than 'yes' will exit)"
17
+ end
18
+
19
+ prompt = $stdin.gets.chomp
20
+
21
+ if prompt == "yes"
22
+ puts "#{data_migration[:class_name]}: migrating"
23
+ t_start = Time.now
24
+
25
+ require "#{Rails.root}/lib/tasks/data_migrations/#{data_migration[:basefilename]}"
26
+ eval(data_migration[:class_name]).run
27
+
28
+ t_end = Time.now
29
+
30
+ unless data_migration[:processed]
31
+ ActiveRecord::Base.connection.execute(
32
+ "INSERT INTO data_migration_versions
33
+ VALUES (NULL, #{version}, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)" )
34
+ end
35
+
36
+ puts "#{data_migration[:class_name]}: migrated (#{t_end - t_start}s)"
37
+ end
38
+ else
39
+ puts "No data migration found matching version: #{version}"
40
+ end
41
+ else
42
+ data_migrations.each do |k, v|
43
+ unless v[:processed]
44
+ puts "Starting data migration #{v[:class_name]}. Do you wish to continue? (responses other than 'yes' will exit)"
45
+ prompt = $stdin.gets.chomp
46
+ if prompt == "yes"
47
+ puts "#{v[:class_name]}: migrating"
48
+ t_start = Time.now
49
+
50
+ require "#{Rails.root}/lib/tasks/data_migrations/#{v[:basefilename]}"
51
+ eval(v[:class_name]).run
52
+
53
+ t_end = Time.now
54
+
55
+ ActiveRecord::Base.connection.execute(
56
+ "INSERT INTO data_migration_versions
57
+ VALUES (NULL, #{k}, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)" )
58
+
59
+ puts "#{v[:class_name]}: migrated (#{t_end - t_start}s)"
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ task mark: :environment do
67
+ data_migrations = DataMigration.all
68
+
69
+ if (version = ENV['VERSION'])
70
+ data_migration = data_migrations[version]
71
+
72
+ if data_migration.present?
73
+ if data_migration[:processed]
74
+ puts "Data migration already processed."
75
+ else
76
+ puts "Data migration #{data_migration[:class_name]} will be marked as processed. Continue? (responses other than 'yes' will exit)"
77
+
78
+ prompt = $stdin.gets.chomp
79
+
80
+ if prompt == "yes"
81
+ ActiveRecord::Base.connection.execute(
82
+ "INSERT INTO data_migration_versions
83
+ VALUES (NULL, #{version}, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)" )
84
+
85
+ puts "#{data_migration[:class_name]}: marked as migrated"
86
+ end
87
+ end
88
+ else
89
+ puts "No data migration found matching version: #{version}"
90
+ end
91
+ else
92
+ puts "VERSION must be supplied."
93
+ end
94
+ end
95
+
96
+ task mark_all: :environment do
97
+ unprocessed_data_migrations = DataMigration.all.select { |k, v| !v[:processed] }
98
+
99
+ puts "This will mark all data migrations as already processed. Continue? (responses other than 'yes' will exit)"
100
+
101
+ prompt = $stdin.gets.chomp
102
+ if prompt == "yes"
103
+ unprocessed_data_migrations.each do |k, v|
104
+ ActiveRecord::Base.connection.execute(
105
+ "INSERT INTO data_migration_versions
106
+ VALUES (NULL, #{k}, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)" )
107
+
108
+ puts "#{v[:class_name]}: marked as migrated"
109
+ end
110
+ end
111
+ end
112
+
113
+ task unmark: :environment do
114
+ data_migrations = DataMigration.all
115
+
116
+ if (version = ENV['VERSION'])
117
+ data_migration = data_migrations[version]
118
+
119
+ if data_migration.present?
120
+ if !data_migration[:processed]
121
+ puts "Data migration not yet processed."
122
+ else
123
+ puts "Data migration #{data_migration[:class_name]} will be unmarked as processed. Continue? (responses other than 'yes' will exit)"
124
+
125
+ prompt = $stdin.gets.chomp
126
+
127
+ if prompt == "yes"
128
+ ActiveRecord::Base.connection.execute(
129
+ "DELETE FROM data_migration_versions
130
+ WHERE version = #{version}" )
131
+
132
+ puts "#{data_migration[:class_name]}: unmarked as migrated"
133
+ end
134
+ end
135
+ else
136
+ puts "No data migration found matching version: #{version}"
137
+ end
138
+ else
139
+ puts "VERSION must be supplied."
140
+ end
141
+ end
142
+
143
+ task unmark_all: :environment do
144
+ puts "All data migrations will be unmarked as processed. Continue? (responses other than 'yes' will exit)"
145
+
146
+ prompt = $stdin.gets.chomp
147
+
148
+ if prompt == "yes"
149
+ ActiveRecord::Base.connection.execute(
150
+ "DELETE FROM data_migration_versions" )
151
+
152
+ puts "Data migration records cleared"
153
+ end
154
+ end
155
+ end
data/migrer.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'migrer/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "migrer"
8
+ gem.version = Migrer::VERSION
9
+ gem.authors = ["Sathya Sekaran", "Michael Durnhofer"]
10
+ gem.email = ["sfsekaran@gmail.com"]
11
+ gem.description = %q{The polite data migration valet.}
12
+ gem.summary = %q{The 'migrer' gem helps generate, execute, and keep track of data migrations.}
13
+ gem.homepage = "http://github.com/sfsekaran/migrer"
14
+
15
+ gem.rubyforge_project = "migrer"
16
+
17
+ gem.files = `git ls-files`.split($/)
18
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
19
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
20
+ gem.require_paths = ["lib", "script", "db"]
21
+
22
+ gem.add_runtime_dependency "activerecord", "~> 3.2.2"
23
+ end
data/script/rails ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3
+
4
+ ENGINE_ROOT = File.expand_path('../..', __FILE__)
5
+ ENGINE_PATH = File.expand_path('../../lib/migrer/engine', __FILE__)
6
+
7
+ require 'rails/all'
8
+ require 'rails/engine/commands'
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: migrer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Sathya Sekaran
9
+ - Michael Durnhofer
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2013-01-12 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activerecord
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ~>
21
+ - !ruby/object:Gem::Version
22
+ version: 3.2.2
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ~>
29
+ - !ruby/object:Gem::Version
30
+ version: 3.2.2
31
+ description: The polite data migration valet.
32
+ email:
33
+ - sfsekaran@gmail.com
34
+ executables: []
35
+ extensions: []
36
+ extra_rdoc_files: []
37
+ files:
38
+ - .gitignore
39
+ - Gemfile
40
+ - LICENSE.txt
41
+ - README.md
42
+ - Rakefile
43
+ - db/migrate/20121229002105_create_migrer_table.rb
44
+ - lib/data_migration.rb
45
+ - lib/generators/data_migration/USAGE
46
+ - lib/generators/data_migration/data_migration_generator.rb
47
+ - lib/generators/data_migration/templates/data_migration.rb
48
+ - lib/migrer.rb
49
+ - lib/migrer/engine.rb
50
+ - lib/migrer/version.rb
51
+ - lib/tasks/migrer.rake
52
+ - migrer.gemspec
53
+ - script/rails
54
+ homepage: http://github.com/sfsekaran/migrer
55
+ licenses: []
56
+ post_install_message:
57
+ rdoc_options: []
58
+ require_paths:
59
+ - lib
60
+ - script
61
+ - db
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ! '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ! '>='
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubyforge_project: migrer
76
+ rubygems_version: 1.8.24
77
+ signing_key:
78
+ specification_version: 3
79
+ summary: The 'migrer' gem helps generate, execute, and keep track of data migrations.
80
+ test_files: []