rails-infrastructure 0.1.0
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 +7 -0
- data/.gitignore +18 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.rdoc +80 -0
- data/Rakefile +7 -0
- data/examples/infrastructure/databases.yml +29 -0
- data/examples/infrastructure/environment.yml +2 -0
- data/examples/infrastructure/server.yml +9 -0
- data/examples/infrastructure/servers/unicorn.rb +69 -0
- data/examples/infrastructure/servers/unicorn.yml.erb +13 -0
- data/examples/infrastructure/version.yml +2 -0
- data/examples/infrastructure.yml +11 -0
- data/lib/infrastructure/configurable.rb +51 -0
- data/lib/infrastructure/configuration.rb +93 -0
- data/lib/infrastructure/constants.rb +5 -0
- data/lib/infrastructure/databases.rb +117 -0
- data/lib/infrastructure/environment.rb +16 -0
- data/lib/infrastructure/path.rb +7 -0
- data/lib/infrastructure/railtie.rb +68 -0
- data/lib/infrastructure/server.rb +7 -0
- data/lib/infrastructure/version.rb +23 -0
- data/lib/infrastructure.rb +25 -0
- data/lib/rails-infrastructure.rb +2 -0
- data/lib/tasks/databases.rake +148 -0
- data/lib/tasks/environment.rake +19 -0
- data/lib/tasks/server.rake +73 -0
- data/lib/tasks/version.rake +23 -0
- data/rails-infrastructure.gemspec +28 -0
- data/test/infrastructure/configurable_test.rb +94 -0
- data/test/infrastructure/configuration_test.yml.erb +5 -0
- data/test/infrastructure/database_test.rb +108 -0
- data/test/infrastructure/environment_test.rb +23 -0
- data/test/infrastructure/paths_test.rb +9 -0
- data/test/infrastructure/server_test.rb +9 -0
- data/test/infrastructure/version_test.rb +23 -0
- data/test/infrastructure_test.rb +26 -0
- data/test/test_helper.rb +2 -0
- metadata +163 -0
@@ -0,0 +1,117 @@
|
|
1
|
+
class Infrastructure
|
2
|
+
class Databases
|
3
|
+
|
4
|
+
include Configurable
|
5
|
+
|
6
|
+
attr_reader :orm, :environment
|
7
|
+
attr_reader :global_defaults, :system
|
8
|
+
|
9
|
+
def initialize(orm, environment)
|
10
|
+
@orm = orm
|
11
|
+
@environment = environment.to_sym
|
12
|
+
@global_defaults = {}
|
13
|
+
@environment_defaults = {}
|
14
|
+
@system = {}
|
15
|
+
callback :after_configure, -> { merge_defaults }
|
16
|
+
callback :after_assignment, -> (key, value) { merge_defaults }
|
17
|
+
end
|
18
|
+
|
19
|
+
def merge_defaults
|
20
|
+
@global_defaults = @global_defaults.merge(configuration.fetch(:defaults) || {})
|
21
|
+
configuration.delete :defaults
|
22
|
+
@system = @system.merge(configuration.fetch(:system) || {}).merge @global_defaults
|
23
|
+
configuration.delete :system
|
24
|
+
configuration.each do |environment, configs|
|
25
|
+
@environment_defaults[environment] ||= Hash.new
|
26
|
+
@environment_defaults[environment] = @environment_defaults[environment].merge(configs.fetch(:defaults) || {})
|
27
|
+
configs.delete :defaults
|
28
|
+
configs.each do |id, config|
|
29
|
+
config.assign :database, "#{environment}_#{id}" unless config.fetch :database
|
30
|
+
config.assign :id, id.to_s unless config.fetch(:id) == id.to_s
|
31
|
+
@environment_defaults[environment].each { |k,v| config.assign k, v unless config.fetch k }
|
32
|
+
@global_defaults.each { |k,v| config.assign k, v unless config.fetch k }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def available?(id)
|
38
|
+
available.include? database(id)
|
39
|
+
end
|
40
|
+
|
41
|
+
def available
|
42
|
+
connection.execute("SELECT datname FROM pg_database").map { |result| result['datname'] }
|
43
|
+
end
|
44
|
+
|
45
|
+
def connection
|
46
|
+
orm.connection
|
47
|
+
end
|
48
|
+
|
49
|
+
def tables
|
50
|
+
connection.tables
|
51
|
+
end
|
52
|
+
|
53
|
+
def environment_configs(environment = environment)
|
54
|
+
fetch(environment) || raise(ArgumentError, "database configurations for environment #{environment} are not configured")
|
55
|
+
end
|
56
|
+
alias_method :configs, :environment_configs
|
57
|
+
|
58
|
+
def environment_database(id)
|
59
|
+
config(id)[:database]
|
60
|
+
end
|
61
|
+
alias_method :database, :environment_database
|
62
|
+
|
63
|
+
def environment_defaults(environment = environment)
|
64
|
+
@environment_defaults[environment] ||= Hash.new
|
65
|
+
end
|
66
|
+
alias_method :defaults, :environment_defaults
|
67
|
+
|
68
|
+
def environment_config(id)
|
69
|
+
if id.is_a?(String) || id.is_a?(Symbol)
|
70
|
+
id = id.to_sym
|
71
|
+
if config = configs.fetch(id)
|
72
|
+
return config.to_h
|
73
|
+
end
|
74
|
+
if id.to_s == defaults[:id]
|
75
|
+
if config = configs.fetch(defaults[:id])
|
76
|
+
return config.to_h
|
77
|
+
else
|
78
|
+
raise ArgumentError, "default database #{defaults[:id]} in environment #{environment} is not configured"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
return system if id == :system
|
82
|
+
elsif id.is_a? Hash
|
83
|
+
return id
|
84
|
+
end
|
85
|
+
raise ArgumentError, "database configuration for #{id} in environment #{environment} is not configured"
|
86
|
+
end
|
87
|
+
alias_method :config, :environment_config
|
88
|
+
|
89
|
+
def drop(id)
|
90
|
+
connection.drop_database database(id)
|
91
|
+
end
|
92
|
+
|
93
|
+
def create(id)
|
94
|
+
connection.create_database database(id)
|
95
|
+
end
|
96
|
+
|
97
|
+
def connect(id)
|
98
|
+
orm.establish_connection config(id)
|
99
|
+
end
|
100
|
+
|
101
|
+
def connect!(id)
|
102
|
+
begin
|
103
|
+
connect id
|
104
|
+
rescue StandardError
|
105
|
+
connect system
|
106
|
+
create id
|
107
|
+
connect id
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def databases(environment = environment)
|
112
|
+
configs(environment).map { |id, configs| configs[:database] }.compact.uniq.sort
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class Infrastructure
|
2
|
+
class Environment
|
3
|
+
|
4
|
+
include Configurable
|
5
|
+
|
6
|
+
%w( production development test ).each do |environment|
|
7
|
+
define_method "#{environment}?", -> { to_s == environment }
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_s
|
11
|
+
configuration.fetch(:environment).to_s
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
@@ -0,0 +1,68 @@
|
|
1
|
+
unless defined? ::Inf
|
2
|
+
::Inf = Infrastructure.new
|
3
|
+
end
|
4
|
+
|
5
|
+
class Infrastructure
|
6
|
+
class Railtie < Rails::Railtie
|
7
|
+
|
8
|
+
config.before_configuration do |app|
|
9
|
+
|
10
|
+
Inf.build :path, Path
|
11
|
+
Inf.path.assign :rails, Hash.new
|
12
|
+
Inf.path.rails.configure do
|
13
|
+
assign :root, Dir.pwd
|
14
|
+
Dir.glob("#{root}/*").select { |f| File.directory? f }.each do |dir|
|
15
|
+
dir = File.basename(dir)
|
16
|
+
assign "#{dir}_dir", root + "/#{dir}"
|
17
|
+
Dir.glob("#{root}/#{dir}/*").select { |f| File.directory? f }.each do |sub_dir|
|
18
|
+
sub_dir = File.basename(sub_dir)
|
19
|
+
assign "#{dir}_#{sub_dir}_dir", root + "/#{dir}/#{sub_dir}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
Dir.glob("#{root}/config/infrastructure/*").select { |f| File.directory? f }.each do |dir|
|
23
|
+
dir = File.basename(dir)
|
24
|
+
assign "infrastructure_#{dir}_dir", root + "/config/infrastructure/#{dir}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
Inf.load_config_if_exists Inf.path.rails.config_dir + '/infrastructure.yml'
|
29
|
+
Inf.load_config_if_exists Inf.path.rails.config_dir + '/infrastructure.yml.erb'
|
30
|
+
|
31
|
+
Inf.build :environment, Environment
|
32
|
+
Inf.environment.load_config_if_exists Inf.path.rails.config_infrastructure_dir + '/environment.yml' do
|
33
|
+
ENV['RAILS_ENV'] = Inf.environment.to_s
|
34
|
+
Rails.env = Inf.environment.to_s
|
35
|
+
rake_tasks { load 'tasks/environment.rake' }
|
36
|
+
end
|
37
|
+
|
38
|
+
Inf.build :version, Version
|
39
|
+
Inf.version.load_config_if_exists Inf.path.rails.config_infrastructure_dir + '/version.yml' do
|
40
|
+
rake_tasks { load 'tasks/version.rake' }
|
41
|
+
end
|
42
|
+
|
43
|
+
Inf.build :server, Server
|
44
|
+
Inf.server.load_config_if_exists Inf.path.rails.config_infrastructure_dir + '/server.yml' do
|
45
|
+
rake_tasks { load 'tasks/server.rake' }
|
46
|
+
Inf.server.servers.each do |server|
|
47
|
+
Inf.server.assign server, Hash.new
|
48
|
+
Inf.server.fetch(server).assign Inf.server.fetch(:defaults).to_h
|
49
|
+
%w( .yml .yml.erb ).each do |extension|
|
50
|
+
Inf.server.fetch(server).load_config_if_exists Inf.path.rails.infrastructure_servers_dir + "/#{server}" + extension
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
config.before_initialize do
|
58
|
+
Inf.build :databases, Databases, ActiveRecord::Base, Rails.env
|
59
|
+
Inf.databases.load_config_if_exists Inf.path.rails.config_infrastructure_dir + '/databases.yml' do
|
60
|
+
ENV['DATABASE_URL'] = Inf.databases.environment_defaults[:id]
|
61
|
+
Rails::Application::Configuration.send(:define_method, :database_configuration) { Inf.databases.environment_configs }
|
62
|
+
ActiveRecord::Migration.verbose = false
|
63
|
+
rake_tasks { load 'tasks/databases.rake' }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class Infrastructure
|
2
|
+
|
3
|
+
class Version
|
4
|
+
|
5
|
+
include Configurable
|
6
|
+
|
7
|
+
def update_version(i, value = nil)
|
8
|
+
array_version = configuration.version.split('.')
|
9
|
+
array_version[i] = value || (array_version[i] || 0).to_i + 1
|
10
|
+
assign :version, array_version.join('.')
|
11
|
+
end
|
12
|
+
|
13
|
+
%w( major minor tiny ).each_with_index do |version, index|
|
14
|
+
define_method "bump_#{version}", -> { update_version index }
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
version.to_s
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
require 'erb'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
require 'colored'
|
6
|
+
|
7
|
+
require 'infrastructure/constants'
|
8
|
+
require 'infrastructure/configurable'
|
9
|
+
require 'infrastructure/configuration'
|
10
|
+
require 'infrastructure/environment'
|
11
|
+
require 'infrastructure/version'
|
12
|
+
require 'infrastructure/path'
|
13
|
+
require 'infrastructure/databases'
|
14
|
+
require 'infrastructure/server'
|
15
|
+
|
16
|
+
class Infrastructure
|
17
|
+
|
18
|
+
include Configurable
|
19
|
+
|
20
|
+
def build(key, model, *params)
|
21
|
+
model = model.constantize if model.is_a? String
|
22
|
+
assign key, model.new(*params)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
def forced?(params = {})
|
2
|
+
@forced = true if params[:force] == 'force'
|
3
|
+
@forced == true
|
4
|
+
end
|
5
|
+
|
6
|
+
def exit_if_production(params = {})
|
7
|
+
if Rails.env.production? && ! forced?(params)
|
8
|
+
puts 'This task must be forced in production environment ('.yellow + 'rake <task>[force]'.red + ')'.yellow
|
9
|
+
exit!
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module Rake
|
14
|
+
class Task
|
15
|
+
def self.reinvoke(*params, &block)
|
16
|
+
invoke(*params, &block)
|
17
|
+
reenable()
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
namespace :database do
|
23
|
+
|
24
|
+
desc "Create database if it does not exist"
|
25
|
+
task :create, :id do |name, params|
|
26
|
+
puts 'Creating: ' + params[:id].to_s.green
|
27
|
+
Inf.databases.connect :super
|
28
|
+
Inf.databases.create params[:id] if ! Inf.databases.available? params[:id]
|
29
|
+
end
|
30
|
+
|
31
|
+
desc "Drop database if exists"
|
32
|
+
task :drop, :id, :force do |name, params|
|
33
|
+
exit_if_production params
|
34
|
+
puts 'Dropping: ' + params[:id].to_s.green
|
35
|
+
Inf.databases.connect :super
|
36
|
+
Inf.databases.drop params[:id] if Inf.databases.available? params[:id]
|
37
|
+
end
|
38
|
+
|
39
|
+
desc "Migrate database"
|
40
|
+
task :migrate, :id, :version do |name, params|
|
41
|
+
puts 'Migrating: ' + params[:id].to_s.green
|
42
|
+
Inf.databases.connect params[:id]
|
43
|
+
ActiveRecord::Base.logger.level = Logger::INFO
|
44
|
+
current_version = ActiveRecord::Migrator.current_version
|
45
|
+
target_version = (params[:version] || ActiveRecord::Migrator.last_version).to_i
|
46
|
+
ActiveRecord::Migrator.migrate ActiveRecord::Migrator.migrations_paths, target_version
|
47
|
+
ActiveRecord::Migrator.migrations(ActiveRecord::Migrator.migrations_paths).each do |migration|
|
48
|
+
if target_version < current_version
|
49
|
+
puts "Rollbacked: - #{migration.version} - #{migration.name.green} - #{migration.filename}" if migration.version >= target_version && migration.version < current_version
|
50
|
+
else
|
51
|
+
puts "Migrated: - #{migration.version} - #{migration.name.green} - #{migration.filename}" if migration.version > current_version && migration.version <= target_version
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
desc "Rollback database"
|
57
|
+
task :rollback, :id, :version do |name, params|
|
58
|
+
puts 'Rollbacking: ' + params[:id].to_s.green
|
59
|
+
Inf.databases.connect params[:id]
|
60
|
+
ActiveRecord::Base.logger.level = Logger::INFO
|
61
|
+
current_version = ActiveRecord::Migrator.current_version
|
62
|
+
all_versions = ActiveRecord::Migrator.get_all_versions
|
63
|
+
previous_index = all_versions.index(current_version) - 1
|
64
|
+
previous_index = 0 if previous_index < 0
|
65
|
+
previous_version = all_versions[previous_index]
|
66
|
+
target_version = (params[:version] || previous_version).to_i
|
67
|
+
ActiveRecord::Migrator.migrate ActiveRecord::Migrator.migrations_paths, target_version
|
68
|
+
ActiveRecord::Migrator.migrations(ActiveRecord::Migrator.migrations_paths).each do |migration|
|
69
|
+
if target_version < current_version
|
70
|
+
puts "Rollbacked: - #{migration.version} - #{migration.name.green} - #{migration.filename}" if migration.version >= target_version && migration.version < current_version
|
71
|
+
else
|
72
|
+
puts "Migrated: - #{migration.version} - #{migration.name.green} - #{migration.filename}" if migration.version > current_version && migration.version <= target_version
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
desc "Seed database"
|
78
|
+
task :seed, :id do |name, params|
|
79
|
+
exit_if_production params
|
80
|
+
puts 'Seeding: ' + params[:id].to_s.green
|
81
|
+
Inf.databases.connect params[:id]
|
82
|
+
Rake::Task['database:migrate'].reinvoke params[:id]
|
83
|
+
load Inf.path.rails.db_dir + 'seeds.rb'
|
84
|
+
end
|
85
|
+
|
86
|
+
desc "Drop, create, then migrate database"
|
87
|
+
task :reset, :id, :force do |name, params|
|
88
|
+
exit_if_production params
|
89
|
+
Rake::Task['database:drop'].reinvoke params[:id]
|
90
|
+
Rake::Task['database:create'].reinvoke params[:id]
|
91
|
+
Rake::Task['database:migrate'].reinvoke params[:id]
|
92
|
+
end
|
93
|
+
|
94
|
+
namespace :reset do
|
95
|
+
desc "Reset then seed database"
|
96
|
+
task :seed, :force do |name, params|
|
97
|
+
exit_if_production params
|
98
|
+
Rake::Task['databases:reset'].reinvoke params[:id], params
|
99
|
+
Rake::Task['databases:seed'].reinvoke params[:id]
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
namespace :databases do
|
106
|
+
|
107
|
+
desc "Create all databases that dont exist"
|
108
|
+
task :create do
|
109
|
+
Inf.databases.configs.each { |id, config| Rake::Task['database:create'].reinvoke id }
|
110
|
+
end
|
111
|
+
|
112
|
+
desc "Drop all databases that exist"
|
113
|
+
task :drop, :force do |name, params|
|
114
|
+
exit_if_production params
|
115
|
+
Inf.databases.configs.each { |id, config| Rake::Task['database:drop'].reinvoke id }
|
116
|
+
end
|
117
|
+
|
118
|
+
desc "Migrate all databases"
|
119
|
+
task :migrate, :version do |name, params|
|
120
|
+
Inf.databases.configs.each { |id, config| Rake::Task['database:migrate'].reinvoke id, params[:version] }
|
121
|
+
end
|
122
|
+
|
123
|
+
desc "Rollback all databases"
|
124
|
+
task :rollback, :version do |name, params|
|
125
|
+
Inf.databases.configs.each { |id, config| Rake::Task['database:rollback'].reinvoke id }
|
126
|
+
end
|
127
|
+
|
128
|
+
desc "Drop, create, migrate all databases"
|
129
|
+
task :reset, :force do |name, params|
|
130
|
+
exit_if_production params
|
131
|
+
Inf.databases.configs.each { |id, config| Rake::Task['database:reset'].reinvoke id }
|
132
|
+
end
|
133
|
+
|
134
|
+
desc "Seed all databases"
|
135
|
+
task :seed, :force do |name, params|
|
136
|
+
exit_if_production params
|
137
|
+
Inf.databases.configs.each { |id, config| Rake::Task['database:seed'].reinvoke id }
|
138
|
+
end
|
139
|
+
|
140
|
+
namespace :reset do
|
141
|
+
desc "Reset then seed all databases"
|
142
|
+
task :seed, :force do |name, params|
|
143
|
+
exit_if_production params
|
144
|
+
Inf.databases.configs.each { |id, config| Rake::Task['database:seed'].reinvoke id, params[:force] }
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
namespace :environment do
|
2
|
+
|
3
|
+
desc 'display current environment'
|
4
|
+
task :current do
|
5
|
+
puts 'Environment: ' + Inf.environment.to_s.green
|
6
|
+
end
|
7
|
+
|
8
|
+
def set_environment_and_save(environment)
|
9
|
+
Inf.environment.assign :environment, environment
|
10
|
+
Inf.environment.configuration.save_config Inf.path.rails.config_infrastructure_dir + '/environment.yml'
|
11
|
+
Rake::Task['environment:current'].invoke
|
12
|
+
end
|
13
|
+
|
14
|
+
%w( test development production ).each do |environment|
|
15
|
+
desc "Change to #{environment} environment"
|
16
|
+
task(environment.to_sym) { set_environment_and_save environment }
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|