Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
235b0d3
Add trilogy adapter to rails-8-1 gemfile
Austio Sep 18, 2025
3a4eb44
Setup trilogy test in yml
Austio Sep 18, 2025
580bc8f
Add configuration to switch Departure database adapter version
Austio Sep 18, 2025
0a35ff9
Rename Rails81DepartureAdapter to Rails81Mysql2Adapter
Austio Sep 18, 2025
b276a0e
Add trilogy database adapter
Austio Sep 18, 2025
90426d5
Add spec for mysql/trilogy alter statement commands in adapter
Austio Sep 18, 2025
a525937
Move require statement for trilogy after the active record compatibil…
Austio Sep 19, 2025
fcabff4
Add spec for returning trilogy adapter when it is specified
Austio Sep 19, 2025
6b38704
Move departure adapter loading to after_initialize hooks
Austio Sep 19, 2025
7b1112f
Remove adapter column from rails 8.1. Update configy.yml.erb to expose
Austio Sep 20, 2025
e0989bd
Add spec asserting that we are indeed connecting to the correct adapter
Austio Sep 22, 2025
e38df06
Rename constants in spec files from V8_1_Adapter to the specific V8_1…
Austio Sep 22, 2025
efbb11f
Attempt to adjust CI file to allow trilogy connection
Austio Sep 22, 2025
1947f30
Define column in rails 8.0 and rails 8.1
Austio Sep 22, 2025
2aaef93
Move setup_departure_integration helper and use in Departure::Migrati…
Austio Sep 23, 2025
fa01812
Refactor database to have different configs build a consistent config…
Austio Nov 5, 2025
d9f47fa
Update database.yml to use either socket or host exclusively. Use da…
Austio Nov 5, 2025
801e492
Bump rails appraisal file to 8.1.1
Austio Nov 5, 2025
1e6470e
Run rubocop
Austio Nov 7, 2025
3cbb35c
Add spec for rails 8.0 adapter
Austio Nov 7, 2025
edce126
Update appraisal spec to be rails 8.1 instead of rails 8.1.0.beta1
Austio Nov 7, 2025
2ab05a5
Add test helper to skip loading rails 8.0 and 8.1 when running rails …
Austio Nov 7, 2025
b315873
Update test.yml to not run sudoe to alter user permissions for mysql
Austio Nov 7, 2025
4e5b9b9
Merge branch 'master' into trilogy-adapter-support
Austio Dec 8, 2025
5602188
Readd rails errors for 7.1 and 6.1 being unsupported
Austio Dec 8, 2025
aad936b
Run rubocop
Austio Dec 9, 2025
41a1fd5
Add mysql flush for priviledges due to trilogy error
Austio Dec 10, 2025
d2a2880
Add register_integrations class method to rails adapater. Call that …
Austio Dec 10, 2025
9fbc420
Disable line too long rubocop in specs. This is not helpful
Austio Dec 10, 2025
db7679d
Update rails version under test in rails8.1 for mysql to reference RA…
Austio Dec 10, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 38 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: Test
on: [push, pull_request]

jobs:
test:
test_mysql:
strategy:
fail-fast: false
matrix:
Expand Down Expand Up @@ -36,6 +36,43 @@ jobs:
run: sudo systemctl start mysql.service
- run: bin/setup
- run: bundle exec rake

test_trilogy:
strategy:
fail-fast: false
matrix:
ruby:
- 3.2
- 3.3
- 3.4
gemfile:
- gemfiles/rails_8_1.gemfile
env:
DB_ADAPTER: "trilogy"
PERCONA_DB_USER: root
PERCONA_DB_PASSWORD: root
BUNDLE_GEMFILE: ${{ matrix.gemfile }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true
- name: "Add Percona GPG key"
run: sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 9334A25F8507EFA5
- name: "Add Percona APT repository"
run: echo "deb http://repo.percona.com/apt `lsb_release -cs` main" | sudo tee -a /etc/apt/sources.list
- run: sudo apt-get update -qq
- run: sudo apt-get install percona-toolkit
- name: Start MySQL server
run: sudo systemctl start mysql.service
- name: Configure MySQL for Trilogy
run: |
sudo mysql -u root -proot -e "ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'root'; FLUSH PRIVILEGES;"
- run: bin/setup
- run: bundle exec rake

lint:
strategy:
fail-fast: false
Expand Down
2 changes: 2 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ Layout/LineLength:
Exclude:
- 'departure.gemspec'
- 'test_database.rb'
- 'spec/*'
- 'spec/**/*'

Metrics/MethodLength:
Max: 30
Expand Down
1 change: 1 addition & 0 deletions Appraisals
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ end

appraise 'rails-8-1' do
gem 'rails', '8.1.1'
gem 'trilogy'
end
15 changes: 11 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,16 @@ It's strongly recommended to name it after this gems name, such as

All configuration options are configurable from the `Departure.configure` block example below

|Option|Default|What it Controls|
|---|---|---|
|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|
| Option | Default | What it Controls |
|-----------------------------------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 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 |

### Trilogy Adapter Support

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
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be a problem to support trilogy since rails 7.1?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was also wondering if it wouldn't be possible to get that from the original connection. On my original attempt to implement trilogy support I remember trying that but ended up with the configuration like you did, but I was wondering whether that wasn't possible now.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can derive it from the connection, i'm not 100% there yet with this pr but once i am we can answer the pre 8.1 for complexity if someone is actually needing in rails 8.0 or before.

My initial thought is to put it in 8.1 and beyond so that as people upgrade they will be able to use it.

7.1 is EOL October 1st

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

7.1 -> 8.0 and 8.0 -> 8.1 are easy upgrades, so I won't bother about supporting previous versions.


1. If the database configuration specifies 'trilogy' use the trilogy adapter
2. Default to mysql2

### Disable on per-migration basis

Expand Down Expand Up @@ -226,7 +233,7 @@ adapters.
%% Core Departure Components
subgraph "Departure System"
RailsAdapter["RailsAdapter<br/>(Version Detection)"]
DepartureAdapter["Rails81DepartureAdapter<br/>(Connection Adapter)"]
DepartureAdapter["Rails81MysqlAdapter<br/>(Connection Adapter)"]
Runner["Runner<br/>(Query Interceptor)"]
Command["Command<br/>(Process Executor)"]
CliGenerator["CliGenerator<br/>(Command Builder)"]
Expand Down
24 changes: 12 additions & 12 deletions gemfiles/rails_7_2.gemfile
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# This file was generated by Appraisal

source "https://rubygems.org"
source 'https://rubygems.org'

gem "base64"
gem "codeclimate-test-reporter", "~> 1.0.3", group: :test, require: nil
gem "lhm"
gem "logger"
gem "mutex_m", require: false
gem "rubocop", "~> 1.74.0", require: false
gem "rubocop-performance", "~> 1.20.2", require: false
gem "zeitwerk", "< 2.7.0"
gem "bigdecimal"
gem "rails", "7.2.2.1"
gem 'base64'
gem 'bigdecimal'
gem 'codeclimate-test-reporter', '~> 1.0.3', group: :test, require: nil
gem 'lhm'
gem 'logger'
gem 'mutex_m', require: false
gem 'rails', '7.2.2.1'
gem 'rubocop', '~> 1.74.0', require: false
gem 'rubocop-performance', '~> 1.20.2', require: false
gem 'zeitwerk', '< 2.7.0'

gemspec path: "../"
gemspec path: '../'
24 changes: 12 additions & 12 deletions gemfiles/rails_8_0.gemfile
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# This file was generated by Appraisal

source "https://rubygems.org"
source 'https://rubygems.org'

gem "base64"
gem "codeclimate-test-reporter", "~> 1.0.3", group: :test, require: nil
gem "lhm"
gem "logger"
gem "mutex_m", require: false
gem "rubocop", "~> 1.74.0", require: false
gem "rubocop-performance", "~> 1.20.2", require: false
gem "zeitwerk", "< 2.7.0"
gem "bigdecimal"
gem "rails", "8.0.2.1"
gem 'base64'
gem 'bigdecimal'
gem 'codeclimate-test-reporter', '~> 1.0.3', group: :test, require: nil
gem 'lhm'
gem 'logger'
gem 'mutex_m', require: false
gem 'rails', '8.0.2.1'
gem 'rubocop', '~> 1.74.0', require: false
gem 'rubocop-performance', '~> 1.20.2', require: false
gem 'zeitwerk', '< 2.7.0'

gemspec path: "../"
gemspec path: '../'
23 changes: 12 additions & 11 deletions gemfiles/rails_8_1.gemfile
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
# This file was generated by Appraisal

source "https://rubygems.org"
source 'https://rubygems.org'

gem "base64"
gem "codeclimate-test-reporter", "~> 1.0.3", group: :test, require: nil
gem "lhm"
gem "logger"
gem "mutex_m", require: false
gem "rubocop", "~> 1.74.0", require: false
gem "rubocop-performance", "~> 1.20.2", require: false
gem "zeitwerk", "< 2.7.0"
gem "rails", "8.1.1"
gem 'base64'
gem 'codeclimate-test-reporter', '~> 1.0.3', group: :test, require: nil
gem 'lhm'
gem 'logger'
gem 'mutex_m', require: false
gem 'rails', '8.1.1'
gem 'rubocop', '~> 1.74.0', require: false
gem 'rubocop-performance', '~> 1.20.2', require: false
gem 'trilogy'
gem 'zeitwerk', '< 2.7.0'

gemspec path: "../"
gemspec path: '../'
2 changes: 2 additions & 0 deletions gemfiles/rails_8_1.gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ GEM
stringio (3.1.7)
thor (1.4.0)
timeout (0.4.4)
trilogy (2.9.0)
tsort (0.2.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
Expand Down Expand Up @@ -310,6 +311,7 @@ DEPENDENCIES
rspec-its (~> 1.2)
rubocop (~> 1.74.0)
rubocop-performance (~> 1.20.2)
trilogy
zeitwerk (< 2.7.0)

BUNDLED WITH
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@

module ActiveRecord
module ConnectionAdapters
class Rails81DepartureAdapter < ActiveRecord::ConnectionAdapters::Mysql2Adapter
class Rails81Mysql2Adapter < ActiveRecord::ConnectionAdapters::Mysql2Adapter
TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) } if defined?(initialize_type_map)

class Column < ActiveRecord::ConnectionAdapters::MySQL::Column
def adapter
Rails81DepartureAdapter
Rails81Mysql2Adapter
end
end

Expand All @@ -33,8 +33,6 @@ def visit_DropForeignKey(name) # rubocop:disable Naming/MethodName
end
end

extend Forwardable
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did we forget this here in previous PRs?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🙈 yes my bad


include ForAlterStatements unless method_defined?(:change_column_for_alter)

ADAPTER_NAME = 'Percona'.freeze
Expand Down
77 changes: 77 additions & 0 deletions lib/active_record/connection_adapters/rails_8_1_trilogy_adapter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
require 'active_record/connection_adapters/abstract_mysql_adapter'
require 'active_record/connection_adapters/trilogy_adapter'
require 'active_record/connection_adapters/patch_connection_handling'
require 'departure'
require 'forwardable'

module ActiveRecord
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Core change - add rails 8.1 trilogy adapter

module ConnectionAdapters
class Rails81TrilogyAdapter < ActiveRecord::ConnectionAdapters::TrilogyAdapter
class Column < ActiveRecord::ConnectionAdapters::MySQL::Column
def adapter
Rails81TrilogyAdapter
end
end

# https://github.com/departurerb/departure/commit/f178ca26cd3befa1c68301d3b57810f8cdcff9eb
# For `DROP FOREIGN KEY constraint_name` with pt-online-schema-change requires specifying `_constraint_name`
# rather than the real constraint_name due to to a limitation in MySQL
# pt-online-schema-change adds a leading underscore to foreign key constraint names when creating the new table.
# https://www.percona.com/blog/2017/03/21/dropping-foreign-key-constraint-using-pt-online-schema-change-2/
class SchemaCreation < ActiveRecord::ConnectionAdapters::MySQL::SchemaCreation
def visit_DropForeignKey(name) # rubocop:disable Naming/MethodName
fk_name =
if name =~ /^__(.+)/
Regexp.last_match(1)
else
"_#{name}"
end

"DROP FOREIGN KEY #{fk_name}"
end
end

include ForAlterStatements unless method_defined?(:change_column_for_alter)

ADAPTER_NAME = 'Percona'.freeze

def self.new_client(config)
original_client = super

Departure::DbClient.new(config, original_client)
end

# add_index is modified from the underlying mysql adapter implementation to ensure we add ALTER TABLE to it
def add_index(table_name, column_name, options = {})
index_definition, = add_index_options(table_name, column_name, **options)
execute <<-SQL.squish
ALTER TABLE #{quote_table_name(index_definition.table)}
ADD #{schema_creation.accept(index_definition)}
SQL
end

# remove_index is modified from the underlying mysql adapter implementation to ensure we add ALTER TABLE to it
def remove_index(table_name, column_name = nil, **options)
return if options[:if_exists] && !index_exists?(table_name, column_name, **options)

index_name = index_name_for_remove(table_name, column_name, options)

execute "ALTER TABLE #{quote_table_name(table_name)} DROP INDEX #{quote_column_name(index_name)}"
end

def schema_creation
SchemaCreation.new(self)
end

private

# rubocop:disable Metrics/ParameterLists
def perform_query(raw_connection, sql, binds, type_casted_binds, prepare:, notification_payload:, batch: false)
return raw_connection.send_to_pt_online_schema_change(sql) if raw_connection.alter_statement?(sql)

super
end
# rubocop:enable Metrics/ParameterLists
end
end
end
2 changes: 0 additions & 2 deletions lib/departure.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@
# We need the OS not to buffer the IO to see pt-osc's output while migrating
$stdout.sync = true

Departure::RailsAdapter.for_current.register_integrations
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this not needed anymore? Did this get moved to the railtie?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still tinkering but hoping to pull all the registration into the railtie, if not this will have to work and go back in

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 on this, a railtie is the most appropriate place for registration.


module Departure
class << self
attr_accessor :configuration
Expand Down
3 changes: 2 additions & 1 deletion lib/departure/configuration.rb
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
module Departure
class Configuration
attr_accessor :tmp_path, :global_percona_args, :enabled_by_default, :redirect_stderr,
:disable_rails_advisory_lock_patch
:disable_rails_advisory_lock_patch, :db_adapter_name

def initialize
@tmp_path = '.'.freeze
@error_log_filename = 'departure_error.log'.freeze
@global_percona_args = nil
@enabled_by_default = true
@redirect_stderr = true
@db_adapter_name = nil
end

def error_log_path
Expand Down
Loading