departure 8.0.0 → 8.1.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/.github/workflows/test.yml +38 -1
- data/AGENTS.md +75 -0
- data/Appraisals +1 -0
- data/CHANGELOG.md +12 -0
- data/Gemfile.lock +1 -1
- data/README.md +26 -4
- data/departure.gemspec +2 -3
- data/gemfiles/rails_7_2.gemfile +12 -12
- data/gemfiles/rails_7_2.gemfile.lock +1 -1
- data/gemfiles/rails_8_0.gemfile +12 -12
- data/gemfiles/rails_8_0.gemfile.lock +1 -1
- data/gemfiles/rails_8_1.gemfile +12 -11
- data/gemfiles/rails_8_1.gemfile.lock +3 -1
- data/lib/active_record/connection_adapters/for_alter.rb +0 -6
- data/lib/active_record/connection_adapters/patch_connection_handling.rb +6 -5
- data/lib/active_record/connection_adapters/{rails_8_1_departure_adapter.rb → rails_8_1_adapter_behavior.rb} +12 -31
- data/lib/active_record/connection_adapters/rails_8_1_mysql2_adapter.rb +23 -0
- data/lib/active_record/connection_adapters/rails_8_1_trilogy_adapter.rb +21 -0
- data/lib/departure/migration.rb +40 -10
- data/lib/departure/rails_adapter.rb +68 -32
- data/lib/departure/railtie.rb +2 -0
- data/lib/departure/version.rb +1 -1
- data/lib/departure.rb +0 -2
- metadata +9 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7c430a93842e6abdfa3f64de47ae938c782d53bbaba75ba532baee057b25d471
|
|
4
|
+
data.tar.gz: 0eeaaeaa8a9d6cf83885ab94b4ad1aae833d73f1fd1f9da87414476f5eede157
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4e0b56e69008ab1885216db89d106775ef10198819d2da007476820921c8c382c79aba3d63637a99276c321723112796936b03b5b099db3a629bbe80d9da21f4
|
|
7
|
+
data.tar.gz: d9de074bdaa985d016e83ad61745e3c77930e9262bc5dea7e4d7a5b9db75d86c66db9f2929d14f474f91f1ffbb3397a553b6c4e60fc0c5dd2e9800db15a04ee6
|
data/.github/workflows/test.yml
CHANGED
|
@@ -3,7 +3,7 @@ name: Test
|
|
|
3
3
|
on: [push, pull_request]
|
|
4
4
|
|
|
5
5
|
jobs:
|
|
6
|
-
|
|
6
|
+
test_mysql:
|
|
7
7
|
strategy:
|
|
8
8
|
fail-fast: false
|
|
9
9
|
matrix:
|
|
@@ -36,6 +36,43 @@ jobs:
|
|
|
36
36
|
run: sudo systemctl start mysql.service
|
|
37
37
|
- run: bin/setup
|
|
38
38
|
- run: bundle exec rake
|
|
39
|
+
|
|
40
|
+
test_trilogy:
|
|
41
|
+
strategy:
|
|
42
|
+
fail-fast: false
|
|
43
|
+
matrix:
|
|
44
|
+
ruby:
|
|
45
|
+
- 3.2
|
|
46
|
+
- 3.3
|
|
47
|
+
- 3.4
|
|
48
|
+
gemfile:
|
|
49
|
+
- gemfiles/rails_8_1.gemfile
|
|
50
|
+
env:
|
|
51
|
+
DB_ADAPTER: "trilogy"
|
|
52
|
+
PERCONA_DB_USER: root
|
|
53
|
+
PERCONA_DB_PASSWORD: root
|
|
54
|
+
BUNDLE_GEMFILE: ${{ matrix.gemfile }}
|
|
55
|
+
runs-on: ubuntu-latest
|
|
56
|
+
steps:
|
|
57
|
+
- uses: actions/checkout@v4
|
|
58
|
+
- uses: ruby/setup-ruby@v1
|
|
59
|
+
with:
|
|
60
|
+
ruby-version: ${{ matrix.ruby }}
|
|
61
|
+
bundler-cache: true
|
|
62
|
+
- name: "Add Percona GPG key"
|
|
63
|
+
run: sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 9334A25F8507EFA5
|
|
64
|
+
- name: "Add Percona APT repository"
|
|
65
|
+
run: echo "deb http://repo.percona.com/apt `lsb_release -cs` main" | sudo tee -a /etc/apt/sources.list
|
|
66
|
+
- run: sudo apt-get update -qq
|
|
67
|
+
- run: sudo apt-get install percona-toolkit
|
|
68
|
+
- name: Start MySQL server
|
|
69
|
+
run: sudo systemctl start mysql.service
|
|
70
|
+
- name: Configure MySQL for Trilogy
|
|
71
|
+
run: |
|
|
72
|
+
sudo mysql -u root -proot -e "ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'root'; FLUSH PRIVILEGES;"
|
|
73
|
+
- run: bin/setup
|
|
74
|
+
- run: bundle exec rake
|
|
75
|
+
|
|
39
76
|
lint:
|
|
40
77
|
strategy:
|
|
41
78
|
fail-fast: false
|
data/AGENTS.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Context
|
|
2
|
+
|
|
3
|
+
Departure is a Ruby gem that wraps Rails ActiveRecord migrations using `ALTER TABLE` statements with `pt-online-schema-change` (Percona Toolkit) so DDL runs online and non-blocking.
|
|
4
|
+
|
|
5
|
+
It must stay aware of how the ActiveRecord API changes across versions and supports all currently supported versions of Rails and Ruby.
|
|
6
|
+
|
|
7
|
+
It supports both the `mysql2` and `trilogy` database adapter gems (trilogy on Rails 8.1+).
|
|
8
|
+
|
|
9
|
+
# Project Layout
|
|
10
|
+
|
|
11
|
+
- `lib/active_record/connection_adapters/` — per-Rails-version connection adapters:
|
|
12
|
+
- `rails_7_2_departure_adapter.rb`
|
|
13
|
+
- `rails_8_0_departure_adapter.rb`
|
|
14
|
+
- `rails_8_1_mysql2_adapter.rb`
|
|
15
|
+
- `rails_8_1_trilogy_adapter.rb`
|
|
16
|
+
- `for_alter.rb`, `patch_connection_handling.rb` — shared behavior
|
|
17
|
+
- `lib/departure/rails_adapter.rb` — version dispatch. `Departure::RailsAdapter.for(ar_version, db_connection_adapter:)` selects the right adapter class. New Rails/adapter combinations are wired in here.
|
|
18
|
+
- `lib/departure/railtie.rb` — Rails integration entry point; calls `RailsAdapter.register_integrations`.
|
|
19
|
+
- `lib/departure/runner.rb`, `cli_generator.rb`, `command.rb` — intercept ALTER statements and shell out to `pt-online-schema-change`.
|
|
20
|
+
- `lib/departure/rails_patches/` — targeted patches against ActiveRecord internals.
|
|
21
|
+
- `lib/lhm/` — LHM DSL compatibility shim.
|
|
22
|
+
- `spec/dummy/` — minimal Rails app used by integration specs.
|
|
23
|
+
|
|
24
|
+
# Adapter Selection
|
|
25
|
+
|
|
26
|
+
1. If the database config specifies `trilogy` (Rails 8.1+), use the trilogy adapter.
|
|
27
|
+
2. Otherwise default to `mysql2`.
|
|
28
|
+
|
|
29
|
+
Selection lives in `Departure::RailsAdapter.for`. When adding a new Rails version, add a `V<MAJOR>_<MINOR>_*Adapter` subclass of `BaseAdapter` and update the dispatch logic.
|
|
30
|
+
|
|
31
|
+
# Development
|
|
32
|
+
|
|
33
|
+
- `docker-compose.yml` brings up a MySQL database container and a Rails container with the gem mounted in.
|
|
34
|
+
- The `Appraisal` gem manages Rails version dependencies; configurations live in `Appraisals` and generated gemfiles in `gemfiles/`.
|
|
35
|
+
- Local gems are vendored to `tmp/local_gems` (mounted at `/app/vendor/bundle`) so debugging tools like `pry` can step through ActiveRecord internals.
|
|
36
|
+
|
|
37
|
+
## Required env vars
|
|
38
|
+
Set by `docker-compose.yml`; if running outside Docker, export them yourself:
|
|
39
|
+
|
|
40
|
+
- `PERCONA_DB_USER`
|
|
41
|
+
- `PERCONA_DB_PASSWORD`
|
|
42
|
+
- `PERCONA_DB_HOST`
|
|
43
|
+
- `PERCONA_DB_NAME`
|
|
44
|
+
- `DB_ADAPTER=trilogy` — only when running against trilogy (Rails 8.1)
|
|
45
|
+
|
|
46
|
+
## External dependencies
|
|
47
|
+
|
|
48
|
+
- `pt-online-schema-change` from Percona Toolkit must be on `PATH` — the gem shells out to it. CI installs it from the Percona APT repo.
|
|
49
|
+
- MySQL server. Trilogy requires `mysql_native_password` auth, not `caching_sha2_password`. CI runs `ALTER USER ... IDENTIFIED WITH mysql_native_password` followed by `FLUSH PRIVILEGES` before the trilogy job.
|
|
50
|
+
|
|
51
|
+
# Testing
|
|
52
|
+
|
|
53
|
+
- Be sure that changes are valid against both `rubocop` and the `rspec` suites.
|
|
54
|
+
- The supported test matrix is defined in `.github/workflows/test.yml`:
|
|
55
|
+
- **mysql2:** Ruby 3.2 / 3.3 / 3.4 × Rails 7.2 / 8.0 / 8.1
|
|
56
|
+
- **trilogy:** Ruby 3.2 / 3.3 / 3.4 × Rails 8.1 only
|
|
57
|
+
- **lint:** Ruby 3.4 with the Rails 8.1 gemfile
|
|
58
|
+
- Run inside Docker via `appraisal`:
|
|
59
|
+
- Full suite: `docker compose exec rails bundle exec appraisal rails-8-1 bundle exec rspec spec`
|
|
60
|
+
- Single example: `docker compose exec rails bundle exec appraisal rails-8-1 bundle exec rspec spec/path/to_spec.rb:LINE`
|
|
61
|
+
- Trilogy run: prepend `DB_ADAPTER=trilogy` to the rspec command (rails-8-1 only)
|
|
62
|
+
- Lint: `docker compose exec rails bundle exec appraisal rails-8-1 bundle exec rubocop --parallel`
|
|
63
|
+
|
|
64
|
+
# Adding a Rails version
|
|
65
|
+
|
|
66
|
+
1. Add an `appraise '<rails-x-y>' do ... end` block in `Appraisals`.
|
|
67
|
+
2. `bundle exec appraisal generate && bundle exec appraisal install`
|
|
68
|
+
3. Add a matching `V<X>_<Y>_*Adapter` class in `lib/departure/rails_adapter.rb` and a connection-adapter file under `lib/active_record/connection_adapters/`.
|
|
69
|
+
4. Update the `gemfile:` matrix in `.github/workflows/test.yml`. Add a separate `test_trilogy` entry only if trilogy is supported on that version.
|
|
70
|
+
|
|
71
|
+
# Conventions
|
|
72
|
+
|
|
73
|
+
- Follow the existing adapter naming pattern: `rails_<MAJOR>_<MINOR>_<DRIVER>_adapter.rb` and register through `Departure::RailsAdapter`. Don't introduce a parallel registration path.
|
|
74
|
+
- User-visible changes go in `CHANGELOG.md` (Keep a Changelog format).
|
|
75
|
+
- Release process is documented in `RELEASING.md`.
|
data/Appraisals
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,18 @@ Please follow the format in [Keep a Changelog](http://keepachangelog.com/)
|
|
|
6
6
|
|
|
7
7
|
## [NEXT]
|
|
8
8
|
|
|
9
|
+
## [8.1.0] - 2026-05-28
|
|
10
|
+
|
|
11
|
+
- [Add Rails 8.1 Trilogy adapter support](https://github.com/departurerb/departure/pull/132)
|
|
12
|
+
|
|
13
|
+
## [8.0.2] - 2026-04-30
|
|
14
|
+
|
|
15
|
+
- [Fix Rails multi-database migrations](https://github.com/departurerb/departure/pull/138)
|
|
16
|
+
|
|
17
|
+
## [8.0.1] - 2025-12-12
|
|
18
|
+
|
|
19
|
+
- [Remove stderr message "Including for_alter statements"](https://github.com/departurerb/departure/pull/136)
|
|
20
|
+
|
|
9
21
|
## [8.0.0] - 2025-11-24
|
|
10
22
|
|
|
11
23
|
- Bump [appraisal to 2.5.0](https://github.com/departurerb/departure/pull/129)
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -151,9 +151,16 @@ It's strongly recommended to name it after this gems name, such as
|
|
|
151
151
|
|
|
152
152
|
All configuration options are configurable from the `Departure.configure` block example below
|
|
153
153
|
|
|
154
|
-
|Option|Default|What it Controls|
|
|
155
|
-
|
|
156
|
-
|disable_rails_advisory_lock_patch|false|When truthy, disables a patch in at least rails 7.1 and 7.2 where rails throws ConcurrentMigrationErrors due to the inability to release the advisory lock in migrations|
|
|
154
|
+
| Option | Default | What it Controls |
|
|
155
|
+
|-----------------------------------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
156
|
+
| disable_rails_advisory_lock_patch | false | When truthy, disables a patch in at least rails 7.1 and 7.2 where rails throws ConcurrentMigrationErrors due to the inability to release the advisory lock in migrations |
|
|
157
|
+
|
|
158
|
+
### Trilogy Adapter Support
|
|
159
|
+
|
|
160
|
+
Starting in Rails 8.1 we add support for the use of the trilogy database adapter gem. Logic for selecting an adapter follows this logic
|
|
161
|
+
|
|
162
|
+
1. If the database configuration specifies 'trilogy' use the trilogy adapter
|
|
163
|
+
2. Default to mysql2
|
|
157
164
|
|
|
158
165
|
### Disable on per-migration basis
|
|
159
166
|
|
|
@@ -213,6 +220,21 @@ When any errors occur, an `ActiveRecord::StatementInvalid` exception is
|
|
|
213
220
|
raised and the migration is aborted, as all other ActiveRecord connection
|
|
214
221
|
adapters.
|
|
215
222
|
|
|
223
|
+
### Rails multi-database applications
|
|
224
|
+
|
|
225
|
+
Rails multi-database applications expect `bin/rails db:migrate` to run
|
|
226
|
+
migrations for every configured database. Rails 8.1 does this through
|
|
227
|
+
`ActiveRecord::Tasks::DatabaseTasks.migrate_all`, which temporarily switches the
|
|
228
|
+
migration connection to each database configuration before running that
|
|
229
|
+
database's migrations.
|
|
230
|
+
|
|
231
|
+
Departure supports that flow by restoring Rails' migration connection identity
|
|
232
|
+
after each migration. During the migration body, Departure can still reconnect
|
|
233
|
+
with the Percona adapter so `ALTER TABLE` statements go through
|
|
234
|
+
`pt-online-schema-change`. After the migration finishes, Rails gets back the
|
|
235
|
+
same `ActiveRecord::Base.connection_specification_name` it had before Departure
|
|
236
|
+
swapped adapters, so the next configured database can be migrated normally.
|
|
237
|
+
|
|
216
238
|
### Diagram
|
|
217
239
|
|
|
218
240
|
```mermaid
|
|
@@ -226,7 +248,7 @@ adapters.
|
|
|
226
248
|
%% Core Departure Components
|
|
227
249
|
subgraph "Departure System"
|
|
228
250
|
RailsAdapter["RailsAdapter<br/>(Version Detection)"]
|
|
229
|
-
DepartureAdapter["
|
|
251
|
+
DepartureAdapter["Rails81Mysql2Adapter<br/>(Connection Adapter)"]
|
|
230
252
|
Runner["Runner<br/>(Query Interceptor)"]
|
|
231
253
|
Command["Command<br/>(Process Executor)"]
|
|
232
254
|
CliGenerator["CliGenerator<br/>(Command Builder)"]
|
data/departure.gemspec
CHANGED
|
@@ -8,9 +8,8 @@ require 'departure/version'
|
|
|
8
8
|
Gem::Specification.new do |spec|
|
|
9
9
|
spec.name = 'departure'
|
|
10
10
|
spec.version = Departure::VERSION
|
|
11
|
-
spec.authors = ['Ilya Zayats', 'Pau Pérez', 'Fran Casas', 'Jorge Morante', 'Enrico Stano', 'Adrian Serafin', 'Kirk Haines', 'Guillermo Iguaran']
|
|
12
|
-
spec.email = ['ilya.zayats@redbooth.com', 'pau.perez@redbooth.com', 'nflamel@gmail.com', 'jorge.morante@redbooth.com', 'adrian@softmad.pl', 'wyhaines@gmail.com', 'guilleiguaran@gmail.com']
|
|
13
|
-
|
|
11
|
+
spec.authors = ['Ilya Zayats', 'Pau Pérez', 'Fran Casas', 'Jorge Morante', 'Enrico Stano', 'Adrian Serafin', 'Kirk Haines', 'Guillermo Iguaran', 'Austin Story', 'Douglas Soares de Andrade']
|
|
12
|
+
spec.email = ['ilya.zayats@redbooth.com', 'pau.perez@redbooth.com', 'nflamel@gmail.com', 'jorge.morante@redbooth.com', 'adrian@softmad.pl', 'wyhaines@gmail.com', 'guilleiguaran@gmail.com', 'lonnieastory@gmail.com', 'douglas@51street.dev']
|
|
14
13
|
spec.summary = %q(pt-online-schema-change runner for ActiveRecord migrations)
|
|
15
14
|
spec.description = %q(Execute your ActiveRecord migrations with Percona's pt-online-schema-change. Formerly known as Percona Migrator.)
|
|
16
15
|
spec.homepage = 'https://github.com/departurerb/departure'
|
data/gemfiles/rails_7_2.gemfile
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
# This file was generated by Appraisal
|
|
2
2
|
|
|
3
|
-
source
|
|
3
|
+
source 'https://rubygems.org'
|
|
4
4
|
|
|
5
|
-
gem
|
|
6
|
-
gem
|
|
7
|
-
gem
|
|
8
|
-
gem
|
|
9
|
-
gem
|
|
10
|
-
gem
|
|
11
|
-
gem
|
|
12
|
-
gem
|
|
13
|
-
gem
|
|
14
|
-
gem
|
|
5
|
+
gem 'base64'
|
|
6
|
+
gem 'bigdecimal'
|
|
7
|
+
gem 'codeclimate-test-reporter', '~> 1.0.3', group: :test, require: nil
|
|
8
|
+
gem 'lhm'
|
|
9
|
+
gem 'logger'
|
|
10
|
+
gem 'mutex_m', require: false
|
|
11
|
+
gem 'rails', '7.2.2.1'
|
|
12
|
+
gem 'rubocop', '~> 1.74.0', require: false
|
|
13
|
+
gem 'rubocop-performance', '~> 1.20.2', require: false
|
|
14
|
+
gem 'zeitwerk', '< 2.7.0'
|
|
15
15
|
|
|
16
|
-
gemspec path:
|
|
16
|
+
gemspec path: '../'
|
data/gemfiles/rails_8_0.gemfile
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
# This file was generated by Appraisal
|
|
2
2
|
|
|
3
|
-
source
|
|
3
|
+
source 'https://rubygems.org'
|
|
4
4
|
|
|
5
|
-
gem
|
|
6
|
-
gem
|
|
7
|
-
gem
|
|
8
|
-
gem
|
|
9
|
-
gem
|
|
10
|
-
gem
|
|
11
|
-
gem
|
|
12
|
-
gem
|
|
13
|
-
gem
|
|
14
|
-
gem
|
|
5
|
+
gem 'base64'
|
|
6
|
+
gem 'bigdecimal'
|
|
7
|
+
gem 'codeclimate-test-reporter', '~> 1.0.3', group: :test, require: nil
|
|
8
|
+
gem 'lhm'
|
|
9
|
+
gem 'logger'
|
|
10
|
+
gem 'mutex_m', require: false
|
|
11
|
+
gem 'rails', '8.0.2.1'
|
|
12
|
+
gem 'rubocop', '~> 1.74.0', require: false
|
|
13
|
+
gem 'rubocop-performance', '~> 1.20.2', require: false
|
|
14
|
+
gem 'zeitwerk', '< 2.7.0'
|
|
15
15
|
|
|
16
|
-
gemspec path:
|
|
16
|
+
gemspec path: '../'
|
data/gemfiles/rails_8_1.gemfile
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
# This file was generated by Appraisal
|
|
2
2
|
|
|
3
|
-
source
|
|
3
|
+
source 'https://rubygems.org'
|
|
4
4
|
|
|
5
|
-
gem
|
|
6
|
-
gem
|
|
7
|
-
gem
|
|
8
|
-
gem
|
|
9
|
-
gem
|
|
10
|
-
gem
|
|
11
|
-
gem
|
|
12
|
-
gem
|
|
13
|
-
gem
|
|
5
|
+
gem 'base64'
|
|
6
|
+
gem 'codeclimate-test-reporter', '~> 1.0.3', group: :test, require: nil
|
|
7
|
+
gem 'lhm'
|
|
8
|
+
gem 'logger'
|
|
9
|
+
gem 'mutex_m', require: false
|
|
10
|
+
gem 'rails', '8.1.1'
|
|
11
|
+
gem 'rubocop', '~> 1.74.0', require: false
|
|
12
|
+
gem 'rubocop-performance', '~> 1.20.2', require: false
|
|
13
|
+
gem 'trilogy'
|
|
14
|
+
gem 'zeitwerk', '< 2.7.0'
|
|
14
15
|
|
|
15
|
-
gemspec path:
|
|
16
|
+
gemspec path: '../'
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: ..
|
|
3
3
|
specs:
|
|
4
|
-
departure (8.
|
|
4
|
+
departure (8.1.0)
|
|
5
5
|
activerecord (>= 7.2.0)
|
|
6
6
|
mysql2 (>= 0.4.0, < 0.6.0)
|
|
7
7
|
railties (>= 7.2.0)
|
|
@@ -270,6 +270,7 @@ GEM
|
|
|
270
270
|
stringio (3.1.7)
|
|
271
271
|
thor (1.4.0)
|
|
272
272
|
timeout (0.4.4)
|
|
273
|
+
trilogy (2.9.0)
|
|
273
274
|
tsort (0.2.0)
|
|
274
275
|
tzinfo (2.0.6)
|
|
275
276
|
concurrent-ruby (~> 1.0)
|
|
@@ -310,6 +311,7 @@ DEPENDENCIES
|
|
|
310
311
|
rspec-its (~> 1.2)
|
|
311
312
|
rubocop (~> 1.74.0)
|
|
312
313
|
rubocop-performance (~> 1.20.2)
|
|
314
|
+
trilogy
|
|
313
315
|
zeitwerk (< 2.7.0)
|
|
314
316
|
|
|
315
317
|
BUNDLED WITH
|
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
require 'active_record/connection_adapters/mysql/schema_statements'
|
|
2
2
|
|
|
3
3
|
module ForAlterStatements
|
|
4
|
-
class << self
|
|
5
|
-
def included(_)
|
|
6
|
-
STDERR.puts 'Including for_alter statements'
|
|
7
|
-
end
|
|
8
|
-
end
|
|
9
|
-
|
|
10
4
|
def bulk_change_table(table_name, operations) #:nodoc:
|
|
11
5
|
sqls = operations.flat_map do |command, args|
|
|
12
6
|
table = args.shift
|
|
@@ -7,12 +7,13 @@ module ActiveRecord
|
|
|
7
7
|
# Establishes a connection to the database that's used by all Active
|
|
8
8
|
# Record objects.
|
|
9
9
|
def percona_connection(config)
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
end
|
|
10
|
+
config = config.dup
|
|
11
|
+
original_adapter = config.delete(:departure_original_adapter)
|
|
12
|
+
config[:username] ||= 'root'
|
|
14
13
|
|
|
15
|
-
Departure::RailsAdapter
|
|
14
|
+
Departure::RailsAdapter
|
|
15
|
+
.for_current(db_connection_adapter: original_adapter)
|
|
16
|
+
.create_connection_adapter(**config)
|
|
16
17
|
end
|
|
17
18
|
end
|
|
18
19
|
end
|
|
@@ -1,25 +1,6 @@
|
|
|
1
|
-
require 'active_record/connection_adapters/abstract_mysql_adapter'
|
|
2
|
-
require 'active_record/connection_adapters/mysql2_adapter'
|
|
3
|
-
require 'active_record/connection_adapters/patch_connection_handling'
|
|
4
|
-
require 'departure'
|
|
5
|
-
require 'forwardable'
|
|
6
|
-
|
|
7
1
|
module ActiveRecord
|
|
8
2
|
module ConnectionAdapters
|
|
9
|
-
|
|
10
|
-
TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) } if defined?(initialize_type_map)
|
|
11
|
-
|
|
12
|
-
class Column < ActiveRecord::ConnectionAdapters::MySQL::Column
|
|
13
|
-
def adapter
|
|
14
|
-
Rails81DepartureAdapter
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
# https://github.com/departurerb/departure/commit/f178ca26cd3befa1c68301d3b57810f8cdcff9eb
|
|
19
|
-
# For `DROP FOREIGN KEY constraint_name` with pt-online-schema-change requires specifying `_constraint_name`
|
|
20
|
-
# rather than the real constraint_name due to to a limitation in MySQL
|
|
21
|
-
# pt-online-schema-change adds a leading underscore to foreign key constraint names when creating the new table.
|
|
22
|
-
# https://www.percona.com/blog/2017/03/21/dropping-foreign-key-constraint-using-pt-online-schema-change-2/
|
|
3
|
+
module Rails81AdapterBehavior
|
|
23
4
|
class SchemaCreation < ActiveRecord::ConnectionAdapters::MySQL::SchemaCreation
|
|
24
5
|
def visit_DropForeignKey(name) # rubocop:disable Naming/MethodName
|
|
25
6
|
fk_name =
|
|
@@ -33,16 +14,18 @@ module ActiveRecord
|
|
|
33
14
|
end
|
|
34
15
|
end
|
|
35
16
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
17
|
+
def self.included(adapter_class)
|
|
18
|
+
adapter_class.const_set(:SchemaCreation, SchemaCreation)
|
|
19
|
+
adapter_class.extend(ClassMethods)
|
|
20
|
+
adapter_class.include ForAlterStatements unless adapter_class.method_defined?(:change_column_for_alter)
|
|
21
|
+
end
|
|
41
22
|
|
|
42
|
-
|
|
43
|
-
|
|
23
|
+
module ClassMethods
|
|
24
|
+
def new_client(config)
|
|
25
|
+
original_client = super
|
|
44
26
|
|
|
45
|
-
|
|
27
|
+
Departure::DbClient.new(config, original_client)
|
|
28
|
+
end
|
|
46
29
|
end
|
|
47
30
|
|
|
48
31
|
# add_index is modified from the underlying mysql adapter implementation to ensure we add ALTER TABLE to it
|
|
@@ -64,13 +47,11 @@ module ActiveRecord
|
|
|
64
47
|
end
|
|
65
48
|
|
|
66
49
|
def schema_creation
|
|
67
|
-
SchemaCreation.new(self)
|
|
50
|
+
self.class::SchemaCreation.new(self)
|
|
68
51
|
end
|
|
69
52
|
|
|
70
53
|
private
|
|
71
54
|
|
|
72
|
-
attr_reader :mysql_adapter
|
|
73
|
-
|
|
74
55
|
# rubocop:disable Metrics/ParameterLists
|
|
75
56
|
def perform_query(raw_connection, sql, binds, type_casted_binds, prepare:, notification_payload:, batch: false)
|
|
76
57
|
return raw_connection.send_to_pt_online_schema_change(sql) if raw_connection.alter_statement?(sql)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require 'active_record/connection_adapters/abstract_mysql_adapter'
|
|
2
|
+
require 'active_record/connection_adapters/mysql2_adapter'
|
|
3
|
+
require 'active_record/connection_adapters/patch_connection_handling'
|
|
4
|
+
require 'departure'
|
|
5
|
+
require 'active_record/connection_adapters/rails_8_1_adapter_behavior'
|
|
6
|
+
|
|
7
|
+
module ActiveRecord
|
|
8
|
+
module ConnectionAdapters
|
|
9
|
+
class Rails81Mysql2Adapter < ActiveRecord::ConnectionAdapters::Mysql2Adapter
|
|
10
|
+
TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) } if defined?(initialize_type_map)
|
|
11
|
+
|
|
12
|
+
class Column < ActiveRecord::ConnectionAdapters::MySQL::Column
|
|
13
|
+
def adapter
|
|
14
|
+
Rails81Mysql2Adapter
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
ADAPTER_NAME = 'Percona'.freeze
|
|
19
|
+
|
|
20
|
+
include Rails81AdapterBehavior
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'active_record/connection_adapters/abstract_mysql_adapter'
|
|
2
|
+
require 'active_record/connection_adapters/trilogy_adapter'
|
|
3
|
+
require 'active_record/connection_adapters/patch_connection_handling'
|
|
4
|
+
require 'departure'
|
|
5
|
+
require 'active_record/connection_adapters/rails_8_1_adapter_behavior'
|
|
6
|
+
|
|
7
|
+
module ActiveRecord
|
|
8
|
+
module ConnectionAdapters
|
|
9
|
+
class Rails81TrilogyAdapter < ActiveRecord::ConnectionAdapters::TrilogyAdapter
|
|
10
|
+
class Column < ActiveRecord::ConnectionAdapters::MySQL::Column
|
|
11
|
+
def adapter
|
|
12
|
+
Rails81TrilogyAdapter
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
ADAPTER_NAME = 'Percona'.freeze
|
|
17
|
+
|
|
18
|
+
include Rails81AdapterBehavior
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
data/lib/departure/migration.rb
CHANGED
|
@@ -8,6 +8,8 @@ module Departure
|
|
|
8
8
|
module Migration
|
|
9
9
|
extend ActiveSupport::Concern
|
|
10
10
|
|
|
11
|
+
DEPARTURE_ADAPTERS = %w[percona percona_trilogy].freeze
|
|
12
|
+
|
|
11
13
|
included do
|
|
12
14
|
# Holds the name of the adapter that was configured by the app.
|
|
13
15
|
mattr_accessor :original_adapter
|
|
@@ -53,11 +55,13 @@ module Departure
|
|
|
53
55
|
# Migrate with or without Departure based on uses_departure class
|
|
54
56
|
# attribute.
|
|
55
57
|
def migrate(direction)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
with_restored_connection_specification_name do
|
|
59
|
+
if uses_departure?
|
|
60
|
+
departure_migrate(direction)
|
|
61
|
+
else
|
|
62
|
+
reconnect_without_percona
|
|
63
|
+
active_record_migrate(direction)
|
|
64
|
+
end
|
|
61
65
|
end
|
|
62
66
|
end
|
|
63
67
|
|
|
@@ -73,15 +77,29 @@ module Departure
|
|
|
73
77
|
# Make all connections in the connection pool to use PerconaAdapter
|
|
74
78
|
# instead of the current adapter.
|
|
75
79
|
def reconnect_with_percona
|
|
76
|
-
|
|
77
|
-
|
|
80
|
+
config = connection_config
|
|
81
|
+
return if departure_adapter_config?(config)
|
|
82
|
+
|
|
83
|
+
departure_adapter = Departure::RailsAdapter.for_current(db_connection_adapter: config[:adapter])
|
|
84
|
+
Departure::ConnectionBase.establish_connection(
|
|
85
|
+
config.merge(
|
|
86
|
+
adapter: departure_adapter.departure_adapter_name,
|
|
87
|
+
departure_original_adapter: config[:adapter]
|
|
88
|
+
)
|
|
89
|
+
)
|
|
78
90
|
end
|
|
79
91
|
|
|
80
92
|
# Reconnect without percona adapter when Departure is disabled but was
|
|
81
93
|
# enabled in a previous migration.
|
|
82
94
|
def reconnect_without_percona
|
|
83
|
-
|
|
84
|
-
|
|
95
|
+
config = connection_config
|
|
96
|
+
return unless departure_adapter_config?(config)
|
|
97
|
+
|
|
98
|
+
Departure::OriginalAdapterConnection.establish_connection(
|
|
99
|
+
config
|
|
100
|
+
.except(:departure_original_adapter)
|
|
101
|
+
.merge(adapter: config[:departure_original_adapter] || original_adapter)
|
|
102
|
+
)
|
|
85
103
|
end
|
|
86
104
|
|
|
87
105
|
private
|
|
@@ -89,12 +107,24 @@ module Departure
|
|
|
89
107
|
# Capture the type of the adapter configured by the app if not already set.
|
|
90
108
|
def connection_config
|
|
91
109
|
configuration_hash.tap do |config|
|
|
92
|
-
self.class.original_adapter ||= config[:adapter]
|
|
110
|
+
self.class.original_adapter ||= config[:departure_original_adapter] || config[:adapter]
|
|
93
111
|
end
|
|
94
112
|
end
|
|
95
113
|
|
|
114
|
+
private def departure_adapter_config?(config)
|
|
115
|
+
DEPARTURE_ADAPTERS.include?(config[:adapter])
|
|
116
|
+
end
|
|
117
|
+
|
|
96
118
|
private def configuration_hash
|
|
97
119
|
ActiveRecord::Base.connection_db_config.configuration_hash
|
|
98
120
|
end
|
|
121
|
+
|
|
122
|
+
private def with_restored_connection_specification_name
|
|
123
|
+
connection_specification_name = ActiveRecord::Base.connection_specification_name
|
|
124
|
+
|
|
125
|
+
yield
|
|
126
|
+
ensure
|
|
127
|
+
ActiveRecord::Base.connection_specification_name = connection_specification_name
|
|
128
|
+
end
|
|
99
129
|
end
|
|
100
130
|
end
|
|
@@ -10,7 +10,13 @@ module Departure
|
|
|
10
10
|
class MustImplementError < StandardError; end
|
|
11
11
|
|
|
12
12
|
class << self
|
|
13
|
+
def register_integrations(**args)
|
|
14
|
+
for_current(**args).register_integrations
|
|
15
|
+
end
|
|
16
|
+
|
|
13
17
|
def version_matches?(version_string, compatibility_string = current_version::STRING)
|
|
18
|
+
raise "Invalid Gem Version: '#{version_string}'" unless Gem::Version.correct?(version_string)
|
|
19
|
+
|
|
14
20
|
requirement = Gem::Requirement.new(compatibility_string)
|
|
15
21
|
requirement.satisfied_by?(Gem::Version.new(version_string))
|
|
16
22
|
end
|
|
@@ -19,13 +25,19 @@ module Departure
|
|
|
19
25
|
ActiveRecord::VERSION
|
|
20
26
|
end
|
|
21
27
|
|
|
22
|
-
def for_current
|
|
23
|
-
self.for(current_version)
|
|
28
|
+
def for_current(**args)
|
|
29
|
+
self.for(current_version, **args)
|
|
24
30
|
end
|
|
25
31
|
|
|
26
|
-
|
|
32
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
|
33
|
+
def for(ar_version, db_connection_adapter: nil)
|
|
34
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
|
27
35
|
if ar_version::MAJOR == 8 && ar_version::MINOR.positive?
|
|
28
|
-
|
|
36
|
+
if db_connection_adapter == 'trilogy'
|
|
37
|
+
V8_1_TrilogyAdapter
|
|
38
|
+
else
|
|
39
|
+
V8_1_Mysql2Adapter
|
|
40
|
+
end
|
|
29
41
|
elsif ar_version::MAJOR == 8
|
|
30
42
|
V8_0_Adapter
|
|
31
43
|
elsif ar_version::MAJOR >= 7 && ar_version::MINOR >= 2
|
|
@@ -47,6 +59,10 @@ module Departure
|
|
|
47
59
|
raise MustImplementError, 'adapter must implement create_connection_adapter'
|
|
48
60
|
end
|
|
49
61
|
|
|
62
|
+
def departure_adapter_name
|
|
63
|
+
'percona'
|
|
64
|
+
end
|
|
65
|
+
|
|
50
66
|
# https://github.com/rails/rails/commit/9ad36e067222478090b36a985090475bb03e398c#diff-de807ece2205a84c0e3de66b0e5ab831325d567893b8b88ce0d6e9d498f923d1
|
|
51
67
|
# Rails Column arity changed to require cast_type in position 2 which required us introducing this indirection
|
|
52
68
|
def new_sql_column(name:,
|
|
@@ -69,14 +85,12 @@ module Departure
|
|
|
69
85
|
require 'active_record/connection_adapters/rails_7_2_departure_adapter'
|
|
70
86
|
require 'departure/rails_patches/active_record_migrator_with_advisory_lock_patch'
|
|
71
87
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
include Departure::Migration
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
ActiveRecord::Migrator.prepend Departure::RailsPatches::ActiveRecordMigratorWithAdvisoryLockPatch
|
|
88
|
+
ActiveRecord::Migration.class_eval do
|
|
89
|
+
include Departure::Migration
|
|
78
90
|
end
|
|
79
91
|
|
|
92
|
+
ActiveRecord::Migrator.prepend Departure::RailsPatches::ActiveRecordMigratorWithAdvisoryLockPatch
|
|
93
|
+
|
|
80
94
|
ActiveRecord::ConnectionAdapters.register 'percona',
|
|
81
95
|
'ActiveRecord::ConnectionAdapters::Rails72DepartureAdapter',
|
|
82
96
|
'active_record/connection_adapters/rails_7_2_departure_adapter'
|
|
@@ -98,14 +112,12 @@ module Departure
|
|
|
98
112
|
require 'active_record/connection_adapters/rails_8_0_departure_adapter'
|
|
99
113
|
require 'departure/rails_patches/active_record_migrator_with_advisory_lock_patch'
|
|
100
114
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
include Departure::Migration
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
ActiveRecord::Migrator.prepend Departure::RailsPatches::ActiveRecordMigratorWithAdvisoryLockPatch
|
|
115
|
+
ActiveRecord::Migration.class_eval do
|
|
116
|
+
include Departure::Migration
|
|
107
117
|
end
|
|
108
118
|
|
|
119
|
+
ActiveRecord::Migrator.prepend Departure::RailsPatches::ActiveRecordMigratorWithAdvisoryLockPatch
|
|
120
|
+
|
|
109
121
|
ActiveRecord::ConnectionAdapters.register 'percona',
|
|
110
122
|
'ActiveRecord::ConnectionAdapters::Rails80DepartureAdapter',
|
|
111
123
|
'active_record/connection_adapters/rails_8_0_departure_adapter'
|
|
@@ -121,27 +133,15 @@ module Departure
|
|
|
121
133
|
end
|
|
122
134
|
end
|
|
123
135
|
|
|
124
|
-
class
|
|
136
|
+
class V8_1_Mysql2Adapter < BaseAdapter # rubocop:disable Naming/ClassAndModuleCamelCase
|
|
125
137
|
class << self
|
|
126
138
|
def register_integrations
|
|
127
|
-
require 'active_record/connection_adapters/
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
ActiveSupport.on_load(:active_record) do
|
|
131
|
-
ActiveRecord::Migration.class_eval do
|
|
132
|
-
include Departure::Migration
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
ActiveRecord::Migrator.prepend Departure::RailsPatches::ActiveRecordMigratorWithAdvisoryLockPatch
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
ActiveRecord::ConnectionAdapters.register 'percona',
|
|
139
|
-
'ActiveRecord::ConnectionAdapters::Rails81DepartureAdapter',
|
|
140
|
-
'active_record/connection_adapters/rails_8_1_departure_adapter'
|
|
139
|
+
require 'active_record/connection_adapters/rails_8_1_mysql2_adapter'
|
|
140
|
+
register_rails_8_1_integrations
|
|
141
141
|
end
|
|
142
142
|
|
|
143
143
|
def create_connection_adapter(**config)
|
|
144
|
-
ActiveRecord::ConnectionAdapters::
|
|
144
|
+
ActiveRecord::ConnectionAdapters::Rails81Mysql2Adapter.new(config)
|
|
145
145
|
end
|
|
146
146
|
|
|
147
147
|
# rubocop:disable Metrics/ParameterLists
|
|
@@ -160,6 +160,42 @@ module Departure
|
|
|
160
160
|
def sql_column
|
|
161
161
|
::ActiveRecord::ConnectionAdapters::MySQL::Column
|
|
162
162
|
end
|
|
163
|
+
|
|
164
|
+
private
|
|
165
|
+
|
|
166
|
+
def register_rails_8_1_integrations
|
|
167
|
+
require 'departure/rails_patches/active_record_migrator_with_advisory_lock_patch'
|
|
168
|
+
|
|
169
|
+
ActiveRecord::Migration.class_eval do
|
|
170
|
+
include Departure::Migration
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
ActiveRecord::Migrator.prepend Departure::RailsPatches::ActiveRecordMigratorWithAdvisoryLockPatch
|
|
174
|
+
|
|
175
|
+
ActiveRecord::ConnectionAdapters.register 'percona',
|
|
176
|
+
'ActiveRecord::ConnectionAdapters::Rails81Mysql2Adapter',
|
|
177
|
+
'active_record/connection_adapters/rails_8_1_mysql2_adapter'
|
|
178
|
+
ActiveRecord::ConnectionAdapters.register 'percona_trilogy',
|
|
179
|
+
'ActiveRecord::ConnectionAdapters::Rails81TrilogyAdapter',
|
|
180
|
+
'active_record/connection_adapters/rails_8_1_trilogy_adapter'
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
class V8_1_TrilogyAdapter < V8_1_Mysql2Adapter # rubocop:disable Naming/ClassAndModuleCamelCase
|
|
186
|
+
class << self
|
|
187
|
+
def register_integrations
|
|
188
|
+
require 'active_record/connection_adapters/rails_8_1_trilogy_adapter'
|
|
189
|
+
register_rails_8_1_integrations
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def create_connection_adapter(**config)
|
|
193
|
+
ActiveRecord::ConnectionAdapters::Rails81TrilogyAdapter.new(config)
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def departure_adapter_name
|
|
197
|
+
'percona_trilogy'
|
|
198
|
+
end
|
|
163
199
|
end
|
|
164
200
|
end
|
|
165
201
|
end
|
data/lib/departure/railtie.rb
CHANGED
data/lib/departure/version.rb
CHANGED
data/lib/departure.rb
CHANGED
|
@@ -23,8 +23,6 @@ require 'departure/railtie' if defined?(Rails)
|
|
|
23
23
|
# We need the OS not to buffer the IO to see pt-osc's output while migrating
|
|
24
24
|
$stdout.sync = true
|
|
25
25
|
|
|
26
|
-
Departure::RailsAdapter.for_current.register_integrations
|
|
27
|
-
|
|
28
26
|
module Departure
|
|
29
27
|
class << self
|
|
30
28
|
attr_accessor :configuration
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: departure
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 8.
|
|
4
|
+
version: 8.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ilya Zayats
|
|
@@ -12,6 +12,8 @@ authors:
|
|
|
12
12
|
- Adrian Serafin
|
|
13
13
|
- Kirk Haines
|
|
14
14
|
- Guillermo Iguaran
|
|
15
|
+
- Austin Story
|
|
16
|
+
- Douglas Soares de Andrade
|
|
15
17
|
bindir: bin
|
|
16
18
|
cert_chain: []
|
|
17
19
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
@@ -164,6 +166,8 @@ email:
|
|
|
164
166
|
- adrian@softmad.pl
|
|
165
167
|
- wyhaines@gmail.com
|
|
166
168
|
- guilleiguaran@gmail.com
|
|
169
|
+
- lonnieastory@gmail.com
|
|
170
|
+
- douglas@51street.dev
|
|
167
171
|
executables: []
|
|
168
172
|
extensions: []
|
|
169
173
|
extra_rdoc_files: []
|
|
@@ -175,6 +179,7 @@ files:
|
|
|
175
179
|
- ".rspec"
|
|
176
180
|
- ".rubocop.yml"
|
|
177
181
|
- ".rubocop_todo.yml"
|
|
182
|
+
- AGENTS.md
|
|
178
183
|
- Appraisals
|
|
179
184
|
- CHANGELOG.md
|
|
180
185
|
- CODE_OF_CONDUCT.md
|
|
@@ -203,7 +208,9 @@ files:
|
|
|
203
208
|
- lib/active_record/connection_adapters/patch_connection_handling.rb
|
|
204
209
|
- lib/active_record/connection_adapters/rails_7_2_departure_adapter.rb
|
|
205
210
|
- lib/active_record/connection_adapters/rails_8_0_departure_adapter.rb
|
|
206
|
-
- lib/active_record/connection_adapters/
|
|
211
|
+
- lib/active_record/connection_adapters/rails_8_1_adapter_behavior.rb
|
|
212
|
+
- lib/active_record/connection_adapters/rails_8_1_mysql2_adapter.rb
|
|
213
|
+
- lib/active_record/connection_adapters/rails_8_1_trilogy_adapter.rb
|
|
207
214
|
- lib/departure.rb
|
|
208
215
|
- lib/departure/alter_argument.rb
|
|
209
216
|
- lib/departure/cli_generator.rb
|