capture_migration_sql 1.0.3 → 1.0.5
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/CHANGELOG.md +30 -4
- data/README.md +2 -1
- data/VERSION +1 -1
- data/capture_migration_sql.gemspec +9 -3
- data/lib/capture_migration_sql/migration_extension.rb +28 -13
- data/lib/capture_migration_sql/sql_subscriber.rb +24 -6
- data/lib/capture_migration_sql.rb +21 -3
- metadata +10 -25
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 244ae0fce5c5654d09321b61daea560a442e213b395fb532145f611f8622f873
|
|
4
|
+
data.tar.gz: 3bb661d211e3a5bf357cdcd447f7b8516ae48e5a7a3c0b27810bc67db388b5c7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: df54712d0d2471fe64222635299652c816cee27309ce42cb4a7d783975cac9e6485fcb3aef192e0cd3403e813992117d1a42eb361668c786a622c23322b992f6
|
|
7
|
+
data.tar.gz: b130cec56900275e6e2da6771814fba7cc0f9ce4fc0d87c5f2303980031a8c67085c2200f87f9741ff92f345ef797b3b0b8b53964a38041b6ec5f8e98ea080c7
|
data/CHANGELOG.md
CHANGED
|
@@ -4,22 +4,48 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## 1.0.5
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- SQL files are no longer deleted before a down migration runs; if the down migration fails, the SQL file is kept since the migration is still applied.
|
|
12
|
+
- SQL files are now written to a temporary file and atomically renamed into place, so a process killed mid-migration can no longer leave a permanent, truncated SQL file behind.
|
|
13
|
+
- The migration SQL directory is now created with `FileUtils.mkdir_p`, eliminating a race condition between concurrent migration processes and supporting nested custom directories.
|
|
14
|
+
- Attaching the SQL subscriber is now thread safe, preventing duplicate subscribers (and duplicated SQL output) when migrations run in parallel threads.
|
|
15
|
+
- Ignored statement filters are now applied after stripping leading whitespace, so statements with leading whitespace no longer bypass them.
|
|
16
|
+
- The `INSERT INTO schema_migrations` statement written to SQL files now honors custom schema migrations table names and table name prefixes and suffixes.
|
|
17
|
+
- Connection labels from `using_connection` are no longer written to the SQL file when SQL logging is disabled.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- Rails 5.2 and Ruby 2.6 are the minimum supported versions.
|
|
22
|
+
|
|
23
|
+
## 1.0.4
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- SQL files are now removed when they were created from a failed migration.
|
|
28
|
+
|
|
7
29
|
## 1.0.3
|
|
8
30
|
|
|
9
31
|
### Changed
|
|
10
|
-
|
|
32
|
+
|
|
33
|
+
- SQL files will not be changed if they already exist.
|
|
11
34
|
|
|
12
35
|
## 1.0.2
|
|
13
36
|
|
|
14
37
|
### Changed
|
|
15
|
-
|
|
38
|
+
|
|
39
|
+
- Fix data type for insterting into schema_migrations
|
|
16
40
|
|
|
17
41
|
## 1.0.1
|
|
18
42
|
|
|
19
43
|
### Changed
|
|
20
|
-
|
|
44
|
+
|
|
45
|
+
- Fix SQL for insterting into schema_migrations
|
|
21
46
|
|
|
22
47
|
## 1.0.0
|
|
23
48
|
|
|
24
49
|
### Added
|
|
25
|
-
|
|
50
|
+
|
|
51
|
+
- Initial release
|
data/README.md
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Capture Migration SQL
|
|
2
2
|
|
|
3
3
|
[](https://github.com/bdurand/capture_migration_sql/actions/workflows/continuous_integration.yml)
|
|
4
4
|
[](https://github.com/testdouble/standard)
|
|
5
|
+
[](https://badge.fury.io/rb/capture_migration_sql)
|
|
5
6
|
|
|
6
7
|
This gem adds the ability to capture and persist the SQL statements executed by migrations. There are a couple of reasons why you may want to do this.
|
|
7
8
|
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.0.
|
|
1
|
+
1.0.5
|
|
@@ -10,6 +10,12 @@ Gem::Specification.new do |spec|
|
|
|
10
10
|
spec.homepage = "https://github.com/bdurand/capture_migration_sql"
|
|
11
11
|
spec.license = "MIT"
|
|
12
12
|
|
|
13
|
+
spec.metadata = {
|
|
14
|
+
"homepage_uri" => spec.homepage,
|
|
15
|
+
"source_code_uri" => spec.homepage,
|
|
16
|
+
"changelog_uri" => "#{spec.homepage}/blob/main/CHANGELOG.md"
|
|
17
|
+
}
|
|
18
|
+
|
|
13
19
|
# Specify which files should be added to the gem when it is released.
|
|
14
20
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
15
21
|
ignore_files = %w[
|
|
@@ -21,13 +27,13 @@ Gem::Specification.new do |spec|
|
|
|
21
27
|
gemfiles/
|
|
22
28
|
spec/
|
|
23
29
|
]
|
|
24
|
-
spec.files = Dir.chdir(
|
|
30
|
+
spec.files = Dir.chdir(__dir__) do
|
|
25
31
|
`git ls-files -z`.split("\x0").reject { |f| ignore_files.any? { |path| f.start_with?(path) } }
|
|
26
32
|
end
|
|
27
33
|
|
|
28
34
|
spec.require_paths = ["lib"]
|
|
29
35
|
|
|
30
|
-
spec.add_dependency "activerecord", ">=
|
|
36
|
+
spec.add_dependency "activerecord", ">= 5.2"
|
|
31
37
|
|
|
32
|
-
spec.
|
|
38
|
+
spec.required_ruby_version = ">= 2.6"
|
|
33
39
|
end
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "fileutils"
|
|
4
|
+
|
|
3
5
|
# Extension methods for ActiveRecord::Migration class.
|
|
4
6
|
module CaptureMigrationSql
|
|
5
7
|
module MigrationExtension
|
|
@@ -18,7 +20,7 @@ module CaptureMigrationSql
|
|
|
18
20
|
end
|
|
19
21
|
|
|
20
22
|
# Enable SQL logging. You can call this method within a block where SQL
|
|
21
|
-
# logging was disabled to
|
|
23
|
+
# logging was disabled to re-enable it.
|
|
22
24
|
def enable_sql_logging(&block)
|
|
23
25
|
sql_logging(enabled: true, &block)
|
|
24
26
|
end
|
|
@@ -46,7 +48,7 @@ module CaptureMigrationSql
|
|
|
46
48
|
save_connection = @connection
|
|
47
49
|
begin
|
|
48
50
|
@connection = connection
|
|
49
|
-
stream = CaptureMigrationSql.capture_stream
|
|
51
|
+
stream = CaptureMigrationSql.capture_stream if CaptureMigrationSql.capture_enabled?
|
|
50
52
|
stream.write("-- BEGIN #{label}\n\n") if label && stream
|
|
51
53
|
retval = yield
|
|
52
54
|
stream.write("-- END #{label}\n\n") if label && stream
|
|
@@ -73,24 +75,37 @@ module CaptureMigrationSql
|
|
|
73
75
|
if File.exist?(output_file)
|
|
74
76
|
yield
|
|
75
77
|
else
|
|
76
|
-
|
|
78
|
+
FileUtils.mkdir_p(migration_sql_dir)
|
|
77
79
|
SqlSubscriber.attach_if_necessary
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
Thread.current[:capture_migration_sql_stream] = f
|
|
83
|
-
sql_logging(enabled: true, &block)
|
|
84
|
-
ensure
|
|
85
|
-
Thread.current[:capture_migration_sql_stream] = save_stream
|
|
80
|
+
temp_file = "#{output_file}.tmp.#{Process.pid}.#{Thread.current.object_id}"
|
|
81
|
+
begin
|
|
82
|
+
retval = File.open(temp_file, "w") do |f|
|
|
83
|
+
capture_migration_sql(f, &block)
|
|
86
84
|
end
|
|
87
|
-
|
|
85
|
+
File.rename(temp_file, output_file)
|
|
86
|
+
retval
|
|
87
|
+
ensure
|
|
88
|
+
File.unlink(temp_file) if File.exist?(temp_file)
|
|
88
89
|
end
|
|
89
90
|
end
|
|
90
91
|
else
|
|
92
|
+
retval = yield
|
|
91
93
|
File.unlink(output_file) if output_file && File.exist?(output_file)
|
|
92
|
-
|
|
94
|
+
retval
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def capture_migration_sql(f, &block)
|
|
99
|
+
f.write("--\n-- #{name} : #{version}\n--\n\n")
|
|
100
|
+
save_stream = Thread.current[:capture_migration_sql_stream]
|
|
101
|
+
begin
|
|
102
|
+
Thread.current[:capture_migration_sql_stream] = f
|
|
103
|
+
retval = sql_logging(enabled: true, &block)
|
|
104
|
+
ensure
|
|
105
|
+
Thread.current[:capture_migration_sql_stream] = save_stream
|
|
93
106
|
end
|
|
107
|
+
f.write("INSERT INTO #{CaptureMigrationSql.schema_migrations_table_name} (version) VALUES ('#{version.to_i}');\n")
|
|
108
|
+
retval
|
|
94
109
|
end
|
|
95
110
|
end
|
|
96
111
|
end
|
|
@@ -10,16 +10,19 @@ module CaptureMigrationSql
|
|
|
10
10
|
|
|
11
11
|
SHOW_STATEMENT = /\ASHOW\b/i
|
|
12
12
|
EXPLAIN_STATEMENT = /\AEXPLAIN\b/i
|
|
13
|
-
SELECT_SCHEMA_MIGRATIONS = /\ASELECT.*FROM.*schema_migrations/i
|
|
14
13
|
SELECT_INFORMATION_SCHEMA = /\ASELECT.*information_schema/im
|
|
15
14
|
SQLLITE_VERSION = /\ASELECT sqlite_version\(/i
|
|
16
|
-
IGNORE_STATEMENTS = Regexp.union(SHOW_STATEMENT, EXPLAIN_STATEMENT,
|
|
15
|
+
IGNORE_STATEMENTS = Regexp.union(SHOW_STATEMENT, EXPLAIN_STATEMENT, SELECT_INFORMATION_SCHEMA, SQLLITE_VERSION)
|
|
16
|
+
|
|
17
|
+
ATTACH_MUTEX = Mutex.new
|
|
17
18
|
|
|
18
19
|
class << self
|
|
19
20
|
def attach_if_necessary
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
ATTACH_MUTEX.synchronize do
|
|
22
|
+
unless defined?(@attached) && @attached
|
|
23
|
+
attach_to(:active_record)
|
|
24
|
+
@attached = true
|
|
25
|
+
end
|
|
23
26
|
end
|
|
24
27
|
end
|
|
25
28
|
end
|
|
@@ -31,11 +34,26 @@ module CaptureMigrationSql
|
|
|
31
34
|
payload = event.payload
|
|
32
35
|
return if IGNORE_PAYLOAD_NAMES.include?(payload[:name])
|
|
33
36
|
sql = payload[:sql]
|
|
34
|
-
return if sql.nil?
|
|
37
|
+
return if sql.nil?
|
|
35
38
|
|
|
36
39
|
sql = sql.strip
|
|
40
|
+
return if IGNORE_STATEMENTS.match(sql)
|
|
41
|
+
return if schema_migrations_query?(sql)
|
|
42
|
+
|
|
37
43
|
sql = "#{sql};" unless sql.end_with?(";")
|
|
38
44
|
stream.write("#{sql}\n\n")
|
|
39
45
|
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
# Ignore ActiveRecord's own reads of the schema migrations table. The
|
|
50
|
+
# table name is resolved at runtime so that custom table names and any
|
|
51
|
+
# table name prefix or suffix are matched, staying consistent with the
|
|
52
|
+
# name written to the SQL file.
|
|
53
|
+
def schema_migrations_query?(sql)
|
|
54
|
+
table_name = CaptureMigrationSql.schema_migrations_table_name
|
|
55
|
+
return false if table_name.nil? || table_name.empty?
|
|
56
|
+
/\ASELECT.*FROM.*#{Regexp.escape(table_name)}/im.match?(sql)
|
|
57
|
+
end
|
|
40
58
|
end
|
|
41
59
|
end
|
|
@@ -18,7 +18,7 @@ module CaptureMigrationSql
|
|
|
18
18
|
unless ::ActiveRecord::Migration.include?(MigrationExtension)
|
|
19
19
|
::ActiveRecord::Migration.prepend(MigrationExtension)
|
|
20
20
|
end
|
|
21
|
-
@sql_directory =
|
|
21
|
+
@sql_directory = directory || Rails.root + "db" + "migration_sql"
|
|
22
22
|
@starting_with_version = starting_with.to_i
|
|
23
23
|
end
|
|
24
24
|
|
|
@@ -27,7 +27,7 @@ module CaptureMigrationSql
|
|
|
27
27
|
@sql_directory if defined?(@sql_directory)
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
# Return the migration version number to start
|
|
30
|
+
# Return the migration version number to start capturing SQL.
|
|
31
31
|
def starting_with_version
|
|
32
32
|
@starting_with_version if defined?(@starting_with_version)
|
|
33
33
|
end
|
|
@@ -37,9 +37,27 @@ module CaptureMigrationSql
|
|
|
37
37
|
!!Thread.current[:capture_migration_sql_enabled]
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
-
# Return the
|
|
40
|
+
# Return the stream migration SQL is being written to.
|
|
41
41
|
def capture_stream
|
|
42
42
|
Thread.current[:capture_migration_sql_stream]
|
|
43
43
|
end
|
|
44
|
+
|
|
45
|
+
# Resolve the schema migrations table name so that both the SQL that is
|
|
46
|
+
# written to the file and the statement filter honor custom table names
|
|
47
|
+
# and any table name prefix or suffix. Falls back to "schema_migrations"
|
|
48
|
+
# if the name cannot be determined.
|
|
49
|
+
def schema_migrations_table_name
|
|
50
|
+
if defined?(ActiveRecord::SchemaMigration) && ActiveRecord::SchemaMigration.respond_to?(:table_name)
|
|
51
|
+
ActiveRecord::SchemaMigration.table_name
|
|
52
|
+
else
|
|
53
|
+
connection = ActiveRecord::Base.connection
|
|
54
|
+
schema_migration = if connection.respond_to?(:schema_migration)
|
|
55
|
+
connection.schema_migration
|
|
56
|
+
elsif connection.pool.respond_to?(:schema_migration)
|
|
57
|
+
connection.pool.schema_migration
|
|
58
|
+
end
|
|
59
|
+
schema_migration ? schema_migration.table_name : "schema_migrations"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
44
62
|
end
|
|
45
63
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: capture_migration_sql
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Brian Durand
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: activerecord
|
|
@@ -16,29 +15,14 @@ dependencies:
|
|
|
16
15
|
requirements:
|
|
17
16
|
- - ">="
|
|
18
17
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '
|
|
18
|
+
version: '5.2'
|
|
20
19
|
type: :runtime
|
|
21
20
|
prerelease: false
|
|
22
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
22
|
requirements:
|
|
24
23
|
- - ">="
|
|
25
24
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '
|
|
27
|
-
- !ruby/object:Gem::Dependency
|
|
28
|
-
name: bundler
|
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
|
30
|
-
requirements:
|
|
31
|
-
- - ">="
|
|
32
|
-
- !ruby/object:Gem::Version
|
|
33
|
-
version: '0'
|
|
34
|
-
type: :development
|
|
35
|
-
prerelease: false
|
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
-
requirements:
|
|
38
|
-
- - ">="
|
|
39
|
-
- !ruby/object:Gem::Version
|
|
40
|
-
version: '0'
|
|
41
|
-
description:
|
|
25
|
+
version: '5.2'
|
|
42
26
|
email:
|
|
43
27
|
- bbdurand@gmail.com
|
|
44
28
|
executables: []
|
|
@@ -57,8 +41,10 @@ files:
|
|
|
57
41
|
homepage: https://github.com/bdurand/capture_migration_sql
|
|
58
42
|
licenses:
|
|
59
43
|
- MIT
|
|
60
|
-
metadata:
|
|
61
|
-
|
|
44
|
+
metadata:
|
|
45
|
+
homepage_uri: https://github.com/bdurand/capture_migration_sql
|
|
46
|
+
source_code_uri: https://github.com/bdurand/capture_migration_sql
|
|
47
|
+
changelog_uri: https://github.com/bdurand/capture_migration_sql/blob/main/CHANGELOG.md
|
|
62
48
|
rdoc_options: []
|
|
63
49
|
require_paths:
|
|
64
50
|
- lib
|
|
@@ -66,15 +52,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
66
52
|
requirements:
|
|
67
53
|
- - ">="
|
|
68
54
|
- !ruby/object:Gem::Version
|
|
69
|
-
version: '
|
|
55
|
+
version: '2.6'
|
|
70
56
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
71
57
|
requirements:
|
|
72
58
|
- - ">="
|
|
73
59
|
- !ruby/object:Gem::Version
|
|
74
60
|
version: '0'
|
|
75
61
|
requirements: []
|
|
76
|
-
rubygems_version:
|
|
77
|
-
signing_key:
|
|
62
|
+
rubygems_version: 4.0.3
|
|
78
63
|
specification_version: 4
|
|
79
64
|
summary: Capture the SQL that is executed when running ActiveRecord migrations so
|
|
80
65
|
that it can be run in in other environments that don't support migrations.
|