xmigra 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/xmigra/db_support/mssql.rb +103 -2
- data/lib/xmigra/db_support/psql.rb +77 -1
- data/lib/xmigra/migration.rb +11 -0
- data/lib/xmigra/program.rb +32 -1
- data/lib/xmigra/reversion_script_building.rb +40 -0
- data/lib/xmigra/revert_file.rb +42 -0
- data/lib/xmigra/schema_updater.rb +3 -0
- data/lib/xmigra/vcs_support/git.rb +1 -1
- data/lib/xmigra/version.rb +1 -1
- data/test/reversions.rb +97 -0
- data/test/runner.rb +13 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5e70e491aa62e8fdf597baa7794b6c342ebb074d
|
4
|
+
data.tar.gz: 6d95f99d62ca23e9fb0f801dc37e0eaca2656cd0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ddf810521f87c7ecf49c5aef49d8f51ce913c9e7ae6b0bb3ba14395560d965c9ff538ebd80872b97c1870e986f09e7f523e58054caf1b2387b80a44be4558ad5
|
7
|
+
data.tar.gz: 54aea5341db82a73aa972f6ad6e27f11a9c24780d5f83bd146f6c4c25b9cc1376aa99081177ddb14310720b0cb68081c1a4fa2d1fd67b91fa1dc961bad43f670
|
@@ -12,6 +12,8 @@ module XMigra
|
|
12
12
|
$/ix
|
13
13
|
STATISTICS_FILE = 'statistics-objects.yaml'
|
14
14
|
|
15
|
+
ID_COLLATION = 'Latin1_General_CS_AS'
|
16
|
+
|
15
17
|
class StatisticsObject
|
16
18
|
def initialize(name, params)
|
17
19
|
(@name = name.dup).freeze
|
@@ -153,7 +155,7 @@ IF NOT EXISTS (
|
|
153
155
|
)
|
154
156
|
BEGIN
|
155
157
|
CREATE TABLE [xmigra].[applied] (
|
156
|
-
[MigrationID] nvarchar(80) NOT NULL,
|
158
|
+
[MigrationID] nvarchar(80) COLLATE #{ID_COLLATION} NOT NULL,
|
157
159
|
[ApplicationOrder] int IDENTITY(1,1) NOT NULL,
|
158
160
|
[VersionBridgeMark] bit NOT NULL,
|
159
161
|
[Description] nvarchar(max) NOT NULL,
|
@@ -171,6 +173,45 @@ BEGIN
|
|
171
173
|
END;
|
172
174
|
GO
|
173
175
|
|
176
|
+
IF NOT EXISTS (
|
177
|
+
SELECT * FROM sys.columns
|
178
|
+
WHERE object_id = OBJECT_ID(N'[xmigra].[applied]')
|
179
|
+
AND name = N'MigrationID'
|
180
|
+
AND collation_name = N'#{ID_COLLATION}'
|
181
|
+
)
|
182
|
+
BEGIN
|
183
|
+
ALTER TABLE xmigra.applied DROP CONSTRAINT PK_version;
|
184
|
+
ALTER TABLE xmigra.applied ALTER COLUMN [MigrationID] nvarchar(80) COLLATE Latin1_General_CS_AS NOT NULL;
|
185
|
+
ALTER TABLE xmigra.applied ADD CONSTRAINT PK_version PRIMARY KEY ([MigrationID] ASC) WITH (
|
186
|
+
PAD_INDEX = OFF,
|
187
|
+
STATISTICS_NORECOMPUTE = OFF,
|
188
|
+
IGNORE_DUP_KEY = OFF,
|
189
|
+
ALLOW_ROW_LOCKS = ON,
|
190
|
+
ALLOW_PAGE_LOCKS = ON
|
191
|
+
) ON [PRIMARY];
|
192
|
+
END;
|
193
|
+
|
194
|
+
IF NOT EXISTS (
|
195
|
+
SELECT * FROM sys.objects
|
196
|
+
WHERE object_id = OBJECT_ID(N'[xmigra].[previous_states]')
|
197
|
+
AND type IN (N'U')
|
198
|
+
)
|
199
|
+
BEGIN
|
200
|
+
CREATE TABLE [xmigra].[previous_states] (
|
201
|
+
[Changed] datetime NOT NULL,
|
202
|
+
[MigrationApplicationOrder] int NOT NULL,
|
203
|
+
[FromMigrationID] nvarchar(80) COLLATE #{ID_COLLATION},
|
204
|
+
[ToRangeStartMigrationID] nvarchar(80) COLLATE #{ID_COLLATION} NOT NULL,
|
205
|
+
[ToRangeEndMigrationID] nvarchar(80) COLLATE #{ID_COLLATION} NOT NULL,
|
206
|
+
|
207
|
+
CONSTRAINT [PK_previous_states] PRIMARY KEY CLUSTERED (
|
208
|
+
[Changed] ASC,
|
209
|
+
[MigrationApplicationOrder] ASC
|
210
|
+
)
|
211
|
+
);
|
212
|
+
END;
|
213
|
+
GO
|
214
|
+
|
174
215
|
IF NOT EXISTS (
|
175
216
|
SELECT * FROM sys.objects
|
176
217
|
WHERE object_id = OBJECT_ID(N'[xmigra].[DF_version_VersionBridgeMark]')
|
@@ -244,6 +285,30 @@ BEGIN
|
|
244
285
|
[CompletesMigration] nvarchar(80) NULL
|
245
286
|
) ON [PRIMARY];
|
246
287
|
END;
|
288
|
+
|
289
|
+
IF EXISTS (
|
290
|
+
SELECT * FROM sys.objects
|
291
|
+
WHERE object_id = OBJECT_ID(N'[xmigra].[last_applied_migrations]')
|
292
|
+
AND type IN (N'V')
|
293
|
+
)
|
294
|
+
BEGIN
|
295
|
+
DROP VIEW [xmigra].[last_applied_migrations];
|
296
|
+
END;
|
297
|
+
GO
|
298
|
+
|
299
|
+
CREATE VIEW [xmigra].[last_applied_migrations] AS
|
300
|
+
SELECT
|
301
|
+
ROW_NUMBER() OVER (ORDER BY a.[ApplicationOrder] DESC) AS [RevertOrder],
|
302
|
+
a.[Description]
|
303
|
+
FROM
|
304
|
+
[xmigra].[applied] a
|
305
|
+
WHERE
|
306
|
+
a.[ApplicationOrder] > COALESCE((
|
307
|
+
SELECT TOP (1) ps.[MigrationApplicationOrder]
|
308
|
+
FROM [xmigra].[previous_states] ps
|
309
|
+
JOIN [xmigra].[applied] a2 ON ps.[ToRangeStartMigrationID] = a2.[MigrationID]
|
310
|
+
ORDER BY ps.[Changed] DESC
|
311
|
+
), 0);
|
247
312
|
END_OF_SQL
|
248
313
|
end
|
249
314
|
|
@@ -260,7 +325,7 @@ END;
|
|
260
325
|
GO
|
261
326
|
|
262
327
|
CREATE TABLE [xmigra].[migrations] (
|
263
|
-
[MigrationID] nvarchar(80) NOT NULL,
|
328
|
+
[MigrationID] nvarchar(80) COLLATE #{ID_COLLATION} NOT NULL,
|
264
329
|
[ApplicationOrder] int NOT NULL,
|
265
330
|
[Description] ntext NOT NULL,
|
266
331
|
[Install] bit NOT NULL DEFAULT(0)
|
@@ -472,6 +537,38 @@ ELSE BEGIN
|
|
472
537
|
)
|
473
538
|
AND [ApplicationOrder] > @BridgePoint;
|
474
539
|
END;
|
540
|
+
|
541
|
+
INSERT INTO [xmigra].[previous_states] (
|
542
|
+
[Changed],
|
543
|
+
[MigrationApplicationOrder],
|
544
|
+
[FromMigrationID],
|
545
|
+
[ToRangeStartMigrationID],
|
546
|
+
[ToRangeEndMigrationID]
|
547
|
+
)
|
548
|
+
SELECT TOP (1)
|
549
|
+
CURRENT_TIMESTAMP,
|
550
|
+
-- Application order of last installed migration --
|
551
|
+
COALESCE(
|
552
|
+
(
|
553
|
+
SELECT TOP(1) [ApplicationOrder] FROM [xmigra].[applied]
|
554
|
+
ORDER BY [ApplicationOrder] DESC
|
555
|
+
),
|
556
|
+
0
|
557
|
+
),
|
558
|
+
( -- Last installed migration --
|
559
|
+
SELECT TOP (1) [MigrationID]
|
560
|
+
FROM [xmigra].[applied]
|
561
|
+
ORDER BY [ApplicationOrder] DESC
|
562
|
+
),
|
563
|
+
m.[MigrationID],
|
564
|
+
( -- Last migration to install --
|
565
|
+
SELECT TOP(1) [MigrationID] FROM [xmigra].[migrations]
|
566
|
+
WHERE [Install] <> 0
|
567
|
+
ORDER BY [ApplicationOrder] DESC
|
568
|
+
)
|
569
|
+
FROM [xmigra].[migrations] m
|
570
|
+
WHERE m.[Install] <> 0
|
571
|
+
ORDER BY m.[ApplicationOrder] ASC;
|
475
572
|
END_OF_SQL
|
476
573
|
end
|
477
574
|
|
@@ -885,6 +982,10 @@ END;
|
|
885
982
|
end.join("\n"))
|
886
983
|
end
|
887
984
|
|
985
|
+
def reversion_tracking_sql
|
986
|
+
"DELETE FROM [xmigra].[applied] WHERE [MigrationID] = '#{id}';\n"
|
987
|
+
end
|
988
|
+
|
888
989
|
def each_batch(sql)
|
889
990
|
current_batch_lines = []
|
890
991
|
sql.each_line do |line|
|
@@ -111,6 +111,24 @@ module XMigra
|
|
111
111
|
);
|
112
112
|
END IF;
|
113
113
|
|
114
|
+
IF NOT EXISTS(
|
115
|
+
SELECT * FROM information_schema.tables
|
116
|
+
WHERE table_schema = 'xmigra' AND table_name = 'previous_states'
|
117
|
+
) THEN
|
118
|
+
CREATE TABLE xmigra.previous_states (
|
119
|
+
"Changed" timestamp NOT NULL,
|
120
|
+
"MigrationApplicationOrder" int NOT NULL,
|
121
|
+
"FromMigrationID" varchar(80),
|
122
|
+
"ToRangeStartMigrationID" varchar(80) NOT NULL,
|
123
|
+
"ToRangeEndMigrationID" varchar(80) NOT NULL,
|
124
|
+
|
125
|
+
CONSTRAINT PK_previous_states PRIMARY KEY (
|
126
|
+
"Changed",
|
127
|
+
"MigrationApplicationOrder"
|
128
|
+
)
|
129
|
+
);
|
130
|
+
END IF;
|
131
|
+
|
114
132
|
IF NOT EXISTS(
|
115
133
|
SELECT * FROM information_schema.tables
|
116
134
|
WHERE table_schema = 'xmigra' AND table_name = 'access_objects'
|
@@ -145,6 +163,26 @@ module XMigra
|
|
145
163
|
);
|
146
164
|
END IF;
|
147
165
|
|
166
|
+
IF NOT EXISTS(
|
167
|
+
SELECT * FROM information_schema.views
|
168
|
+
WHERE table_schema = 'xmigra' and table_name = 'last_applied_migrations'
|
169
|
+
) THEN
|
170
|
+
CREATE VIEW xmigra.last_applied_migrations AS
|
171
|
+
SELECT
|
172
|
+
row_number() OVER (ORDER BY a."ApplicationOrder" DESC) AS "RevertOrder",
|
173
|
+
a."Description"
|
174
|
+
FROM
|
175
|
+
xmigra.applied a
|
176
|
+
WHERE
|
177
|
+
a."ApplicationOrder" > COALESCE((
|
178
|
+
SELECT ps."MigrationApplicationOrder"
|
179
|
+
FROM xmigra.previous_states ps
|
180
|
+
JOIN xmigra.applied a2 ON ps."ToRangeStartMigrationID" = a2."MigrationID"
|
181
|
+
ORDER BY ps."Changed" DESC
|
182
|
+
LIMIT 1
|
183
|
+
), 0);
|
184
|
+
END IF;
|
185
|
+
|
148
186
|
RAISE NOTICE ' done';
|
149
187
|
}
|
150
188
|
end
|
@@ -292,6 +330,40 @@ module XMigra
|
|
292
330
|
);
|
293
331
|
END IF;
|
294
332
|
|
333
|
+
INSERT INTO xmigra.previous_states (
|
334
|
+
"Changed",
|
335
|
+
"MigrationApplicationOrder",
|
336
|
+
"FromMigrationID",
|
337
|
+
"ToRangeStartMigrationID",
|
338
|
+
"ToRangeEndMigrationID"
|
339
|
+
)
|
340
|
+
SELECT
|
341
|
+
CURRENT_TIMESTAMP,
|
342
|
+
-- Application order of last installed migration --
|
343
|
+
COALESCE(
|
344
|
+
(
|
345
|
+
SELECT "ApplicationOrder" FROM xmigra.applied
|
346
|
+
ORDER BY "ApplicationOrder" DESC
|
347
|
+
),
|
348
|
+
0
|
349
|
+
),
|
350
|
+
( -- Last installed migration --
|
351
|
+
SELECT "MigrationID" FROM xmigra.applied
|
352
|
+
ORDER BY "ApplicationOrder" DESC
|
353
|
+
LIMIT 1
|
354
|
+
),
|
355
|
+
m."MigrationID",
|
356
|
+
( -- Last migration to install --
|
357
|
+
SELECT "MigrationID" FROM temp$xmigra_migrations
|
358
|
+
WHERE "Install"
|
359
|
+
ORDER BY "ApplicationOrder" DESC
|
360
|
+
LIMIT 1
|
361
|
+
)
|
362
|
+
FROM temp$xmigra_migrations m
|
363
|
+
WHERE "Install"
|
364
|
+
ORDER BY "ApplicationOrder" ASC
|
365
|
+
LIMIT 1;
|
366
|
+
|
295
367
|
RAISE NOTICE ' done';
|
296
368
|
})
|
297
369
|
end
|
@@ -490,6 +562,10 @@ module XMigra
|
|
490
562
|
}
|
491
563
|
end
|
492
564
|
|
565
|
+
def reversion_tracking_sql
|
566
|
+
%Q{DELETE FROM xmigra.applied WHERE "MigrationID" = '#{id}';\n}
|
567
|
+
end
|
568
|
+
|
493
569
|
def check_existence_sql(for_existence, error_message)
|
494
570
|
error_message_literal = PgSQLSpecifics.string_literal sprintf(error_message, quoted_name)
|
495
571
|
|
@@ -591,7 +667,7 @@ module XMigra
|
|
591
667
|
DELETE FROM xmigra.applied WHERE "MigrationID" = CompletedMigration.applied;
|
592
668
|
|
593
669
|
INSERT INTO xmigra.applied ("MigrationID", "VersionBridgeMark", "Description")
|
594
|
-
|
670
|
+
VALUES (CompletedMigration.applied, TRUE, 'Branch upgrade from branch ' || CompletedMigration.old_branch || '.');
|
595
671
|
|
596
672
|
RAISE NOTICE ' done';
|
597
673
|
END IF;
|
data/lib/xmigra/migration.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'xmigra/revert_file'
|
1
3
|
|
2
4
|
module XMigra
|
3
5
|
class Migration
|
@@ -18,6 +20,15 @@ module XMigra
|
|
18
20
|
attr_reader :id, :follows, :sql, :description, :changes
|
19
21
|
attr_accessor :file_path
|
20
22
|
|
23
|
+
def schema_dir
|
24
|
+
Pathname(file_path).dirname.join('..')
|
25
|
+
end
|
26
|
+
|
27
|
+
def reversion
|
28
|
+
result = RevertFile.new(self)
|
29
|
+
return result if result.exist?
|
30
|
+
end
|
31
|
+
|
21
32
|
class << self
|
22
33
|
def id_from_filename(fname)
|
23
34
|
XMigra.secure_digest(fname.upcase) # Base64 encoded digest
|
data/lib/xmigra/program.rb
CHANGED
@@ -184,7 +184,7 @@ END_OF_HELP
|
|
184
184
|
|
185
185
|
def output_to(fpath_or_nil)
|
186
186
|
if fpath_or_nil.nil?
|
187
|
-
yield(
|
187
|
+
yield($stdout)
|
188
188
|
else
|
189
189
|
File.open(fpath_or_nil, "w") do |stream|
|
190
190
|
yield(stream)
|
@@ -457,6 +457,7 @@ system shall be targeted for the generation of scripts. Currently the
|
|
457
457
|
supported values are:
|
458
458
|
|
459
459
|
- Microsoft SQL Server
|
460
|
+
- PostgreSQL
|
460
461
|
|
461
462
|
Each system can also have sub-settings that modify the generated scripts.
|
462
463
|
|
@@ -671,6 +672,36 @@ END_OF_HELP
|
|
671
672
|
end
|
672
673
|
end
|
673
674
|
|
675
|
+
subcommand 'reversions', "Generate a script file containing reversions" do |argv|
|
676
|
+
args, options = command_line(argv, {:outfile=>true},
|
677
|
+
:help=> <<END_OF_HELP)
|
678
|
+
This command generates a script file containing parts that can be run to
|
679
|
+
revert individual migrations in reverse of the order they are applied. The
|
680
|
+
SQL for reverting the migration is taken from a file with the same basename
|
681
|
+
as the migration it reverts, but in the 'rollback' subfolder and with a
|
682
|
+
'.sql' extension. The output file will not run as a viable script; a
|
683
|
+
contiguous section starting at the first SQL command and terminating at a
|
684
|
+
migration boundary should be run. Subsequent sections, consecutive with those
|
685
|
+
previously run, may also be run to further revert the database if necessary.
|
686
|
+
|
687
|
+
It may be helpful to execute the query:
|
688
|
+
|
689
|
+
SELECT * FROM xmigra.last_applied_migrations ORDER BY "RevertOrder";
|
690
|
+
|
691
|
+
This query lists the migrations applied by the last upgrade script that was
|
692
|
+
run.
|
693
|
+
END_OF_HELP
|
694
|
+
|
695
|
+
argument_error_unless(args.length == 0,
|
696
|
+
"'%prog %cmd' does not take any arguments.")
|
697
|
+
|
698
|
+
sql_gen = SchemaUpdater.new(options.source_dir).extend(WarnToStderr)
|
699
|
+
|
700
|
+
output_to(options.outfile) do |out_stream|
|
701
|
+
out_stream.print(sql_gen.reversion_script)
|
702
|
+
end
|
703
|
+
end
|
704
|
+
|
674
705
|
subcommand 'render', "Generate SQL script for an access object" do |argv|
|
675
706
|
args, options = command_line(argv, {:outfile=>true},
|
676
707
|
:argument_desc=>"ACCESS_OBJECT_FILE",
|
@@ -0,0 +1,40 @@
|
|
1
|
+
|
2
|
+
module XMigra
|
3
|
+
module ReversionScriptBuilding
|
4
|
+
# This module is intended to be included into XMigra::SchemaUpdater
|
5
|
+
|
6
|
+
def reversions
|
7
|
+
if @reversions.nil?
|
8
|
+
@reversions = []
|
9
|
+
migrations.reverse_each do |m|
|
10
|
+
reversion = m.reversion
|
11
|
+
break unless reversion
|
12
|
+
@reversions << reversion
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
return @reversions if @reversions
|
17
|
+
end
|
18
|
+
|
19
|
+
def reversion_script
|
20
|
+
return nil if reversions.empty?
|
21
|
+
|
22
|
+
usage_note = [
|
23
|
+
"Run the reversion scripts below (separated by -- ======= -- dividers) in",
|
24
|
+
"the order given to revert changes as far as desired. Migrations should",
|
25
|
+
"always be reverted in the order given in this file. If any migration is",
|
26
|
+
"not reverted and one further down this file is, XMigra will no longer be",
|
27
|
+
"able to update the database schema.\n",
|
28
|
+
"The query:",
|
29
|
+
"",
|
30
|
+
" SELECT * FROM xmigra.last_applied_migrations ORDER BY \"RevertOrder\";",
|
31
|
+
"",
|
32
|
+
"lists the migrations applied by the last upgrade script run against this",
|
33
|
+
"database.\n",
|
34
|
+
].collect {|l| '-- ' + l + "\n"}.join('')
|
35
|
+
|
36
|
+
return usage_note + "========================================\n" + \
|
37
|
+
reversions.join("-- ================================== --\n")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
module XMigra
|
4
|
+
class RevertFile
|
5
|
+
REVERSION_SUBDIR = 'rollback'
|
6
|
+
|
7
|
+
def initialize(migration)
|
8
|
+
@migration = migration
|
9
|
+
mig_path = Pathname(migration.file_path)
|
10
|
+
@description = "REVERT #{migration.description} (#{mig_path.basename})"
|
11
|
+
@path = migration.schema_dir.join(
|
12
|
+
REVERSION_SUBDIR,
|
13
|
+
mig_path.basename.to_s.sub(/\..*?$/, '.sql')
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :path, :description
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
if @path.exist?
|
21
|
+
@sql ||= "-- %s:\n\n%s\n%s" % [
|
22
|
+
@description,
|
23
|
+
@path.read,
|
24
|
+
@migration.reversion_tracking_sql
|
25
|
+
]
|
26
|
+
else
|
27
|
+
"-- #@description: No reversion given\n"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def inspect
|
32
|
+
"#<#{self.class.name} %s%s>" % [
|
33
|
+
@path,
|
34
|
+
(" (missing)" unless @path.exist?),
|
35
|
+
]
|
36
|
+
end
|
37
|
+
|
38
|
+
def exist?
|
39
|
+
@path.exist?
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -1,8 +1,11 @@
|
|
1
1
|
|
2
2
|
require 'xmigra/schema_manipulator'
|
3
|
+
require 'xmigra/reversion_script_building'
|
3
4
|
|
4
5
|
module XMigra
|
5
6
|
class SchemaUpdater < SchemaManipulator
|
7
|
+
include ReversionScriptBuilding
|
8
|
+
|
6
9
|
DEV_SCRIPT_WARNING = <<-"END_OF_TEXT"
|
7
10
|
*********************************************************
|
8
11
|
*** WARNING ***
|
data/lib/xmigra/version.rb
CHANGED
data/test/reversions.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
|
2
|
+
def in_xmigra_schema
|
3
|
+
1.temp_dirs do |schema|
|
4
|
+
Dir.chdir(schema) do
|
5
|
+
initialize_xmigra_schema
|
6
|
+
yield
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_migration(migration_name, reversion_sql=nil)
|
12
|
+
tool = XMigra::NewMigrationAdder.new('.')
|
13
|
+
mig_path = tool.add_migration migration_name
|
14
|
+
mig_chain = XMigra::MigrationChain.new('structure')
|
15
|
+
migration = mig_chain[-1]
|
16
|
+
unless reversion_sql.nil?
|
17
|
+
class <<migration
|
18
|
+
def reversion_tracking_sql
|
19
|
+
'-- TRACK REVERSION OF MIGRATION --'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
rev_file = XMigra::RevertFile.new(migration)
|
23
|
+
rev_file.path.dirname.mkpath
|
24
|
+
rev_file.path.open('w') do |rev_stream|
|
25
|
+
rev_stream.puts reversion_sql
|
26
|
+
end
|
27
|
+
end
|
28
|
+
return migration
|
29
|
+
end
|
30
|
+
|
31
|
+
def add_migration_reversion_pair(migration_name, reversion_sql)
|
32
|
+
return [add_migration(migration_name, reversion_sql), reversion_sql]
|
33
|
+
end
|
34
|
+
|
35
|
+
run_test "Generate upgrade with no reversions" do
|
36
|
+
in_xmigra_schema do
|
37
|
+
XMigra::NewMigrationAdder.new('.').tap do |tool|
|
38
|
+
tool.add_migration "Create foo table"
|
39
|
+
end
|
40
|
+
XMigra::Program.run(['upgrade', '--outfile=/dev/null'])
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
run_test "Generate reversions script with no reversions" do
|
45
|
+
in_xmigra_schema do
|
46
|
+
XMigra::NewMigrationAdder.new('.').tap do |tool|
|
47
|
+
tool.add_migration "Create foo table"
|
48
|
+
end
|
49
|
+
XMigra::Program.run(['reversions', '--outfile=/dev/null'])
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
run_test "Migration reversion contains SQL in reversion file" do
|
54
|
+
in_xmigra_schema do
|
55
|
+
reversion_sql = "DROP TABLE foo;"
|
56
|
+
migration = add_migration("Create foo table", reversion_sql)
|
57
|
+
assert("Reversion commands did not contain expected SQL") {
|
58
|
+
migration.reversion.to_s.include? reversion_sql
|
59
|
+
}
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
run_test "Generated revisions script for one migration" do
|
64
|
+
in_xmigra_schema do
|
65
|
+
reversion_sql = "DROP TABLE foo;"
|
66
|
+
migration = add_migration("Create foo table", reversion_sql)
|
67
|
+
assert("Reversions script did not contain reversion SQL") {
|
68
|
+
XMigra::Program.run(['reversions'])
|
69
|
+
test_output.include? reversion_sql
|
70
|
+
}
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
run_test "Generated revisions script for one migration removes application record" do
|
75
|
+
in_xmigra_schema do
|
76
|
+
reversion_sql = "DROP TABLE foo;"
|
77
|
+
migration = add_migration("Create foo table", reversion_sql)
|
78
|
+
assert("Reversions script does not remove migration application record") {
|
79
|
+
XMigra::Program.run(['reversions'])
|
80
|
+
script = test_output
|
81
|
+
script =~ /DELETE\s+FROM\s+.?xmigra.?\..?applied.?\s+WHERE\s+.?MigrationID.?\s*=\s*'#{migration.id}'\s*;/
|
82
|
+
}
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
run_test "Generate reversions script for two migrations" do
|
87
|
+
in_xmigra_schema do
|
88
|
+
migrations = []
|
89
|
+
migrations << add_migration_reversion_pair("Create foo table", "DROP TABLE foo;")
|
90
|
+
migrations << add_migration_reversion_pair("Add bar column to foo table", "ALTER TABLE foo DROP bar;")
|
91
|
+
assert("ALTER TABLE appeared after DROP TABLE") {
|
92
|
+
XMigra::Program.run(['reversions'])
|
93
|
+
script = test_output
|
94
|
+
(script =~ /ALTER\s+TABLE/) < (script =~ /DROP\s+TABLE/)
|
95
|
+
}
|
96
|
+
end
|
97
|
+
end
|
data/test/runner.rb
CHANGED
@@ -7,6 +7,7 @@ require 'tmpdir'
|
|
7
7
|
|
8
8
|
TESTS = %w[
|
9
9
|
git_vcs
|
10
|
+
reversions
|
10
11
|
]
|
11
12
|
|
12
13
|
$:.unshift Pathname(__FILE__).expand_path.dirname.dirname + 'lib'
|
@@ -48,7 +49,13 @@ def run_test(name, &block)
|
|
48
49
|
end
|
49
50
|
else
|
50
51
|
begin
|
51
|
-
|
52
|
+
prev_stdout = $stdout
|
53
|
+
$stdout = StringIO.new
|
54
|
+
begin
|
55
|
+
block.call
|
56
|
+
ensure
|
57
|
+
$stdout = prev_stdout
|
58
|
+
end
|
52
59
|
exit! 0
|
53
60
|
rescue AssertionFailure
|
54
61
|
exit! 2
|
@@ -95,6 +102,11 @@ def initialize_xmigra_schema(path='.', options={})
|
|
95
102
|
end
|
96
103
|
end
|
97
104
|
|
105
|
+
def test_output
|
106
|
+
return nil unless $stdout.kind_of? StringIO
|
107
|
+
return $stdout.string
|
108
|
+
end
|
109
|
+
|
98
110
|
def assert(message=nil, &block)
|
99
111
|
get_message = proc {
|
100
112
|
if !message and File.exist?(block.source_location[0])
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xmigra
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Next IT Corporation
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2015-02-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -73,6 +73,8 @@ files:
|
|
73
73
|
- lib/xmigra/new_migration_adder.rb
|
74
74
|
- lib/xmigra/permission_script_writer.rb
|
75
75
|
- lib/xmigra/program.rb
|
76
|
+
- lib/xmigra/reversion_script_building.rb
|
77
|
+
- lib/xmigra/revert_file.rb
|
76
78
|
- lib/xmigra/schema_manipulator.rb
|
77
79
|
- lib/xmigra/schema_updater.rb
|
78
80
|
- lib/xmigra/stored_procedure.rb
|
@@ -82,6 +84,7 @@ files:
|
|
82
84
|
- lib/xmigra/version.rb
|
83
85
|
- lib/xmigra/view.rb
|
84
86
|
- test/git_vcs.rb
|
87
|
+
- test/reversions.rb
|
85
88
|
- test/runner.rb
|
86
89
|
- xmigra.gemspec
|
87
90
|
homepage: https://github.com/rtweeks/xmigra
|