schema_migration_monitor 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use ruby-1.9.2-p290@schema_migration_monitor
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in schema_migration_monitor.gemspec
4
+ gemspec
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,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -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,3 @@
1
+ module SchemaMigrationMonitor
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,2 @@
1
+ require 'schema_migration_monitor/version'
2
+ require 'schema_migration_monitor/monitor'
@@ -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
@@ -0,0 +1,7 @@
1
+ Dir['./lib/**/*.rb'].map { |f| require f }
2
+
3
+ require 'mocha'
4
+
5
+ RSpec.configure do |config|
6
+ config.mock_with :mocha
7
+ end
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