schema_migration_monitor 0.0.1
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.
- data/.gitignore +17 -0
- data/.rvmrc +1 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +42 -0
- data/Rakefile +2 -0
- data/lib/schema_migration_monitor/migration_path_service.rb +25 -0
- data/lib/schema_migration_monitor/monitor.rb +83 -0
- data/lib/schema_migration_monitor/version.rb +3 -0
- data/lib/schema_migration_monitor.rb +2 -0
- data/schema_migration_monitor.gemspec +23 -0
- data/spec/migration_path_service_spec.rb +52 -0
- data/spec/monitor_spec.rb +54 -0
- data/spec/spec_helper.rb +7 -0
- metadata +108 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use ruby-1.9.2-p290@schema_migration_monitor
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Vita Rara (dba Enable Labs)
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# SchemaMigrationMonitor
|
2
|
+
|
3
|
+
This gem is used to warn developers of pending schema migrations. Each time your development or test environment is loaded, a migration check will occur. If a pending migration is found, the following example output will be in sent to your console output:
|
4
|
+
|
5
|
+
|
6
|
+
********************************************************
|
7
|
+
** The following migration(s) need to be run: **
|
8
|
+
** - ./db/migrate/20120627151108_create_examples.rb **
|
9
|
+
********************************************************
|
10
|
+
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
|
14
|
+
Add this line to your application's Gemfile:
|
15
|
+
|
16
|
+
gem 'schema_migration_monitor', :group => [:development, :test]
|
17
|
+
|
18
|
+
And then execute:
|
19
|
+
|
20
|
+
$ bundle
|
21
|
+
|
22
|
+
Or install it yourself as:
|
23
|
+
|
24
|
+
$ gem install schema_migration_monitor
|
25
|
+
|
26
|
+
## Usage
|
27
|
+
|
28
|
+
Require the gem!
|
29
|
+
|
30
|
+
## Custom Migration Path
|
31
|
+
|
32
|
+
The gem uses the path './db/migrate' by default to find your migrations. If your project is using a custom path for migrations you must put a '.schema_migration_monitor.yml' in your project's root path. A sample '.schema_migration_monitor.yml' file would be written as follows:
|
33
|
+
|
34
|
+
migration_path: './custom_migration_path'
|
35
|
+
|
36
|
+
## Contributing
|
37
|
+
|
38
|
+
1. Fork it
|
39
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
40
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
41
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
42
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
class MigrationPathService
|
4
|
+
|
5
|
+
DEFAULT_MIGRATION_PATH = './db/migrate'
|
6
|
+
USER_CONFIG_PATH = '.schema_migration_monitor.yml'
|
7
|
+
|
8
|
+
class MigrationPathNotFoundError < StandardError; end
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def execute
|
12
|
+
return get_user_config_path if Pathname.new(USER_CONFIG_PATH).exist?
|
13
|
+
return DEFAULT_MIGRATION_PATH if Pathname.new(DEFAULT_MIGRATION_PATH).exist?
|
14
|
+
raise MigrationPathNotFoundError
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_user_config_path
|
18
|
+
YAML::load(user_config_file)['migration_path']
|
19
|
+
end
|
20
|
+
|
21
|
+
def user_config_file
|
22
|
+
File.open(USER_CONFIG_PATH)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require File.dirname(__FILE__) + '/migration_path_service'
|
3
|
+
|
4
|
+
module ActiveRecord
|
5
|
+
module ConnectionAdapters
|
6
|
+
class ConnectionHandler
|
7
|
+
|
8
|
+
alias_method :establish_connection_without_monitor, :establish_connection
|
9
|
+
|
10
|
+
def establish_connection(name, spec)
|
11
|
+
result = establish_connection_without_monitor(name,spec)
|
12
|
+
monitor_migrations
|
13
|
+
result
|
14
|
+
end
|
15
|
+
|
16
|
+
def monitor_migrations
|
17
|
+
SchemaMigrationMonitor::Monitor.new.execute
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module SchemaMigrationMonitor
|
24
|
+
class Monitor
|
25
|
+
|
26
|
+
def initialize(output_stream = $stdout)
|
27
|
+
@migration_path = MigrationPathService.execute
|
28
|
+
@output_stream = output_stream
|
29
|
+
end
|
30
|
+
|
31
|
+
def execute
|
32
|
+
@pending_migrations = get_pending_migrations
|
33
|
+
return if @pending_migrations.empty?
|
34
|
+
output_report
|
35
|
+
end
|
36
|
+
|
37
|
+
def output_report
|
38
|
+
write_boxed_output(report_text.split("\n"))
|
39
|
+
end
|
40
|
+
|
41
|
+
def report_text
|
42
|
+
res = "The following migration(s) need to be run:"
|
43
|
+
res << @pending_migrations.map { |migration| "\n - #{migration.filename}" }.join
|
44
|
+
end
|
45
|
+
|
46
|
+
def write_boxed_output(text_lines)
|
47
|
+
longest_line = get_longest_line(text_lines)
|
48
|
+
|
49
|
+
wrap_output_in_red do
|
50
|
+
@output_stream.write("*" * (longest_line + 6) + "\n")
|
51
|
+
|
52
|
+
text_lines.each do |line|
|
53
|
+
@output_stream.write "** #{line}#{ " " * (longest_line - line.to_s.length) } **\n"
|
54
|
+
end
|
55
|
+
|
56
|
+
@output_stream.write("*" * (longest_line + 6) + "\n")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def wrap_output_in_red
|
61
|
+
@output_stream.write("\e[1;31m\n")
|
62
|
+
yield if block_given?
|
63
|
+
@output_stream.write("\n\e[0m")
|
64
|
+
end
|
65
|
+
|
66
|
+
def get_longest_line(text_lines)
|
67
|
+
text_lines.inject(0) do |memo, arg|
|
68
|
+
line_length = arg.to_s.length
|
69
|
+
memo = line_length if line_length > memo
|
70
|
+
memo
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def get_pending_migrations
|
75
|
+
migrator.pending_migrations
|
76
|
+
end
|
77
|
+
|
78
|
+
def migrator
|
79
|
+
@migrator ||= ActiveRecord::Migrator.new(:up, @migration_path)
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/schema_migration_monitor/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Enable Labs"]
|
6
|
+
gem.email = ["info@enablelabs.com"]
|
7
|
+
gem.description = %q{Make sure the test environment schema is up to date.}
|
8
|
+
gem.summary = %q{Make sure the test environment schema is up to date.}
|
9
|
+
gem.homepage = ""
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "schema_migration_monitor"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = SchemaMigrationMonitor::VERSION
|
17
|
+
|
18
|
+
gem.add_development_dependency "rspec"
|
19
|
+
gem.add_development_dependency "mocha"
|
20
|
+
gem.add_development_dependency 'sqlite3'
|
21
|
+
|
22
|
+
gem.add_dependency "activerecord"
|
23
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
describe MigrationPathService do
|
5
|
+
describe ".execute" do
|
6
|
+
describe "when no .schema_migration_monitor config exists" do
|
7
|
+
before(:each) do
|
8
|
+
Pathname.expects(:new).with(MigrationPathService::USER_CONFIG_PATH).returns( mock(exist?:false) )
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should verify a ./db/migrate directory exists" do
|
12
|
+
Pathname.expects(:new).with('./db/migrate').returns( mock(exist?:true) )
|
13
|
+
MigrationPathService.execute
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "when a ./db/migrate directory exists" do
|
17
|
+
it "should return the string './db/migrate'" do
|
18
|
+
Pathname.expects(:new).with('./db/migrate').returns( mock(exist?:true) )
|
19
|
+
MigrationPathService.execute.should == './db/migrate'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "when a ./db/migrate directory does not exist" do
|
24
|
+
it "should raise an exception" do
|
25
|
+
Pathname.expects(:new).with('./db/migrate').returns( mock(exist?:false) )
|
26
|
+
|
27
|
+
expect do
|
28
|
+
MigrationPathService.execute
|
29
|
+
end.should raise_error(MigrationPathService::MigrationPathNotFoundError)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "when .schema_migration_monitor config exists" do
|
35
|
+
let(:user_config_file_contents) do
|
36
|
+
contents=<<-EOF
|
37
|
+
migration_path: ./custom/migrate
|
38
|
+
EOF
|
39
|
+
end
|
40
|
+
|
41
|
+
before(:each) do
|
42
|
+
Pathname.expects(:new).with(MigrationPathService::USER_CONFIG_PATH).returns( mock(exist?:true) )
|
43
|
+
MigrationPathService.expects(:user_config_file).returns(user_config_file_contents)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should return the path contained in the .schema_migration_monitor config" do
|
47
|
+
MigrationPathService.execute.should == './custom/migrate'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SchemaMigrationMonitor::Monitor do
|
4
|
+
before(:each) do
|
5
|
+
MigrationPathService.stubs(:execute).returns(MigrationPathService::DEFAULT_MIGRATION_PATH)
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "when ActiveRecord establishes a connection" do
|
9
|
+
it "should also execute the schema migration monitor" do
|
10
|
+
SchemaMigrationMonitor::Monitor.expects(:new).returns(mock(execute: nil))
|
11
|
+
ActiveRecord::Base.establish_connection({:adapter => 'sqlite3', database: ":memory:"})
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "when there are no pending migrations" do
|
16
|
+
let!(:mock_migrator) do
|
17
|
+
mock('migrator').tap do |migrator|
|
18
|
+
migrator.expects(:pending_migrations).returns([])
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
before(:each) do
|
23
|
+
SchemaMigrationMonitor::Monitor.any_instance.expects(:migrator).returns(mock_migrator)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should do nothing" do
|
27
|
+
output_stream = mock('output_stream')
|
28
|
+
output_stream.expects(:write).never
|
29
|
+
SchemaMigrationMonitor::Monitor.new(output_stream).execute
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "when there are pending migrations" do
|
34
|
+
let(:migrations) { [mock('migration1', filename:'20120101000000_fake_migration')] }
|
35
|
+
|
36
|
+
let!(:mock_migrator) do
|
37
|
+
mock('migrator').tap do |migrator|
|
38
|
+
migrator.expects(:pending_migrations).returns(migrations)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
before(:each) do
|
43
|
+
SchemaMigrationMonitor::Monitor.any_instance.expects(:migrator).returns(mock_migrator)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should print a message to stdout" do
|
47
|
+
read_io, write_io = IO.pipe
|
48
|
+
SchemaMigrationMonitor::Monitor.new(write_io).execute
|
49
|
+
write_io.close_write
|
50
|
+
read_io.read.should match(/The following migration\(s\) need to be run/)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: schema_migration_monitor
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Enable Labs
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-06-27 00:00:00.000000000 -04:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rspec
|
17
|
+
requirement: &2165800900 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
23
|
+
type: :development
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *2165800900
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: mocha
|
28
|
+
requirement: &2165800480 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *2165800480
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: sqlite3
|
39
|
+
requirement: &2165800060 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ! '>='
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
45
|
+
type: :development
|
46
|
+
prerelease: false
|
47
|
+
version_requirements: *2165800060
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: activerecord
|
50
|
+
requirement: &2165799640 !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ! '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
type: :runtime
|
57
|
+
prerelease: false
|
58
|
+
version_requirements: *2165799640
|
59
|
+
description: Make sure the test environment schema is up to date.
|
60
|
+
email:
|
61
|
+
- info@enablelabs.com
|
62
|
+
executables: []
|
63
|
+
extensions: []
|
64
|
+
extra_rdoc_files: []
|
65
|
+
files:
|
66
|
+
- .gitignore
|
67
|
+
- .rvmrc
|
68
|
+
- Gemfile
|
69
|
+
- LICENSE
|
70
|
+
- README.md
|
71
|
+
- Rakefile
|
72
|
+
- lib/schema_migration_monitor.rb
|
73
|
+
- lib/schema_migration_monitor/migration_path_service.rb
|
74
|
+
- lib/schema_migration_monitor/monitor.rb
|
75
|
+
- lib/schema_migration_monitor/version.rb
|
76
|
+
- schema_migration_monitor.gemspec
|
77
|
+
- spec/migration_path_service_spec.rb
|
78
|
+
- spec/monitor_spec.rb
|
79
|
+
- spec/spec_helper.rb
|
80
|
+
has_rdoc: true
|
81
|
+
homepage: ''
|
82
|
+
licenses: []
|
83
|
+
post_install_message:
|
84
|
+
rdoc_options: []
|
85
|
+
require_paths:
|
86
|
+
- lib
|
87
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
88
|
+
none: false
|
89
|
+
requirements:
|
90
|
+
- - ! '>='
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '0'
|
93
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ! '>='
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
requirements: []
|
100
|
+
rubyforge_project:
|
101
|
+
rubygems_version: 1.6.2
|
102
|
+
signing_key:
|
103
|
+
specification_version: 3
|
104
|
+
summary: Make sure the test environment schema is up to date.
|
105
|
+
test_files:
|
106
|
+
- spec/migration_path_service_spec.rb
|
107
|
+
- spec/monitor_spec.rb
|
108
|
+
- spec/spec_helper.rb
|