percona_migrator 0.1.0.rc.4 → 0.1.0.rc.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9e5da0e5e83003f39f3fbfda94fd8ae258d79052
4
- data.tar.gz: 4ce4629ba354e7d4cd49345ef5298c33caef63e2
3
+ metadata.gz: e7301e478b66a555e4abe723cd9429914fba7820
4
+ data.tar.gz: fbf40c010ac9272f913b1e79285cb5f61fb11839
5
5
  SHA512:
6
- metadata.gz: 4e1956e97df24759066e4b9ded281074330720274e20a54d6ae07b9b6a64fd292555e2a1a87f7c7ba09752c6c9dc7a0a36016ea6de018de3d8d59211bd718496
7
- data.tar.gz: 11c8a7816627e264a7bd887e50c454145127519f79de24ff2433af3c77ea42a1326f773781e7748a363da053c3a6098374872a90206d2e5e3dbccb61a747f9db
6
+ metadata.gz: 39543206254ddc6f383446adca091ead90f3ac4a879dad0f7b246b8443d3bbeadc5eb95500fa26040fb8c28ef6182ad94e0620a1a4e8dd593f885f057555ed41
7
+ data.tar.gz: 011386f3f3e8866fb9db4c19c98f9e050c4899168bb5c0eb9d78ddd56451ad5eeb89caaa3973f7574f21038b89dbcda4f511353103c760f577007043e8f82af0
data/CHANGELOG.md CHANGED
@@ -6,13 +6,23 @@ Please follow the format in [Keep a Changelog](http://keepachangelog.com/)
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.1.0.rc.5] - 2016-03-29
10
+
11
+ ### Changed
12
+
13
+ - Raise a ActiveRecord::StatementInvalid on failed migration. It also provides
14
+ more detailed error message when possible such as pt-onlin-schema-change
15
+ being missing.
16
+
9
17
  ## [0.1.0.rc.4] - 2016-03-15
10
18
 
11
19
  ### Added
12
20
 
13
21
  - Support #drop_table
14
- - Support [Foreigner gem](https://github.com/matthuhiggins/foreigner) foreign
15
- keys in Rails 3 apps that use it.
22
+ - Support for foreing keys in db/schema.rb when using [Foreigner
23
+ gem](https://github.com/matthuhiggins/foreigner) in Rails 3 apps. This allows to
24
+ define foreign keys with #execute, but does not provide support for
25
+ #add_foreign_key yet.
16
26
 
17
27
  ## [0.1.0.rc.3] - 2016-03-10
18
28
 
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
+
5
+ gem "codeclimate-test-reporter", group: :test, require: nil
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # PerconaMigrator [![Build Status](https://travis-ci.org/redbooth/percona_migrator.svg?branch=master)](https://travis-ci.org/redbooth/percona_migrator)
1
+ # PerconaMigrator [![Build Status](https://travis-ci.org/redbooth/percona_migrator.svg?branch=master)](https://travis-ci.org/redbooth/percona_migrator) [![Code Climate](https://codeclimate.com/github/redbooth/percona_migrator/badges/gpa.svg)](https://codeclimate.com/github/redbooth/percona_migrator)
2
2
 
3
3
  Percona Migrator is a tool for running online and non-blocking
4
4
  DDL `ActiveRecord::Migrations` using `pt-online-schema-change` command-line tool of
data/Rakefile CHANGED
@@ -6,12 +6,12 @@ require './test_database'
6
6
 
7
7
  RSpec::Core::RakeTask.new(:spec)
8
8
 
9
- task :default => :spec
9
+ task default: :spec
10
10
 
11
11
  namespace :db do
12
12
  desc 'Create the test database'
13
13
  task :create do
14
14
  config = Configuration.new
15
- TestDatabase.new(config).create_test_database
15
+ TestDatabase.new(config).setup_test_database
16
16
  end
17
17
  end
@@ -83,7 +83,7 @@ module ActiveRecord
83
83
  def add_column(table_name, column_name, type, options = {})
84
84
  super
85
85
  command = cli_generator.generate(table_name, @sql)
86
- runner.execute(command)
86
+ log(@sql, nil) { runner.execute(command) }
87
87
  end
88
88
 
89
89
  # Removes the column(s) from the table definition
@@ -93,7 +93,7 @@ module ActiveRecord
93
93
  def remove_column(table_name, *column_names)
94
94
  super
95
95
  command = cli_generator.generate(table_name, @sql)
96
- runner.execute(command)
96
+ log(@sql, nil) { runner.execute(command) }
97
97
  end
98
98
 
99
99
  # Adds a new index to the table
@@ -106,7 +106,7 @@ module ActiveRecord
106
106
  execute "ADD #{index_type} INDEX #{quote_column_name(index_name)} (#{index_columns})#{index_options}"
107
107
 
108
108
  command = cli_generator.generate(table_name, @sql)
109
- runner.execute(command)
109
+ log(@sql, nil) { runner.execute(command) }
110
110
  end
111
111
 
112
112
  # Remove the given index from the table.
@@ -118,7 +118,7 @@ module ActiveRecord
118
118
  execute "DROP INDEX #{quote_column_name(index_name)}"
119
119
 
120
120
  command = cli_generator.generate(table_name, @sql)
121
- runner.execute(command)
121
+ log(@sql, nil) { runner.execute(command) }
122
122
  end
123
123
 
124
124
  # Records the SQL statement to be executed. This is used to then delegate
@@ -139,7 +139,7 @@ module ActiveRecord
139
139
  def percona_execute(sql, name)
140
140
  if alter_statement?(sql)
141
141
  command = cli_generator.parse_statement(sql)
142
- runner.execute(command)
142
+ log(sql, nil) { runner.execute(command) }
143
143
  else
144
144
  mysql_adapter.execute(sql, name)
145
145
  end
@@ -154,6 +154,9 @@ module ActiveRecord
154
154
  yield mysql_adapter.execute(sql, name)
155
155
  end
156
156
 
157
+ def error_number(exception)
158
+ end
159
+
157
160
  private
158
161
 
159
162
  attr_reader :mysql_adapter, :logger, :runner, :cli_generator
@@ -47,7 +47,7 @@ module PerconaMigrator
47
47
  end
48
48
 
49
49
  # Generates the percona command. Fills all the connection credentials from
50
- # the current AR connection, but that can amended via ENV-vars:
50
+ # the current AR connection, but that can be amended via ENV-vars:
51
51
  # PERCONA_DB_HOST, PERCONA_DB_USER, PERCONA_DB_PASSWORD, PERCONA_DB_NAME
52
52
  # Table name can't not be amended, it populates automatically from the
53
53
  # migration data
@@ -59,7 +59,7 @@ module PerconaMigrator
59
59
  alter_argument = AlterArgument.new(statement)
60
60
  dsn = DSN.new(database, table_name)
61
61
 
62
- "#{to_s} #{dsn} #{alter_argument}"
62
+ "#{self} #{dsn} #{alter_argument}"
63
63
  end
64
64
 
65
65
  # Generates the percona command for a raw MySQL statement. Fills all the
@@ -74,7 +74,7 @@ module PerconaMigrator
74
74
  alter_argument = AlterArgument.new(statement)
75
75
  dsn = DSN.new(database, alter_argument.table_name)
76
76
 
77
- "#{to_s} #{dsn} #{alter_argument}"
77
+ "#{self} #{dsn} #{alter_argument}"
78
78
  end
79
79
 
80
80
  private
@@ -1,23 +1,48 @@
1
1
  require 'open3'
2
2
 
3
3
  module PerconaMigrator
4
+ class Error < StandardError; end
5
+
6
+ # Used when for whatever reason we couldn't get the spawned process'
7
+ # status.
8
+ class NoStatusError < Error
9
+ def message
10
+ 'Status could not be retrieved'.freeze
11
+ end
12
+ end
13
+
14
+ # Used when the spawned process failed by receiving a signal.
15
+ # pt-online-schema-change returns "SIGSEGV (signal 11)" on failures.
16
+ class SignalError < Error
17
+ attr_reader :status
18
+
19
+ # Constructor
20
+ #
21
+ # @param status [Process::Status]
22
+ def initialize(status)
23
+ super
24
+ @status = status
25
+ end
26
+
27
+ def message
28
+ status.to_s
29
+ end
30
+ end
31
+
32
+ class CommandNotFoundError < Error
33
+ def message
34
+ 'Please install pt-online-schema-change. Check: https://www.percona.com/doc/percona-toolkit for further details'
35
+ end
36
+ end
4
37
 
5
38
  # It executes pt-online-schema-change commands in a new process and gets its
6
39
  # output and status
7
40
  class Runner
41
+ COMMAND_NOT_FOUND = 127
8
42
 
9
43
  NONE = "\e[0m"
10
44
  CYAN = "\e[38;5;86m"
11
45
  GREEN = "\e[32m"
12
- RED = "\e[31m"
13
-
14
- # Executes the given command printing the output to the logger
15
- #
16
- # @param command [String]
17
- # @param logger [IO]
18
- def self.execute(command, logger)
19
- new(command, logger).execute
20
- end
21
46
 
22
47
  # Constructor
23
48
  #
@@ -33,11 +58,7 @@ module PerconaMigrator
33
58
  # @return [Boolean]
34
59
  def execute(command)
35
60
  @command = command
36
-
37
- log_started
38
- run_command
39
- log_finished
40
-
61
+ logging { run_command }
41
62
  status
42
63
  end
43
64
 
@@ -45,6 +66,15 @@ module PerconaMigrator
45
66
 
46
67
  attr_reader :command, :logger, :status
47
68
 
69
+ # Logs the start and end of the execution
70
+ #
71
+ # @yield
72
+ def logging
73
+ log_started
74
+ yield
75
+ log_finished
76
+ end
77
+
48
78
  # TODO: log as a migration logger subitem
49
79
  #
50
80
  # Logs when the execution started
@@ -56,33 +86,24 @@ module PerconaMigrator
56
86
  #
57
87
  # @raise [Errno::ENOENT] if pt-online-schema-change can't be found
58
88
  def run_command
59
- Open3.popen2(command) do |_stdin, stdout, process|
60
- @status = process.value
61
- logger.info stdout.read
62
- end
63
-
64
- if status.nil?
65
- Kernel.warn("Error running '#{command}': status could not be retrieved")
89
+ message = nil
90
+ Open3.popen3(command) do |_stdin, stdout, stderr, waith_thr|
91
+ @status = waith_thr.value
92
+ message = stderr.read
93
+ logger.info(stdout.read)
66
94
  end
67
95
 
68
- if status && status.signaled?
69
- Kernel.warn("Error running '#{command}': #{status.to_s}")
70
- end
96
+ raise NoStatusError if status.nil?
97
+ raise SignalError.new(status) if status.signaled?
98
+ raise CommandNotFoundError if status.exitstatus == COMMAND_NOT_FOUND
71
99
 
72
- rescue Errno::ENOENT
73
- raise Errno::ENOENT, "Please install pt-online-schema-change. Check: https://www.percona.com/doc/percona-toolkit"
100
+ raise Error, message unless status.success?
74
101
  end
75
102
 
76
- # Logs the status of the execution once it's finished
103
+ # Logs the status of the execution once it's finished. At this point we
104
+ # know it's a success
77
105
  def log_finished
78
- return unless status
79
-
80
- value = status.exitstatus
81
- return unless value
82
-
83
- message = value.zero? ? "#{GREEN}Done!#{NONE}" : "#{RED}Failed!#{NONE}"
84
-
85
- logger.info("\n#{message}")
106
+ logger.info("\n#{GREEN}Done!#{NONE}")
86
107
  end
87
108
  end
88
109
  end
@@ -1,3 +1,3 @@
1
1
  module PerconaMigrator
2
- VERSION = '0.1.0.rc.4'.freeze
2
+ VERSION = '0.1.0.rc.5'.freeze
3
3
  end
data/test_database.rb CHANGED
@@ -1,17 +1,33 @@
1
+ # Setups the test database with the schema_migrations table that ActiveRecord
2
+ # requires for the migrations, plus a table for the Comment model used throught
3
+ # the tests.
4
+ #
1
5
  class TestDatabase
6
+
7
+ # Constructor
8
+ #
9
+ # @param config [Hash]
2
10
  def initialize(config)
3
11
  @config = config
4
12
  end
5
13
 
6
- # Creates the percona_migrator_test database and comments table in it
7
- def create_test_database
8
- %x(#{mysql_command} "DROP DATABASE IF EXISTS percona_migrator_test; CREATE DATABASE percona_migrator_test DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_unicode_ci")
9
- %x(#{mysql_command} "USE percona_migrator_test; DROP TABLE IF EXISTS comments; CREATE TABLE comments (id int(12) NOT NULL AUTO_INCREMENT, PRIMARY KEY (id)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;")
14
+ # Creates the test database, the schema_migrations and the comments tables.
15
+ # It drops any of them if they already exist
16
+ def setup
17
+ setup_test_database
18
+ drop_and_create_schema_migrations_table
19
+ end
20
+
21
+ # Creates the percona_migrator_test database and the comments table in it.
22
+ # Before, it drops both if they already exist
23
+ def setup_test_database
24
+ drop_and_create_test_database
25
+ drop_and_create_comments_table
10
26
  end
11
27
 
12
28
  # Creates the ActiveRecord's schema_migrations table required for
13
- # migrations to work
14
- def create_schema_migrations_table
29
+ # migrations to work. Before, it drops the table if it already exists
30
+ def drop_and_create_schema_migrations_table
15
31
  %x(#{mysql_command} "USE percona_migrator_test; DROP TABLE IF EXISTS schema_migrations; CREATE TABLE schema_migrations ( version varchar(255) COLLATE utf8_unicode_ci NOT NULL, UNIQUE KEY unique_schema_migrations (version)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci")
16
32
  end
17
33
 
@@ -19,6 +35,16 @@ class TestDatabase
19
35
 
20
36
  attr_reader :config
21
37
 
38
+ def drop_and_create_test_database
39
+ %x(#{mysql_command} "DROP DATABASE IF EXISTS percona_migrator_test; CREATE DATABASE percona_migrator_test DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_unicode_ci;")
40
+ end
41
+
42
+ def drop_and_create_comments_table
43
+ %x(#{mysql_command} "USE percona_migrator_test; DROP TABLE IF EXISTS comments; CREATE TABLE comments ( id int(12) NOT NULL AUTO_INCREMENT, PRIMARY KEY (id)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;")
44
+ end
45
+
46
+ # Returns the command to run the mysql client. It uses the crendentials from
47
+ # the provided config
22
48
  def mysql_command
23
49
  "mysql --user=#{config['username']} --password=#{config['password']} -e"
24
50
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: percona_migrator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.rc.4
4
+ version: 0.1.0.rc.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ilya Zayats
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2016-03-15 00:00:00.000000000 Z
13
+ date: 2016-03-29 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rails