git_friendly_dumper 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ class GitFriendlyDumper
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,51 @@
1
+ # All of these tasks can be modified with these environment vars:
2
+ #
3
+ # DUMP_PATH=some/path where the dump is (default db/dump)
4
+ # TABLES=comma,sep,list tables to dump/load (default all)
5
+ # FORCE=true|1 answer 'yes' (default false)
6
+ # PROGRESS=false|0 show progress (default true)
7
+ # CLOBBER=false|0 clobber fixtures on dump (default true)
8
+ # RAISE_ERROR=false|0 silence runtime errors (default true)
9
+ # FIXTURES=comma,sep,list specific fixture files to load, invalid argument for dump tasks, should be relative filenames e.g. users/0000/0001.yml
10
+ # FIXTURES_FILE=filename of newline separated list of fixtures to load (use instead of FIXTURES option)
11
+
12
+ require 'git_friendly_dumper'
13
+
14
+ namespace :db do
15
+ desc "dump structure and data to db/dump (DUMP_PATH)"
16
+ task :dump => :environment do
17
+ GitFriendlyDumper.dump gfd_options.merge(:include_schema => true)
18
+ end
19
+
20
+ desc "replace database with data and stucture in db/dump (DUMP_PATH)"
21
+ task :load => :environment do
22
+ GitFriendlyDumper.load gfd_options.merge(:include_schema => true)
23
+ end
24
+
25
+ namespace :data do
26
+ desc "dump table data to db/dump (DUMP_PATH)"
27
+ task :dump => :environment do
28
+ GitFriendlyDumper.dump gfd_options.merge(:include_schema => false)
29
+ end
30
+
31
+ desc "load table data from db/dump (DUMP_PATH)"
32
+ task :load => :environment do
33
+ GitFriendlyDumper.load gfd_options.merge(:include_schema => false)
34
+ end
35
+ end
36
+
37
+ def gfd_options
38
+ {
39
+ :tables => ENV['TABLES'].present? && ENV['TABLES'].split(',').map(&:squish),
40
+ :path => ENV['DUMP_PATH'] || 'db/dump',
41
+ :force => ['1', 'true'].include?(ENV['FORCE']) ? true : false,
42
+ :include_schema => ['1', 'true'].include?(ENV['SCHEMA']) ? true : false,
43
+ :show_progress => ['0', 'false'].include?(ENV['PROGRESS']) ? false : true,
44
+ :clobber_fixtures => ['1', 'true'].include?(ENV['CLOBBER']) ? true : false,
45
+ :limit => ENV['LIMIT'] || 2500,
46
+ :raise_error => ['0', 'false'].include?(ENV['RAISE_ERROR']) ? false : true,
47
+ :fixtures => ENV['FIXTURES'] && ENV['FIXTURES'].split(','),
48
+ :fixtures_file => ENV['FIXTURES_FILE']
49
+ }
50
+ end
51
+ end
@@ -0,0 +1,319 @@
1
+ require 'spec_helper'
2
+
3
+ module GitFriendlyDumperSpec
4
+ include FileUtils
5
+
6
+ # sample app
7
+ class First < ActiveRecord::Base
8
+ end
9
+
10
+ class Second < ActiveRecord::Base
11
+ end
12
+
13
+ # spec helper methods
14
+ def reset_db
15
+ ActiveRecord::Base.connection.tables.each do |table|
16
+ ActiveRecord::Base.connection.drop_table table
17
+ end
18
+ end
19
+
20
+ def migrate_up(version)
21
+ ActiveRecord::Migration.suppress_messages do
22
+ ActiveRecord::Migrator.migrate ['spec/resources/migrate'], version
23
+ end
24
+ end
25
+
26
+ def remove_dump(path = @path)
27
+ rm_rf @path
28
+ end
29
+
30
+ def dump_files_set(path = @path)
31
+ Dir["#{path}/**/*"].map{|f| f.sub("#{path}/", '')}.to_set
32
+ end
33
+
34
+ def next_string
35
+ @next ||= 0
36
+ @next += 1
37
+ ['Foo', 'Bar', 'Baz'][rand(3)] + ("%04d" % @next)
38
+ end
39
+
40
+ def connection
41
+ ActiveRecord::Base.connection
42
+ end
43
+
44
+ describe 'GitFriendlyDumper' do
45
+ include GitFriendlyDumperSpec
46
+
47
+ before do
48
+ reset_db
49
+ @path = File.join(File.dirname(__FILE__), '../../tmp/dump')
50
+ remove_dump
51
+ end
52
+
53
+ describe "when progressbar not installed" do
54
+ before do
55
+ if defined?(ProgressBar)
56
+ @progress_bar_class = ProgressBar
57
+ Object.send :remove_const, 'ProgressBar'
58
+ end
59
+ end
60
+
61
+ after do
62
+ if @progress_bar_class
63
+ ProgressBar = @progress_bar_class
64
+ end
65
+ end
66
+
67
+ it ":show_progress => true should raise error" do
68
+ lambda { GitFriendlyDumper.new :show_progress => true }.should raise_error(RuntimeError)
69
+ end
70
+ end
71
+
72
+ describe "when db data exists" do
73
+ before do
74
+ migrate_up(20070101010000)
75
+ First.create!(:name => next_string)
76
+ First.create!(:name => next_string)
77
+ Second.create!(:name => next_string)
78
+ Second.create!(:name => next_string)
79
+ end
80
+
81
+ it "connection should have tables == ['firsts', 'seconds', 'schema_migrations']" do
82
+ ActiveRecord::Base.connection.tables.to_set.should == ['firsts', 'seconds', 'schema_migrations'].to_set
83
+ end
84
+
85
+ shared_examples_for "when dump files do not exist" do
86
+ it "should not require confirmation on dump" do
87
+ $stdin.should_not_receive(:gets)
88
+ @dumper.dump
89
+ end
90
+ end
91
+
92
+ shared_examples_for "when dump files exist" do
93
+ it "should require confirmation, and not proceed if not 'yes'" do
94
+ $stdin.should_receive(:gets).and_return("\n")
95
+ @dumper.should_not_receive(:dump_table)
96
+ @dumper.dump
97
+ end
98
+
99
+ it "should require confirmation, and proceed if 'yes'" do
100
+ $stdin.should_receive(:gets).and_return("yes\n")
101
+ @dumper.should_receive(:dump_table).at_least(1)
102
+ @dumper.dump
103
+ end
104
+
105
+ describe ", but :force => true" do
106
+ before do
107
+ @dumper.force = true
108
+ end
109
+
110
+ it "should not ask for confirmation" do
111
+ $stdin.should_not_receive(:gets)
112
+ @dumper.dump
113
+ end
114
+ end
115
+ end
116
+
117
+ describe "dump :include_schema => false" do
118
+ before do
119
+ @dumper = GitFriendlyDumper.new :include_schema => false, :path => @path
120
+ end
121
+
122
+ it_should_behave_like "when dump files do not exist"
123
+
124
+ describe "when dump files exist" do
125
+ before { mkdir_p "#{@path}/firsts" }
126
+ it_should_behave_like "when dump files exist"
127
+ end
128
+
129
+ describe "(after dump)" do
130
+ before do
131
+ @dumper.dump
132
+ end
133
+
134
+ it "should create only dump/firsts and dump/seconds with record fixtures" do
135
+ dump_files_set.should == [
136
+ 'firsts', 'firsts/0000', 'firsts/0000/0001.yml', 'firsts/0000/0002.yml',
137
+ 'seconds', 'seconds/0000', 'seconds/0000/0001.yml', 'seconds/0000/0002.yml'
138
+ ].to_set
139
+ end
140
+
141
+ it "should create fixtures for firsts" do
142
+ File.read("#{@path}/firsts/0000/0001.yml").should == connection.select_one("SELECT * FROM firsts WHERE id=1").to_yaml
143
+ File.read("#{@path}/firsts/0000/0002.yml").should == connection.select_one("SELECT * FROM firsts WHERE id=2").to_yaml
144
+ end
145
+
146
+ it "should create fixtures for seconds" do
147
+ File.read("#{@path}/seconds/0000/0001.yml").should == connection.select_one("SELECT * FROM seconds WHERE id=1").to_yaml
148
+ File.read("#{@path}/seconds/0000/0002.yml").should == connection.select_one("SELECT * FROM seconds WHERE id=2").to_yaml
149
+ end
150
+ end
151
+ end
152
+
153
+ describe "dump :include_schema => true" do
154
+ before do
155
+ @dumper = GitFriendlyDumper.new :include_schema => true, :path => @path
156
+ end
157
+
158
+ it_should_behave_like "when dump files do not exist"
159
+
160
+ describe "when dump files exist" do
161
+ before { mkdir_p "#{@path}/firsts" }
162
+ it_should_behave_like "when dump files exist"
163
+ end
164
+
165
+ describe "(after dump)" do
166
+ before do
167
+ @dumper.dump
168
+ end
169
+
170
+ it "should create dump/firsts, dump/seconds dump/schema_migrations, with record fixtures, and table schemas" do
171
+ dump_files_set.should == [
172
+ 'firsts', 'firsts/0000', 'firsts/0000/0001.yml', 'firsts/0000/0002.yml', 'firsts/schema.rb',
173
+ 'seconds', 'seconds/0000', 'seconds/0000/0001.yml', 'seconds/0000/0002.yml', 'seconds/schema.rb',
174
+ 'schema_migrations', 'schema_migrations/0000', 'schema_migrations/0000/0001.yml', 'schema_migrations/0000/0002.yml', 'schema_migrations/schema.rb'
175
+ ].to_set
176
+ end
177
+
178
+ it "should create fixtures for firsts" do
179
+ File.read("#{@path}/firsts/0000/0001.yml").should == connection.select_one("SELECT * FROM firsts WHERE id=1").to_yaml
180
+ File.read("#{@path}/firsts/0000/0002.yml").should == connection.select_one("SELECT * FROM firsts WHERE id=2").to_yaml
181
+ end
182
+
183
+ it "should create fixtures for seconds" do
184
+ File.read("#{@path}/seconds/0000/0001.yml").should == connection.select_one("SELECT * FROM seconds WHERE id=1").to_yaml
185
+ File.read("#{@path}/seconds/0000/0002.yml").should == connection.select_one("SELECT * FROM seconds WHERE id=2").to_yaml
186
+ end
187
+
188
+ it "should create fixtures for schema_migrations" do
189
+ YAML.load(File.read("#{@path}/schema_migrations/0000/0001.yml")).should == {"version" => "20070101000000"}
190
+ YAML.load(File.read("#{@path}/schema_migrations/0000/0002.yml")).should == {"version" => "20070101010000"}
191
+ end
192
+
193
+ it "should contain create schema for firsts" do
194
+ File.read("#{@path}/firsts/schema.rb").should =~ /create_table "firsts".*string "name"/m
195
+ end
196
+
197
+ it "should contain create schema for seconds" do
198
+ File.read("#{@path}/seconds/schema.rb").should =~ /create_table "seconds".*string "name"/m
199
+ end
200
+
201
+ it "should contain create schema for schema_migrations" do
202
+ File.read("#{@path}/schema_migrations/schema.rb").should =~ /create_table "schema_migrations".*:id => false.*string "version"/m
203
+ end
204
+ end
205
+ end
206
+
207
+
208
+ describe "dumping when RAISE_ERROR=false" do
209
+ let(:dumper) {GitFriendlyDumper.new(:include_schema => true, :raise_error => false, :path => @path)}
210
+ subject{ dumper }
211
+
212
+ describe "when #dump_records raises a runtime error" do
213
+ before(:each) do
214
+ dumper.should_receive(:dump_records).and_raise(RuntimeError)
215
+ end
216
+
217
+ it "#dump should raise a runtime error" do
218
+ lambda { dumper.dump }.should raise_error(RuntimeError)
219
+ end
220
+ end
221
+
222
+ describe "when #dump_records raises an ActiveRecord::Error" do
223
+ before(:each) do
224
+ dumper.should_receive(:dump_records).at_least(1).times.and_raise(ActiveRecord::ActiveRecordError)
225
+ end
226
+
227
+ it "#dump should not raise a runtime error" do
228
+ lambda { dumper.dump }.should_not raise_error
229
+ end
230
+ end
231
+ end
232
+ end
233
+
234
+ describe "when fixtures exist" do
235
+ before do
236
+ migrate_up(20070101010000)
237
+ First.create!(:name => next_string)
238
+ First.create!(:name => next_string)
239
+ Second.create!(:name => next_string)
240
+ Second.create!(:name => next_string)
241
+ GitFriendlyDumper.dump :include_schema => true, :force => true, :path => @path
242
+ reset_db
243
+ end
244
+
245
+ shared_examples_for "when db data does not exist" do
246
+ it "should not require confirmation on load" do
247
+ $stdin.should_not_receive(:gets)
248
+ @dumper.load
249
+ end
250
+ end
251
+
252
+ shared_examples_for "when db data exists" do
253
+ it "should require confirmation, and not proceed if not 'yes'" do
254
+ $stdin.should_receive(:gets).and_return("\n")
255
+ @dumper.should_not_receive(:load_table)
256
+ @dumper.load
257
+ end
258
+
259
+ it "should require confirmation, and proceed if 'yes'" do
260
+ $stdin.should_receive(:gets).and_return("yes\n")
261
+ @dumper.should_receive(:load_table).at_least(1)
262
+ @dumper.load
263
+ end
264
+
265
+ describe ", but :force => true" do
266
+ before do
267
+ @dumper.force = true
268
+ end
269
+
270
+ it "should not ask for confirmation" do
271
+ $stdin.should_not_receive(:gets)
272
+ @dumper.load
273
+ end
274
+ end
275
+ end
276
+
277
+ describe "load :include_schema => true" do
278
+ before do
279
+ @dumper = GitFriendlyDumper.new :include_schema => true, :path => @path
280
+ end
281
+
282
+ it_should_behave_like "when db data does not exist"
283
+
284
+ describe "when db data exists" do
285
+ before do
286
+ migrate_up(20070101010000)
287
+ end
288
+
289
+ it_should_behave_like "when db data exists"
290
+ end
291
+ end
292
+
293
+ describe "loading when RAISE_ERROR=false" do
294
+ let(:dumper) {GitFriendlyDumper.new(:include_schema => true, :raise_error => false, :path => @path)}
295
+ subject{ dumper }
296
+
297
+ describe "when connection raises a runtime error" do
298
+ before(:each) do
299
+ dumper.connection.should_receive(:insert_fixture).and_raise(RuntimeError)
300
+ end
301
+
302
+ it "#load should raise a runtime error" do
303
+ lambda { dumper.load }.should raise_error(RuntimeError)
304
+ end
305
+ end
306
+
307
+ describe "when connection raises an ActiveRecord::Error" do
308
+ before(:each) do
309
+ dumper.connection.should_receive(:insert_fixture).at_least(1).times.and_raise(ActiveRecord::ActiveRecordError)
310
+ end
311
+
312
+ it "#load should not raise a runtime error" do
313
+ lambda { dumper.load }.should_not raise_error
314
+ end
315
+ end
316
+ end
317
+ end
318
+ end
319
+ end
@@ -0,0 +1,11 @@
1
+ class CreateFirsts < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :firsts do |t|
4
+ t.string :name
5
+ end
6
+ end
7
+
8
+ def self.down
9
+ drop_table :firsts
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ class CreateSeconds < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :seconds do |t|
4
+ t.string :name
5
+ end
6
+ end
7
+
8
+ def self.down
9
+ drop_table :seconds
10
+ end
11
+ end
@@ -0,0 +1,8 @@
1
+ require 'rubygems'
2
+ require 'rspec'
3
+
4
+ # Requires supporting files with custom matchers and macros, etc,
5
+ # in ./support/ and its subdirectories.
6
+ Dir[File.expand_path(File.join(File.dirname(__FILE__),'support','**','*.rb'))].each {|f| require f}
7
+
8
+ require 'git_friendly_dumper'
@@ -0,0 +1,6 @@
1
+ require 'active_record'
2
+
3
+ ActiveRecord::Base.establish_connection(
4
+ :adapter => "sqlite3",
5
+ :database => "tmp/db/test.sqlite3"
6
+ )
@@ -0,0 +1,7 @@
1
+ require 'logger'
2
+ require 'active_record'
3
+
4
+ log_filename = File.join(File.dirname(__FILE__), '..', '..', 'tmp', 'test.log')
5
+ `mkdir -p #{File.dirname(log_filename)}`
6
+ log_file = File.open(log_filename, 'w')
7
+ ActiveRecord::Base.logger = Logger.new(log_file)
metadata ADDED
@@ -0,0 +1,196 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: git_friendly_dumper
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Ian White
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-03-05 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activerecord
16
+ requirement: &70093535094440 !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: *70093535094440
25
+ - !ruby/object:Gem::Dependency
26
+ name: mysql2
27
+ requirement: &70093535108500 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70093535108500
36
+ - !ruby/object:Gem::Dependency
37
+ name: sqlite3
38
+ requirement: &70093535105680 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70093535105680
47
+ - !ruby/object:Gem::Dependency
48
+ name: rake
49
+ requirement: &70093535104660 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70093535104660
58
+ - !ruby/object:Gem::Dependency
59
+ name: rspec
60
+ requirement: &70093535103600 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *70093535103600
69
+ - !ruby/object:Gem::Dependency
70
+ name: cucumber
71
+ requirement: &70093535102400 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *70093535102400
80
+ - !ruby/object:Gem::Dependency
81
+ name: aruba
82
+ requirement: &70093535117660 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: *70093535117660
91
+ - !ruby/object:Gem::Dependency
92
+ name: progressbar
93
+ requirement: &70093535116980 !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ type: :development
100
+ prerelease: false
101
+ version_requirements: *70093535116980
102
+ description: Use fixtures to create a db independent and git friendly db dump. It's
103
+ git friendly because each record is in its own file (git doesn't do very well with
104
+ large files that are committed all at once).
105
+ email:
106
+ - ian.w.white@gmail.com
107
+ executables: []
108
+ extensions: []
109
+ extra_rdoc_files: []
110
+ files:
111
+ - lib/git_friendly_dumper/version.rb
112
+ - lib/git_friendly_dumper.rb
113
+ - lib/tasks/git_friendly_dumper_tasks.rake
114
+ - MIT-LICENSE
115
+ - Rakefile
116
+ - History.txt
117
+ - README.rdoc
118
+ - spec/git_friendly_dumper_spec.rb
119
+ - spec/resources/migrate/20070101000000_create_firsts.rb
120
+ - spec/resources/migrate/20070101010000_create_seconds.rb
121
+ - spec/spec_helper.rb
122
+ - spec/support/connect.rb
123
+ - spec/support/logger.rb
124
+ - features/dump/change_dump_path.feature
125
+ - features/dump/data_dump.feature
126
+ - features/dump/default_dump.feature
127
+ - features/dump/dump_and_raise_error.feature
128
+ - features/dump/dump_deleted_records_and_clobber.feature
129
+ - features/dump/dump_specific_tables.feature
130
+ - features/load/clobber_load.feature
131
+ - features/load/db_dump_path_load.feature
132
+ - features/load/default_load.feature
133
+ - features/load/load_and_raise_error.feature
134
+ - features/load/load_fixtures.feature
135
+ - features/load/load_git_changes.feature
136
+ - features/load/load_specific_tables.feature
137
+ - features/step_definitions/app_steps.rb
138
+ - features/step_definitions/database_steps.rb
139
+ - features/support/announce.rb
140
+ - features/support/env.rb
141
+ - features/support/logger.rb
142
+ homepage: http://github.com/ianwhite/git_friendly_dumper
143
+ licenses: []
144
+ post_install_message:
145
+ rdoc_options: []
146
+ require_paths:
147
+ - lib
148
+ required_ruby_version: !ruby/object:Gem::Requirement
149
+ none: false
150
+ requirements:
151
+ - - ! '>='
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
154
+ segments:
155
+ - 0
156
+ hash: 402944153813948199
157
+ required_rubygems_version: !ruby/object:Gem::Requirement
158
+ none: false
159
+ requirements:
160
+ - - ! '>='
161
+ - !ruby/object:Gem::Version
162
+ version: '0'
163
+ segments:
164
+ - 0
165
+ hash: 402944153813948199
166
+ requirements: []
167
+ rubyforge_project:
168
+ rubygems_version: 1.8.10
169
+ signing_key:
170
+ specification_version: 3
171
+ summary: Use fixtures to create a db independent and git friendly db dump.
172
+ test_files:
173
+ - spec/git_friendly_dumper_spec.rb
174
+ - spec/resources/migrate/20070101000000_create_firsts.rb
175
+ - spec/resources/migrate/20070101010000_create_seconds.rb
176
+ - spec/spec_helper.rb
177
+ - spec/support/connect.rb
178
+ - spec/support/logger.rb
179
+ - features/dump/change_dump_path.feature
180
+ - features/dump/data_dump.feature
181
+ - features/dump/default_dump.feature
182
+ - features/dump/dump_and_raise_error.feature
183
+ - features/dump/dump_deleted_records_and_clobber.feature
184
+ - features/dump/dump_specific_tables.feature
185
+ - features/load/clobber_load.feature
186
+ - features/load/db_dump_path_load.feature
187
+ - features/load/default_load.feature
188
+ - features/load/load_and_raise_error.feature
189
+ - features/load/load_fixtures.feature
190
+ - features/load/load_git_changes.feature
191
+ - features/load/load_specific_tables.feature
192
+ - features/step_definitions/app_steps.rb
193
+ - features/step_definitions/database_steps.rb
194
+ - features/support/announce.rb
195
+ - features/support/env.rb
196
+ - features/support/logger.rb