dbcp 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e37c2566e5ac25d166c8fd27df6209e2f83863f1
4
- data.tar.gz: 0960077bc0488bd979f3b97b751a940b3e6f11c4
3
+ metadata.gz: 9c641bd106b4541cdac1d446c797ba2c4ff3f9d5
4
+ data.tar.gz: 0dccc3c0a43466de4d64091afc3c3abb2ad3a386
5
5
  SHA512:
6
- metadata.gz: 0d8b2f092e45700399fbfda1e91cdb0c80205ecf9670b07c5b5996d153ddf9570df48c57278a8427e7ec32350d11148356864f3a0c427d74dc462a45b0747ff0
7
- data.tar.gz: fdde59cd6bd19e060aefd6a1c5999087ebeab62aa2c08c5f4135fadb320979bffb0e8b514256258fc65767646a990b16ec498bbd686aee5741af50b491d70bec
6
+ metadata.gz: 2784736ffcbae106f94c4563e720e6812dc103db3edd75918104ccc9ee089db2957fd16371b99fe5f816887403b730ce91dccc0cc7e8be631cc39b96ef37ee4b
7
+ data.tar.gz: 0de40673b043e993bc02d203f4f73b496afa813bcd0c2369f7edc62196f9d050925882843b00af7e4a85f011c10e221579fd633b214517fa597c1bd7ecd76a33
data/README.md CHANGED
@@ -74,24 +74,33 @@ You can use a database URI in place of an environment name as follows:
74
74
 
75
75
  $ dbcp postgres://my_username:my_pass@db.example.com/my_database development
76
76
 
77
+ ### Capistrano v3
78
+
79
+ If you deploy your application via Capistrano, `dbcp` will lookup and invoke for a matching task name in your capistrano configuration to read the remote ssh and path information for the primary `:db` server role. It will ssh to that server both to read the remote remote `#{deploy_to}/current/config/database.yml` and execute the database export from.
80
+
81
+ Example, with `config/deploy/staging.rb`
82
+
83
+ ```ruby
84
+ server 'staging.example.com', user: 'staging', roles: %w{web app db}
85
+ set :deploy_to, '/www/staging.example.com'
86
+ ```
87
+
88
+ and separately defined `development` environment will allow you to run:
89
+
90
+ $ cap staging development
91
+
77
92
  ## Roadmap
78
93
 
79
94
  The following features are pending:
80
95
 
81
96
  Providers:
82
97
 
83
- - Capistrano task
84
98
  - Heroku, environment name inferred from git remotes
85
99
 
86
- Features:
87
-
88
- - Definable per-tool specific options, e.g. to allow pg_dump to provide a table exclusion list
89
- - URI Provider: specify an remote ssh execution host, perhaps using '@@' as a URI separator?
90
-
91
100
  Refactors:
92
101
 
93
102
  - Handle pg_restore warnings
94
103
  - Better logging
95
104
  - Better help
96
105
 
97
- [Open an issue](https://github.com/gabetax/dbcp/issues) if there's something else you'd like to see supported.
106
+ Please [open an issue](https://github.com/gabetax/dbcp/issues) or send a pull request if you see a weird error, a database or environment definition you want supported, or anything you want to see improved.
data/dbcp.gemspec CHANGED
@@ -22,8 +22,11 @@ Gem::Specification.new do |spec|
22
22
  spec.add_dependency "net-ssh", "~> 2.8.0"
23
23
  spec.add_dependency "net-sftp", "~> 2.1.2"
24
24
  spec.add_development_dependency "bundler", "~> 1.3"
25
+ spec.add_development_dependency "capistrano", "~> 3.1"
25
26
  spec.add_development_dependency "rspec"
26
27
  spec.add_development_dependency "codeclimate-test-reporter"
27
- spec.add_development_dependency "rake"
28
+ # Rake 10.2.0 conflicts with `TypeError: no implicit conversion of Rake::Task into String`
29
+ # https://github.com/capistrano/capistrano/pull/983
30
+ spec.add_development_dependency "rake", "10.1.1"
28
31
  spec.add_development_dependency "pry"
29
32
  end
@@ -5,8 +5,9 @@ module Dbcp
5
5
  class Environment
6
6
  ENVIRONMENT_PROVIDERS = [
7
7
  DatabaseYamlEnvironmentProvider.new('config/database.yml'),
8
- UriEnvironmentProvider.new
9
- ]
8
+ UriEnvironmentProvider.new,
9
+ (Capistrano3EnvironmentProvider.new if defined?(Capistrano3EnvironmentProvider.new))
10
+ ].compact
10
11
 
11
12
  class << self
12
13
  def find(environment_name)
@@ -0,0 +1,64 @@
1
+ begin
2
+ # Capistrano 3 is built on rake. Capistrano 2 has a totally different API
3
+ gem 'capistrano', '~> 3.0'
4
+ require 'capistrano/all'
5
+
6
+ module Dbcp
7
+ class Capistrano3EnvironmentProvider
8
+ REMOTE_YAML_PATH = 'config/database.yml'
9
+
10
+ # @return [Environment, nil]
11
+ def find(environment_name)
12
+ task = capistrano_application.lookup environment_name
13
+ if task
14
+ build_environment environment_name, task
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ # Capistrano and rake both use a lot of global state. `load_rakefile`
21
+ # loads _ONLY_ to the global `Rake.application` instance. If you load
22
+ # the Capfile twice, the second time comes back empty.
23
+ def capistrano_application
24
+ @@capistrano_application ||= load_capistrano_application
25
+ end
26
+
27
+ def load_capistrano_application
28
+ original_application = Rake.application
29
+
30
+ Rake.application = Capistrano::Application.new
31
+ Rake.application.init
32
+ Rake.application.load_rakefile
33
+
34
+ Rake.application
35
+ end
36
+
37
+
38
+ def build_environment(environment_name, task)
39
+ execution_host = execution_host_from_task task
40
+ Environment.new({
41
+ environment_name: environment_name,
42
+ database: execution_host.remote_database('current/config/database.yml', environment_name),
43
+ execution_host: execution_host
44
+ })
45
+ end
46
+
47
+ def execution_host_from_task(task)
48
+ task.invoke
49
+ cap_env = Capistrano::Configuration.env
50
+ server = Capistrano::Configuration.env.primary(:db)
51
+
52
+ SshExecutionHost.new({
53
+ host: server.hostname,
54
+ port: server.port,
55
+ username: server.user,
56
+ path: cap_env.fetch(:deploy_to)
57
+ })
58
+ end
59
+ end
60
+ end
61
+
62
+ rescue LoadError
63
+ # Class won't exist. Make sure to check `if defined?(Dbcp::CapistranoEnvironmentProvider)`
64
+ end
@@ -33,7 +33,7 @@ module Dbcp
33
33
  database = Database.build(environment_hash)
34
34
  rescue Database::BlankDatabaseDefinition => e
35
35
  if execution_host.remote?
36
- database = Database.build fetch_remote_environment_hash(execution_host)[environment_name]
36
+ database = execution_host.remote_database
37
37
  else
38
38
  raise e
39
39
  end
@@ -46,9 +46,5 @@ module Dbcp
46
46
  })
47
47
  end
48
48
 
49
- def fetch_remote_environment_hash(execution_host)
50
- YAML.load execution_host.download "#{execution_host.path}/#{@database_yaml_path}"
51
- end
52
-
53
49
  end
54
50
  end
@@ -77,5 +77,13 @@ module Dbcp
77
77
  return ssh.upload! source_path, destination_path
78
78
  end
79
79
  end
80
+
81
+ def remote_database(database_yaml_path, environment_name)
82
+ Database.build remote_yaml(database_yaml_path)[environment_name]
83
+ end
84
+
85
+ def remote_yaml(remote_yaml_path)
86
+ YAML.load download("#{path}/#{remote_yaml_path}")
87
+ end
80
88
  end
81
89
  end
data/lib/dbcp/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Dbcp
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/dbcp.rb CHANGED
@@ -5,8 +5,9 @@ require 'dbcp/cli'
5
5
  require 'dbcp/database'
6
6
  require 'dbcp/databases/mysql_database'
7
7
  require 'dbcp/databases/postgres_database'
8
- require 'dbcp/environment_providers/uri_environment_provider'
8
+ require 'dbcp/environment_providers/capistrano_3_environment_provider'
9
9
  require 'dbcp/environment_providers/database_yaml_environment_provider'
10
+ require 'dbcp/environment_providers/uri_environment_provider'
10
11
  require 'dbcp/execution_host'
11
12
  require 'dbcp/execution_hosts/local_execution_host'
12
13
  require 'dbcp/execution_hosts/ssh_execution_host'
@@ -0,0 +1,25 @@
1
+ # Load DSL and Setup Up Stages
2
+ require 'capistrano/setup'
3
+
4
+ # Includes default deployment tasks
5
+ require 'capistrano/deploy'
6
+
7
+ # Includes tasks from other gems included in your Gemfile
8
+ #
9
+ # For documentation on these, see for example:
10
+ #
11
+ # https://github.com/capistrano/rvm
12
+ # https://github.com/capistrano/rbenv
13
+ # https://github.com/capistrano/chruby
14
+ # https://github.com/capistrano/bundler
15
+ # https://github.com/capistrano/rails
16
+ #
17
+ # require 'capistrano/rvm'
18
+ # require 'capistrano/rbenv'
19
+ # require 'capistrano/chruby'
20
+ # require 'capistrano/bundler'
21
+ # require 'capistrano/rails/assets'
22
+ # require 'capistrano/rails/migrations'
23
+
24
+ # Loads custom tasks from `lib/capistrano/tasks' if you have any defined.
25
+ Dir.glob('lib/capistrano/tasks/*.cap').each { |r| import r }
@@ -0,0 +1,10 @@
1
+ # Simple Role Syntax
2
+ # ==================
3
+ # Supports bulk-adding hosts to roles, the primary
4
+ # server in each group is considered to be the first
5
+ # unless any hosts have the primary property set.
6
+ # Don't declare `role :all`, it's a meta role
7
+ role :app, %w{staging_user@app.example.com}
8
+ role :web, %w{staging_user@web.example.com}
9
+ role :db, %w{staging_user@db.example.com}
10
+ set :deploy_to, '/www/staging.example.com/current'
@@ -0,0 +1,58 @@
1
+ # config valid only for Capistrano 3.1
2
+ lock '3.1.0'
3
+
4
+ set :application, 'my_app_name'
5
+ set :repo_url, 'git@example.com:me/my_repo.git'
6
+
7
+ # Default branch is :master
8
+ # ask :branch, proc { `git rev-parse --abbrev-ref HEAD`.chomp }
9
+
10
+ # Default deploy_to directory is /var/www/my_app
11
+ # set :deploy_to, '/var/www/my_app'
12
+
13
+ # Default value for :scm is :git
14
+ # set :scm, :git
15
+
16
+ # Default value for :format is :pretty
17
+ # set :format, :pretty
18
+
19
+ # Default value for :log_level is :debug
20
+ # set :log_level, :debug
21
+
22
+ # Default value for :pty is false
23
+ # set :pty, true
24
+
25
+ # Default value for :linked_files is []
26
+ # set :linked_files, %w{config/database.yml}
27
+
28
+ # Default value for linked_dirs is []
29
+ # set :linked_dirs, %w{bin log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system}
30
+
31
+ # Default value for default_env is {}
32
+ # set :default_env, { path: "/opt/ruby/bin:$PATH" }
33
+
34
+ # Default value for keep_releases is 5
35
+ # set :keep_releases, 5
36
+
37
+ namespace :deploy do
38
+
39
+ desc 'Restart application'
40
+ task :restart do
41
+ on roles(:app), in: :sequence, wait: 5 do
42
+ # Your restart mechanism here, for example:
43
+ # execute :touch, release_path.join('tmp/restart.txt')
44
+ end
45
+ end
46
+
47
+ after :publishing, :restart
48
+
49
+ after :restart, :clear_cache do
50
+ on roles(:web), in: :groups, limit: 3, wait: 10 do
51
+ # Here we can do anything such as:
52
+ # within release_path do
53
+ # execute :rake, 'cache:clear'
54
+ # end
55
+ end
56
+ end
57
+
58
+ end
@@ -4,9 +4,6 @@ describe Dbcp::Cli do
4
4
  subject { Dbcp::Cli.new silent_stdout }
5
5
  let(:silent_stdout) { '/dev/null' }
6
6
 
7
- extend ExecuteInDirectory
8
- execute_in_directory(File.expand_path('../../../fixtures', __FILE__))
9
-
10
7
  describe "#start" do
11
8
  context "success" do
12
9
  let(:source) { double 'Dbcp::Environment', database: double(adapter: 'postgres'), environment_name: 'staging' }
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ describe Dbcp::Capistrano3EnvironmentProvider do
4
+ subject { Dbcp::Capistrano3EnvironmentProvider.new }
5
+
6
+ describe "#find" do
7
+ context "when task exists" do
8
+ let(:remote_database) { double 'Database' }
9
+ it "returns an environment" do
10
+ allow_any_instance_of(Dbcp::SshExecutionHost).to receive(:remote_database) { remote_database }
11
+ environment = subject.find 'staging'
12
+ expect(environment).to be_a Dbcp::Environment
13
+ expect(environment.environment_name).to eq 'staging'
14
+ expect(environment.execution_host).to be_a Dbcp::SshExecutionHost
15
+ expect(environment.execution_host.host).to eq 'db.example.com'
16
+ expect(environment.execution_host.username).to eq 'staging_user'
17
+ expect(environment.execution_host.path).to eq '/www/staging.example.com/current'
18
+ expect(environment.database).to eq remote_database
19
+ end
20
+ end
21
+
22
+ context "when task doesn't exist" do
23
+ specify do
24
+ expect(subject.find('doesnt-exist')).to be_nil
25
+ end
26
+ end
27
+
28
+ context "Capfile does't exist" do
29
+ let(:path) { 'doesnt-exist' }
30
+ specify do
31
+ expect(subject.find('production')).to be_nil
32
+ end
33
+ end
34
+ end
35
+
36
+
37
+ end
@@ -4,9 +4,6 @@ describe Dbcp::DatabaseYamlEnvironmentProvider do
4
4
  subject { Dbcp::DatabaseYamlEnvironmentProvider.new path }
5
5
  let(:path) { 'config/database.yml' }
6
6
 
7
- extend ExecuteInDirectory
8
- execute_in_directory(File.expand_path('../../../../fixtures', __FILE__))
9
-
10
7
  describe "#find" do
11
8
  context "when environment exists" do
12
9
  it "returns an environment" do
@@ -37,15 +34,11 @@ describe Dbcp::DatabaseYamlEnvironmentProvider do
37
34
  end
38
35
 
39
36
  context "without database definition, but with ssh_uri" do
40
- let(:remote_yaml) { File.read remote_yaml_path }
41
- let(:remote_yaml_path) { File.expand_path('../../../../fixtures/config/remote_database.yml', __FILE__) }
37
+ let(:remote_database) { double 'Dbcp::Database' }
42
38
  it "fetches database definition from database.yml on remote host" do
43
- allow_any_instance_of(Dbcp::SshExecutionHost).to receive(:download).with('/www/staging.example.com/current/config/database.yml') { remote_yaml }
39
+ allow_any_instance_of(Dbcp::SshExecutionHost).to receive(:remote_database) { remote_database }
44
40
  environment = subject.find 'staging_ssh_only'
45
- expect(environment.database).to be_a Dbcp::PostgresDatabase
46
- expect(environment.database.database).to eq 'remote_staging_database'
47
- expect(environment.database.username).to eq 'remote_staging_username'
48
- expect(environment.database.password).to eq 'remote_staging_password'
41
+ expect(environment.database).to eq remote_database
49
42
  end
50
43
  end
51
44
  end
@@ -41,5 +41,23 @@ describe Dbcp::SshExecutionHost do
41
41
  end
42
42
  end
43
43
 
44
+ context "remote yaml" do
45
+ let(:local_yaml_path) { File.expand_path('../../../../fixtures/config/remote_database.yml', __FILE__) }
46
+ before { allow(subject).to receive(:download) { File.read local_yaml_path } }
47
+
48
+ describe "#remote_database" do
49
+ it "downloads and parses the YAML" do
50
+ database = subject.remote_database 'config/database.yml', 'staging_ssh_only'
51
+ expect(database).to be_a Dbcp::Database
52
+ expect(database.database).to eq 'remote_staging_database'
53
+ end
54
+ end
55
+
56
+ describe "#remote_yaml" do
57
+ it "downloads and parses the YAML" do
58
+ expect(subject.remote_yaml 'config/database.yml').to have_key('staging_ssh_only')
59
+ end
60
+ end
61
+ end
44
62
 
45
63
  end
data/spec/spec_helper.rb CHANGED
@@ -7,3 +7,6 @@ require_relative '../lib/dbcp'
7
7
 
8
8
  Dir[File.expand_path("../support/**/*.rb", __FILE__)].sort.each { |f| require f }
9
9
 
10
+ RSpec.configure do |config|
11
+ config.before(:suite) { Dir.chdir File.expand_path('../fixtures', __FILE__) }
12
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dbcp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gabe Martin-Dempesy
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-09 00:00:00.000000000 Z
11
+ date: 2014-04-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: virtus
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - ~>
67
67
  - !ruby/object:Gem::Version
68
68
  version: '1.3'
69
+ - !ruby/object:Gem::Dependency
70
+ name: capistrano
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: '3.1'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: '3.1'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: rspec
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -98,16 +112,16 @@ dependencies:
98
112
  name: rake
99
113
  requirement: !ruby/object:Gem::Requirement
100
114
  requirements:
101
- - - '>='
115
+ - - '='
102
116
  - !ruby/object:Gem::Version
103
- version: '0'
117
+ version: 10.1.1
104
118
  type: :development
105
119
  prerelease: false
106
120
  version_requirements: !ruby/object:Gem::Requirement
107
121
  requirements:
108
- - - '>='
122
+ - - '='
109
123
  - !ruby/object:Gem::Version
110
- version: '0'
124
+ version: 10.1.1
111
125
  - !ruby/object:Gem::Dependency
112
126
  name: pry
113
127
  requirement: !ruby/object:Gem::Requirement
@@ -145,19 +159,24 @@ files:
145
159
  - lib/dbcp/databases/mysql_database.rb
146
160
  - lib/dbcp/databases/postgres_database.rb
147
161
  - lib/dbcp/environment.rb
162
+ - lib/dbcp/environment_providers/capistrano_3_environment_provider.rb
148
163
  - lib/dbcp/environment_providers/database_yaml_environment_provider.rb
149
164
  - lib/dbcp/environment_providers/uri_environment_provider.rb
150
165
  - lib/dbcp/execution_host.rb
151
166
  - lib/dbcp/execution_hosts/local_execution_host.rb
152
167
  - lib/dbcp/execution_hosts/ssh_execution_host.rb
153
168
  - lib/dbcp/version.rb
169
+ - spec/fixtures/Capfile
154
170
  - spec/fixtures/config/database.yml
171
+ - spec/fixtures/config/deploy.rb
172
+ - spec/fixtures/config/deploy/staging.rb
155
173
  - spec/fixtures/config/remote_database.yml
156
174
  - spec/lib/dbcp/cli_spec.rb
157
175
  - spec/lib/dbcp/database_snapshot_file_spec.rb
158
176
  - spec/lib/dbcp/database_spec.rb
159
177
  - spec/lib/dbcp/databases/mysql_database_spec.rb
160
178
  - spec/lib/dbcp/databases/postgres_database_spec.rb
179
+ - spec/lib/dbcp/environment_providers/capistrano_3_environment_provider_spec.rb
161
180
  - spec/lib/dbcp/environment_providers/database_yaml_environment_provider_spec.rb
162
181
  - spec/lib/dbcp/environment_providers/uri_environment_provider_spec.rb
163
182
  - spec/lib/dbcp/environment_spec.rb
@@ -166,7 +185,6 @@ files:
166
185
  - spec/lib/dbcp/execution_hosts/ssh_execution_host_spec.rb
167
186
  - spec/spec_helper.rb
168
187
  - spec/support/.keep
169
- - spec/support/execute_in_directory.rb
170
188
  homepage: https://github.com/gabetax/dbcp
171
189
  licenses:
172
190
  - MIT
@@ -192,13 +210,17 @@ signing_key:
192
210
  specification_version: 4
193
211
  summary: ''
194
212
  test_files:
213
+ - spec/fixtures/Capfile
195
214
  - spec/fixtures/config/database.yml
215
+ - spec/fixtures/config/deploy.rb
216
+ - spec/fixtures/config/deploy/staging.rb
196
217
  - spec/fixtures/config/remote_database.yml
197
218
  - spec/lib/dbcp/cli_spec.rb
198
219
  - spec/lib/dbcp/database_snapshot_file_spec.rb
199
220
  - spec/lib/dbcp/database_spec.rb
200
221
  - spec/lib/dbcp/databases/mysql_database_spec.rb
201
222
  - spec/lib/dbcp/databases/postgres_database_spec.rb
223
+ - spec/lib/dbcp/environment_providers/capistrano_3_environment_provider_spec.rb
202
224
  - spec/lib/dbcp/environment_providers/database_yaml_environment_provider_spec.rb
203
225
  - spec/lib/dbcp/environment_providers/uri_environment_provider_spec.rb
204
226
  - spec/lib/dbcp/environment_spec.rb
@@ -207,4 +229,3 @@ test_files:
207
229
  - spec/lib/dbcp/execution_hosts/ssh_execution_host_spec.rb
208
230
  - spec/spec_helper.rb
209
231
  - spec/support/.keep
210
- - spec/support/execute_in_directory.rb
@@ -1,10 +0,0 @@
1
- module ExecuteInDirectory
2
- def execute_in_directory(path)
3
- around(:each) do |example|
4
- old = Dir.pwd
5
- Dir.chdir path
6
- example.run
7
- Dir.chdir old
8
- end
9
- end
10
- end