alterity 0.9.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/alterity.rb +8 -8
- data/lib/alterity/configuration.rb +20 -30
- data/lib/alterity/default_configuration.rb +15 -0
- data/lib/alterity/mysql_client_additions.rb +2 -0
- data/lib/alterity/version.rb +1 -1
- data/spec/alterity_spec.rb +3 -1
- data/spec/bin/custom_config.rb +21 -0
- data/spec/bin/rails_app_migration_test.sh +64 -3
- data/spec/bin/test_custom_config_result.rb +20 -0
- metadata +8 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b468009cfd8631b397ea59fcb1750aada7238d5b8910f6cc492cf4778bdc2fa6
|
4
|
+
data.tar.gz: 02e17258c42233d8198ad62cf15841d6c3fe78b4b2730f64100e1771693686a1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8929653022fbcec5f31c5583c619d252547928319276b020021404ad38cdbf2a2fae1861f9748009fcc97f99c0bc7a07f698397d6c8d20d41bbd96251b7a3693
|
7
|
+
data.tar.gz: ec349e1dfee9361ef937e55fe8911da437fad1c7dfc74446ff7f7ce2608943e0755f238297e5073f8786b2a6a0d9dc71c6785a1b91f1d7b04efe4b4a548a1b46
|
data/lib/alterity.rb
CHANGED
@@ -8,14 +8,14 @@ require "alterity/railtie"
|
|
8
8
|
class Alterity
|
9
9
|
class << self
|
10
10
|
def process_sql_query(sql, &block)
|
11
|
-
case sql.strip
|
12
|
-
when /^alter
|
11
|
+
case sql.tr("\n", " ").strip
|
12
|
+
when /^alter\s+table\s+(?<table>.+?)\s+(?<updates>.+)/i
|
13
13
|
execute_alter($~[:table], $~[:updates])
|
14
|
-
when /^create
|
14
|
+
when /^create\s+index\s+(?<index>.+?)\s+on\s+(?<table>.+?)\s+(?<updates>.+)/i
|
15
15
|
execute_alter($~[:table], "ADD INDEX #{$~[:index]} #{$~[:updates]}")
|
16
|
-
when /^create
|
16
|
+
when /^create\s+unique\s+index\s+(?<index>.+?)\s+on\s+(?<table>.+?)\s+(?<updates>.+)/i
|
17
17
|
execute_alter($~[:table], "ADD UNIQUE INDEX #{$~[:index]} #{$~[:updates]}")
|
18
|
-
when /^drop
|
18
|
+
when /^drop\s+index\s+(?<index>.+?)\s+on\s+(?<table>.+)/i
|
19
19
|
execute_alter($~[:table], "DROP INDEX #{$~[:index]}")
|
20
20
|
else
|
21
21
|
block.call
|
@@ -38,9 +38,9 @@ class Alterity
|
|
38
38
|
def execute_alter(table, updates)
|
39
39
|
altered_table = table.delete("`")
|
40
40
|
alter_argument = %("#{updates.gsub('"', '\\"').gsub('`', '\\\`')}")
|
41
|
-
prepared_command = config.command.call(
|
41
|
+
prepared_command = config.command.call(altered_table, alter_argument).to_s.gsub(/\n/, "\\\n")
|
42
42
|
puts "[Alterity] Will execute: #{prepared_command}"
|
43
|
-
system(prepared_command)
|
43
|
+
system(prepared_command) || raise("[Alterity] Command failed")
|
44
44
|
end
|
45
45
|
|
46
46
|
def set_database_config
|
@@ -70,7 +70,7 @@ class Alterity
|
|
70
70
|
return if config.replicas_dsns.empty?
|
71
71
|
|
72
72
|
connection.execute <<~SQL
|
73
|
-
INSERT INTO #{table} (dsn)
|
73
|
+
INSERT INTO #{table} (dsn) VALUES
|
74
74
|
#{config.replicas_dsns.map { |dsn| "('#{dsn}')" }.join(',')}
|
75
75
|
SQL
|
76
76
|
end
|
@@ -13,46 +13,36 @@ class Alterity
|
|
13
13
|
class << self
|
14
14
|
def reset_state_and_configuration
|
15
15
|
self.config = Configuration.new
|
16
|
-
|
16
|
+
class << config
|
17
|
+
def replicas(database:, table:, dsns:)
|
18
|
+
return ArgumentError.new("database & table must be present") if database.blank? || table.blank?
|
19
|
+
|
20
|
+
self.replicas_dsns_database = database
|
21
|
+
self.replicas_dsns_table = table
|
22
|
+
self.replicas_dsns = dsns.uniq.map do |dsn|
|
23
|
+
parts = dsn.split(",")
|
24
|
+
# automatically add default port
|
25
|
+
parts << "P=3306" unless parts.any? { |part| part.start_with?("P=") }
|
26
|
+
# automatically remove master
|
27
|
+
next if parts.include?("h=#{host}") && parts.include?("P=#{port}")
|
28
|
+
|
29
|
+
parts.join(",")
|
30
|
+
end.compact
|
31
|
+
end
|
32
|
+
end
|
17
33
|
|
18
|
-
|
19
|
-
|
20
|
-
pt-online-schema-change
|
21
|
-
-h #{config.host}
|
22
|
-
-P #{config.port}
|
23
|
-
-u #{config.username}
|
24
|
-
--password=#{config.password}
|
25
|
-
--execute
|
26
|
-
D=#{config.database},t=#{altered_table}
|
27
|
-
--alter #{alter_argument}
|
28
|
-
SHELL
|
29
|
-
}
|
34
|
+
self.state = CurrentState.new
|
35
|
+
load "#{__dir__}/default_configuration.rb"
|
30
36
|
end
|
31
37
|
|
32
38
|
def configure
|
33
|
-
yield
|
39
|
+
yield config
|
34
40
|
end
|
35
41
|
|
36
42
|
def command=(new_command)
|
37
43
|
config.command = new_command
|
38
44
|
end
|
39
45
|
|
40
|
-
def replicas_dsns_table(database:, table:, dsns:)
|
41
|
-
return ArgumentError.new("database & table must be present") if database.blank? || table.blank?
|
42
|
-
|
43
|
-
config.replicas_dsns_database = database
|
44
|
-
config.replicas_dsns_table = table
|
45
|
-
config.replicas_dsns = dsns.uniq.map do |dsn|
|
46
|
-
parts = dsn.split(",")
|
47
|
-
# automatically add default port
|
48
|
-
parts << "P=3306" unless parts.any? { |part| part.start_with?("P=") }
|
49
|
-
# automatically remove master
|
50
|
-
next if parts.include?("h=#{config.host}") && parts.include?("P=#{config.port}")
|
51
|
-
|
52
|
-
parts.join(",")
|
53
|
-
end.compact
|
54
|
-
end
|
55
|
-
|
56
46
|
def disable
|
57
47
|
state.disabled = true
|
58
48
|
yield
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Alterity.configure do |config|
|
4
|
+
config.command = lambda { |altered_table, alter_argument|
|
5
|
+
parts = ["pt-online-schema-change"]
|
6
|
+
parts << %(-h "#{config.host}") if config.host.present?
|
7
|
+
parts << %(-P "#{config.port}") if config.port.present?
|
8
|
+
parts << %(-u "#{config.username}") if config.username.present?
|
9
|
+
parts << %(--password "#{config.password.gsub('"', '\\"')}") if config.password.present?
|
10
|
+
parts << "--execute"
|
11
|
+
parts << "D=#{config.database},t=#{altered_table}"
|
12
|
+
parts << "--alter #{alter_argument}"
|
13
|
+
parts.join(" ")
|
14
|
+
}
|
15
|
+
end
|
data/lib/alterity/version.rb
CHANGED
data/spec/alterity_spec.rb
CHANGED
@@ -9,8 +9,10 @@ RSpec.describe Alterity do
|
|
9
9
|
["CREATE INDEX `idx_users_on_col` ON `users` (col)", "`users`", "ADD INDEX `idx_users_on_col` (col)"],
|
10
10
|
["CREATE UNIQUE INDEX `idx_users_on_col` ON `users` (col)", "`users`", "ADD UNIQUE INDEX `idx_users_on_col` (col)"],
|
11
11
|
["DROP INDEX `idx_users_on_col` ON `users`", "`users`", "DROP INDEX `idx_users_on_col`"],
|
12
|
-
["alter table users drop col", "users", "drop col"]
|
12
|
+
["alter table users drop col", "users", "drop col"],
|
13
|
+
[" ALTER TABLE\n users\n DROP col", "users", "DROP col"]
|
13
14
|
].each do |(query, expected_table, expected_updates)|
|
15
|
+
puts query.inspect
|
14
16
|
expected_block = proc {}
|
15
17
|
expect(expected_block).not_to receive(:call)
|
16
18
|
expect(Alterity).to receive(:execute_alter).with(expected_table, expected_updates)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Alterity.configure do |config|
|
4
|
+
config.command = lambda { |altered_table, alter_argument|
|
5
|
+
string = config.to_h.slice(
|
6
|
+
*%i[host port username database replicas_dsns_database replicas_dsns_table replicas_dsns]
|
7
|
+
).to_s
|
8
|
+
system("echo '#{string}' > /tmp/custom_command_result.txt")
|
9
|
+
system("echo '#{altered_table}' >> /tmp/custom_command_result.txt")
|
10
|
+
system("echo '#{alter_argument}' >> /tmp/custom_command_result.txt")
|
11
|
+
}
|
12
|
+
|
13
|
+
config.replicas(
|
14
|
+
database: "percona",
|
15
|
+
table: "replicas_dsns",
|
16
|
+
dsns: [
|
17
|
+
"h=host1",
|
18
|
+
"h=host2"
|
19
|
+
]
|
20
|
+
)
|
21
|
+
end
|
@@ -1,7 +1,68 @@
|
|
1
1
|
#!/usr/bin/env bash
|
2
2
|
|
3
|
-
set -
|
3
|
+
set -euox pipefail
|
4
|
+
|
5
|
+
unset BUNDLE_GEMFILE # because we're going to create a new rails app here and use bundler
|
4
6
|
|
5
|
-
printenv
|
6
|
-
sudo apt update
|
7
7
|
sudo apt install percona-toolkit
|
8
|
+
|
9
|
+
# Fixes: `Cannot connect to MySQL: Cannot get MySQL var character_set_server: DBD::mysql::db selectrow_array failed: Table 'performance_schema.session_variables' doesn't exist [for Statement "SHOW VARIABLES LIKE 'character_set_server'"] at /usr/local/Cellar/percona-toolkit/3.3.0/libexec/bin/pt-online-schema-change line 2415.`
|
10
|
+
mysql -h $MYSQL_HOST -u $MYSQL_USERNAME -e 'set @@global.show_compatibility_56=ON'
|
11
|
+
|
12
|
+
gem install rails -v $RAILS_VERSION
|
13
|
+
|
14
|
+
rails new testapp \
|
15
|
+
--skip-action-mailer \
|
16
|
+
--skip-action-mailbox \
|
17
|
+
--skip-action-text \
|
18
|
+
--skip-active-job \
|
19
|
+
--skip-active-storage \
|
20
|
+
--skip-puma \
|
21
|
+
--skip-action-cable \
|
22
|
+
--skip-sprockets \
|
23
|
+
--skip-spring \
|
24
|
+
--skip-listen--skip-javascript \
|
25
|
+
--skip-turbolinks \
|
26
|
+
--skip-jbuilder--skip-test \
|
27
|
+
--skip-system-test \
|
28
|
+
--skip-bootsnap \
|
29
|
+
--skip-javascript \
|
30
|
+
--skip-webpack-install
|
31
|
+
|
32
|
+
cd testapp
|
33
|
+
|
34
|
+
# Sanity check:
|
35
|
+
# echo 'gem "mysql2"' >> Gemfile
|
36
|
+
|
37
|
+
echo 'gem "alterity", path: "../"' >> Gemfile
|
38
|
+
|
39
|
+
bundle
|
40
|
+
|
41
|
+
# Local machine test
|
42
|
+
# echo 'development:
|
43
|
+
# adapter: mysql2
|
44
|
+
# database: alterity_test' > config/database.yml
|
45
|
+
# bundle e rails db:drop db:create
|
46
|
+
|
47
|
+
echo 'development:
|
48
|
+
adapter: mysql2
|
49
|
+
database: <%= ENV.fetch("MYSQL_DATABASE") %>
|
50
|
+
host: <%= ENV.fetch("MYSQL_HOST") %>
|
51
|
+
username: <%= ENV.fetch("MYSQL_USERNAME") %>' > config/database.yml
|
52
|
+
|
53
|
+
bundle e rails g model shirt
|
54
|
+
|
55
|
+
bundle e rails g migration add_color_to_shirts color:string
|
56
|
+
|
57
|
+
# Test default configuration works as expected
|
58
|
+
bundle e rails db:migrate --trace
|
59
|
+
rails runner 'Shirt.columns.map(&:name).include?("color") || exit(1)'
|
60
|
+
|
61
|
+
# Now test custom command and replication setup
|
62
|
+
cp ../spec/bin/custom_config.rb config/initializers/alterity.rb
|
63
|
+
|
64
|
+
bundle e rails g migration add_color2_to_shirts color2:string
|
65
|
+
|
66
|
+
bundle e rails db:migrate --trace
|
67
|
+
|
68
|
+
ruby ../spec/bin/test_custom_config_result.rb
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
result = File.read("/tmp/custom_command_result.txt").downcase.strip
|
4
|
+
|
5
|
+
expected_result = %({:host=>"127.0.0.1", :port=>nil, :username=>"root", :database=>"alterity_test", :replicas_dsns_database=>"percona", :replicas_dsns_table=>"replicas_dsns", :replicas_dsns=>["h=host1,P=3306", "h=host2,P=3306"]}
|
6
|
+
shirts
|
7
|
+
"ADD \\`color2\\` VARCHAR(255)").downcase.strip
|
8
|
+
|
9
|
+
puts "Expected custom config result:"
|
10
|
+
puts expected_result
|
11
|
+
p expected_result.chars.map(&:hex)
|
12
|
+
|
13
|
+
puts "Custom config result:"
|
14
|
+
puts result
|
15
|
+
p result.chars.map(&:hex)
|
16
|
+
|
17
|
+
if result != expected_result
|
18
|
+
puts "=> mismatch"
|
19
|
+
exit(1)
|
20
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: alterity
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Maximin
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '6.1'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '6.1'
|
41
41
|
description: Execute your ActiveRecord migrations with Percona's pt-online-schema-change.
|
42
42
|
email:
|
43
43
|
- gems@chrismaximin.com
|
@@ -47,11 +47,14 @@ extra_rdoc_files: []
|
|
47
47
|
files:
|
48
48
|
- lib/alterity.rb
|
49
49
|
- lib/alterity/configuration.rb
|
50
|
+
- lib/alterity/default_configuration.rb
|
50
51
|
- lib/alterity/mysql_client_additions.rb
|
51
52
|
- lib/alterity/railtie.rb
|
52
53
|
- lib/alterity/version.rb
|
53
54
|
- spec/alterity_spec.rb
|
55
|
+
- spec/bin/custom_config.rb
|
54
56
|
- spec/bin/rails_app_migration_test.sh
|
57
|
+
- spec/bin/test_custom_config_result.rb
|
55
58
|
- spec/spec_helper.rb
|
56
59
|
homepage: https://github.com/gumroad/alterity
|
57
60
|
licenses:
|
@@ -81,5 +84,7 @@ specification_version: 4
|
|
81
84
|
summary: Execute your ActiveRecord migrations with Percona's pt-online-schema-change.
|
82
85
|
test_files:
|
83
86
|
- spec/alterity_spec.rb
|
87
|
+
- spec/bin/custom_config.rb
|
84
88
|
- spec/bin/rails_app_migration_test.sh
|
89
|
+
- spec/bin/test_custom_config_result.rb
|
85
90
|
- spec/spec_helper.rb
|