xmigra 1.2.0 → 1.3.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 +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
|