snap_deploy 0.1.3
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 +21 -0
- data/.init.sh +8 -0
- data/.rbenv-gemsets +1 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +100 -0
- data/LICENSE.txt +22 -0
- data/README.md +34 -0
- data/Rakefile +25 -0
- data/bin/snap-deploy +10 -0
- data/install.sh +18 -0
- data/lib/snap_deploy.rb +4 -0
- data/lib/snap_deploy/cli.rb +24 -0
- data/lib/snap_deploy/helpers.rb +74 -0
- data/lib/snap_deploy/provider.rb +8 -0
- data/lib/snap_deploy/provider/aws.rb +17 -0
- data/lib/snap_deploy/provider/aws/elastic_beanstalk.rb +156 -0
- data/lib/snap_deploy/provider/aws/ops_works.rb +98 -0
- data/lib/snap_deploy/provider/aws/s3.rb +111 -0
- data/lib/snap_deploy/provider/heroku.rb +242 -0
- data/lib/snap_deploy/provider/heroku/api.rb +1532 -0
- data/lib/snap_deploy/provider/update.rb +25 -0
- data/lib/snap_deploy/version.rb +3 -0
- data/snap_deploy.gemspec +28 -0
- data/spec/spec_helper.rb +41 -0
- data/spec/unit/snap_deploy/provider/aws/ops_works_spec.rb +128 -0
- data/spec/unit/snap_deploy/provider/aws/s3_spec.rb +60 -0
- data/spec/unit/snap_deploy/provider/heroku_spec.rb +189 -0
- metadata +177 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/file_utils_ext'
|
3
|
+
|
4
|
+
class SnapDeploy::Provider::Update < Clamp::Command
|
5
|
+
|
6
|
+
SnapDeploy::CLI.subcommand 'update', 'Update snap deploy', self
|
7
|
+
|
8
|
+
include SnapDeploy::CLI::DefaultOptions
|
9
|
+
include SnapDeploy::Helpers
|
10
|
+
include Rake::FileUtilsExt
|
11
|
+
|
12
|
+
option '--revision',
|
13
|
+
'REVISION',
|
14
|
+
"Update to specified revision",
|
15
|
+
:default => 'release'
|
16
|
+
|
17
|
+
def execute
|
18
|
+
cd(File.dirname(__FILE__), :verbose => !!verbose?) do
|
19
|
+
sh("sudo $(which git) fetch --all", :verbose => !!verbose?)
|
20
|
+
sh("sudo $(which git) merge --ff-only origin/#{revision}", :verbose => !!verbose?)
|
21
|
+
sh("cd \"$(git rev-parse --show-toplevel)\" && sudo ./install.sh")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
data/snap_deploy.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'snap_deploy/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "snap_deploy"
|
8
|
+
spec.version = SnapDeploy::VERSION
|
9
|
+
spec.authors = ["Snap CI"]
|
10
|
+
spec.email = ["support@snap-ci.com"]
|
11
|
+
spec.summary = %q{Deploy your application in a Snap}
|
12
|
+
spec.description = %q{A simple rubygem to help continuously deploy your application}
|
13
|
+
spec.homepage = "https://snap-ci.com"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($\) + Dir["bundle/**/*"] - Dir["**/*.gem"] + Dir['bin/*'] - Dir["bundle/ruby/2.0.0/gems/*/{spec,test,specs,tests,examples,doc,doc-api,benchmarks,benchmark,feature,features}/**/*"]
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
22
|
+
spec.add_runtime_dependency 'ansi'
|
23
|
+
spec.add_runtime_dependency "clamp"
|
24
|
+
spec.add_runtime_dependency "aws-sdk", '1.53.0'
|
25
|
+
spec.add_runtime_dependency "mime-types"
|
26
|
+
spec.add_runtime_dependency "heroics"
|
27
|
+
spec.add_runtime_dependency "rendezvous"
|
28
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
ENV['TEST'] = 'true'
|
2
|
+
require 'simplecov'
|
3
|
+
SimpleCov.start do
|
4
|
+
add_filter '/bundle/ruby/'
|
5
|
+
add_filter '/vendor/cache/'
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'snap_deploy'
|
9
|
+
require 'webmock/rspec'
|
10
|
+
|
11
|
+
module SpecHelper
|
12
|
+
def revision
|
13
|
+
@revision ||= SecureRandom.hex(32)
|
14
|
+
end
|
15
|
+
|
16
|
+
def short_revision
|
17
|
+
revision[0..7]
|
18
|
+
end
|
19
|
+
|
20
|
+
def strip_heredoc(str)
|
21
|
+
indent = str.scan(/^[ \t]*(?=\S)/).min.size || 0
|
22
|
+
str.gsub(/^[ \t]{#{indent}}/, '')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
RSpec.configure do |config|
|
27
|
+
config.include SpecHelper
|
28
|
+
config.tty = true
|
29
|
+
config.expose_dsl_globally = false
|
30
|
+
config.disable_monkey_patching!
|
31
|
+
|
32
|
+
config.before(:each) do
|
33
|
+
@original_env = ENV.to_h.dup
|
34
|
+
ENV.clear
|
35
|
+
end
|
36
|
+
|
37
|
+
config.after(:each) do
|
38
|
+
ENV.replace(@original_env)
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'aws-sdk'
|
3
|
+
|
4
|
+
RSpec.describe SnapDeploy::Provider::AWS::OpsWorks do
|
5
|
+
subject(:cmd) { SnapDeploy::Provider::AWS::OpsWorks.new(nil, {}, {}) }
|
6
|
+
|
7
|
+
let(:client) { double(:ops_works_client) }
|
8
|
+
let(:app_id) { SecureRandom.uuid }
|
9
|
+
let(:deployment_id) { SecureRandom.uuid }
|
10
|
+
let(:stack_id) { SecureRandom.uuid }
|
11
|
+
|
12
|
+
let(:ops_works_app) do
|
13
|
+
{shortname: 'simplephpapp', stack_id: stack_id}
|
14
|
+
end
|
15
|
+
|
16
|
+
before do
|
17
|
+
AWS.stub!
|
18
|
+
|
19
|
+
allow(cmd).to receive(:client).and_return(client)
|
20
|
+
|
21
|
+
allow(ENV).to receive(:[]).with('SNAP_PIPELINE_COUNTER').and_return('123')
|
22
|
+
allow(ENV).to receive(:[]).with('SNAP_COMMIT_SHORT').and_return(short_revision)
|
23
|
+
allow(ENV).to receive(:[]).with('SNAP_COMMIT').and_return(revision)
|
24
|
+
allow(ENV).to receive(:[]).with('SNAP_STAGE_TRIGGERED_BY').and_return('john-doe')
|
25
|
+
end
|
26
|
+
|
27
|
+
example 'with migrate option not specified' do
|
28
|
+
expect(client).to receive(:describe_apps).with(app_ids: [app_id]).and_return({apps: [ops_works_app]})
|
29
|
+
expect(client).to receive(:create_deployment).with(
|
30
|
+
stack_id: stack_id,
|
31
|
+
app_id: app_id,
|
32
|
+
command: {name: 'deploy'},
|
33
|
+
comment: "Deploy build 123(rev #{short_revision}) via Snap CI by john-doe",
|
34
|
+
custom_json: {"deploy"=>{"simplephpapp"=>{"migrate"=>true, "scm"=>{"revision"=>revision}}}}.to_json
|
35
|
+
).and_return({deployment_id: deployment_id})
|
36
|
+
|
37
|
+
expect(client).to receive(:describe_deployments).with({deployment_ids: [deployment_id]}).and_return(
|
38
|
+
{deployments: [status: 'running']},
|
39
|
+
{deployments: [status: 'successful']}
|
40
|
+
)
|
41
|
+
|
42
|
+
expect do
|
43
|
+
cmd.run(['--wait', '--app-id', app_id])
|
44
|
+
end.to output(strip_heredoc(<<-EOF
|
45
|
+
Deployment created: #{deployment_id}
|
46
|
+
Deploying .
|
47
|
+
Deployment successful.
|
48
|
+
EOF
|
49
|
+
)).to_stdout
|
50
|
+
end
|
51
|
+
|
52
|
+
example 'with migrate option specified' do
|
53
|
+
expect(client).to receive(:describe_apps).with(app_ids: [app_id]).and_return({apps: [ops_works_app]})
|
54
|
+
expect(client).to receive(:create_deployment).with(
|
55
|
+
stack_id: stack_id,
|
56
|
+
app_id: app_id,
|
57
|
+
command: {name: 'deploy'},
|
58
|
+
comment: "Deploy build 123(rev #{short_revision}) via Snap CI by john-doe",
|
59
|
+
custom_json: {"deploy"=>{"simplephpapp"=>{"migrate"=>true, "scm"=>{"revision"=>revision}}}}.to_json
|
60
|
+
).and_return({deployment_id: deployment_id})
|
61
|
+
|
62
|
+
expect(client).to receive(:describe_deployments).with({deployment_ids: [deployment_id]}).and_return(
|
63
|
+
{deployments: [status: 'running']},
|
64
|
+
{deployments: [status: 'successful']}
|
65
|
+
)
|
66
|
+
expect do
|
67
|
+
cmd.run(['--wait', '--migrate', '--app-id', app_id])
|
68
|
+
end.to output(strip_heredoc(<<-EOF
|
69
|
+
Deployment created: #{deployment_id}
|
70
|
+
Deploying .
|
71
|
+
Deployment successful.
|
72
|
+
EOF
|
73
|
+
)).to_stdout
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
example 'with migrate option forced off' do
|
78
|
+
expect(client).to receive(:describe_apps).with(app_ids: [app_id]).and_return({apps: [ops_works_app]})
|
79
|
+
expect(client).to receive(:create_deployment).with(
|
80
|
+
stack_id: stack_id,
|
81
|
+
app_id: app_id,
|
82
|
+
command: {name: 'deploy'},
|
83
|
+
comment: "Deploy build 123(rev #{short_revision}) via Snap CI by john-doe",
|
84
|
+
custom_json: {"deploy"=>{"simplephpapp"=>{"migrate"=>false, "scm"=>{"revision"=>revision}}}}.to_json
|
85
|
+
).and_return({deployment_id: deployment_id})
|
86
|
+
|
87
|
+
expect(client).to receive(:describe_deployments).with({deployment_ids: [deployment_id]}).and_return(
|
88
|
+
{deployments: [status: 'running']},
|
89
|
+
{deployments: [status: 'successful']}
|
90
|
+
)
|
91
|
+
|
92
|
+
expect do
|
93
|
+
cmd.run(['--wait', '--no-migrate', '--app-id', app_id])
|
94
|
+
end.to output(strip_heredoc(<<-EOF
|
95
|
+
Deployment created: #{deployment_id}
|
96
|
+
Deploying .
|
97
|
+
Deployment successful.
|
98
|
+
EOF
|
99
|
+
)).to_stdout
|
100
|
+
end
|
101
|
+
|
102
|
+
example 'when deployment fails' do
|
103
|
+
expect(client).to receive(:describe_apps).with(app_ids: [app_id]).and_return({apps: [ops_works_app]})
|
104
|
+
expect(client).to receive(:create_deployment).with(
|
105
|
+
stack_id: stack_id,
|
106
|
+
app_id: app_id,
|
107
|
+
command: {name: 'deploy'},
|
108
|
+
comment: "Deploy build 123(rev #{short_revision}) via Snap CI by john-doe",
|
109
|
+
custom_json: {"deploy"=>{"simplephpapp"=>{"migrate"=>false, "scm"=>{"revision"=>revision}}}}.to_json
|
110
|
+
).and_return({deployment_id: deployment_id})
|
111
|
+
|
112
|
+
expect(client).to receive(:describe_deployments).with({deployment_ids: [deployment_id]}).and_return(
|
113
|
+
{deployments: [status: 'running']},
|
114
|
+
{deployments: [status: 'failed']}
|
115
|
+
)
|
116
|
+
|
117
|
+
expect do
|
118
|
+
expect do
|
119
|
+
cmd.run(['--wait', '--no-migrate', '--app-id', app_id])
|
120
|
+
end.to raise_error('Deployment failed.')
|
121
|
+
end.to output(strip_heredoc(<<-EOF
|
122
|
+
Deployment created: #{deployment_id}
|
123
|
+
Deploying .
|
124
|
+
Deployment failed.
|
125
|
+
EOF
|
126
|
+
)).to_stdout
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'aws-sdk'
|
3
|
+
|
4
|
+
RSpec.describe SnapDeploy::Provider::AWS::S3 do
|
5
|
+
subject(:cmd) { SnapDeploy::Provider::AWS::S3.new(nil, {}, {}) }
|
6
|
+
|
7
|
+
before do
|
8
|
+
AWS.stub!
|
9
|
+
|
10
|
+
allow(ENV).to receive(:[]).with(anything).and_call_original
|
11
|
+
allow(ENV).to receive(:[]).with('AWS_ACCESS_KEY_ID').and_return(SecureRandom.hex)
|
12
|
+
allow(ENV).to receive(:[]).with('AWS_SECRET_ACCESS_KEY').and_return(SecureRandom.hex)
|
13
|
+
allow(ENV).to receive(:[]).with('SNAP_PIPELINE_COUNTER').and_return('123')
|
14
|
+
allow(ENV).to receive(:[]).with('SNAP_COMMIT_SHORT').and_return(short_revision)
|
15
|
+
allow(ENV).to receive(:[]).with('SNAP_COMMIT').and_return(revision)
|
16
|
+
allow(ENV).to receive(:[]).with('SNAP_STAGE_TRIGGERED_BY').and_return('john-doe')
|
17
|
+
end
|
18
|
+
|
19
|
+
example 'with local dir not specified' do
|
20
|
+
expect(Dir).to receive(:chdir).with(Dir.pwd)
|
21
|
+
cmd.run(['--bucket', 'example.com'])
|
22
|
+
end
|
23
|
+
|
24
|
+
example 'with local dir specified' do
|
25
|
+
expect(Dir).to receive(:chdir).with('_build')
|
26
|
+
cmd.run(['--bucket', 'example.com', '--local-dir', '_build'])
|
27
|
+
end
|
28
|
+
|
29
|
+
example "Sends MIME type" do
|
30
|
+
expect(Dir).to receive(:glob).and_yield(__FILE__)
|
31
|
+
expect_any_instance_of(AWS::S3::ObjectCollection).to receive(:create).with(anything(), anything(), hash_including(:content_type => 'application/x-ruby'))
|
32
|
+
cmd.run(['--bucket', 'example.com'])
|
33
|
+
end
|
34
|
+
|
35
|
+
example "Sets Cache and Expiration" do
|
36
|
+
expect(Dir).to receive(:glob).and_yield(__FILE__)
|
37
|
+
expect_any_instance_of(AWS::S3::ObjectCollection).to receive(:create).with(anything(), anything(), hash_including(:cache_control => 'max-age=99999999', :expires => '2012-12-21 00:00:00 -0000'))
|
38
|
+
cmd.run(['--bucket', 'example.com', '--cache-control', 'max-age=99999999', '--expires', '2012-12-21 00:00:00 -0000'])
|
39
|
+
end
|
40
|
+
|
41
|
+
example "Sets ACL" do
|
42
|
+
expect(Dir).to receive(:glob).and_yield(__FILE__)
|
43
|
+
expect_any_instance_of(AWS::S3::ObjectCollection).to receive(:create).with(anything(), anything(), hash_including(:acl => "public_read"))
|
44
|
+
cmd.run(['--bucket', 'example.com', '--acl', 'public_read'])
|
45
|
+
end
|
46
|
+
|
47
|
+
example "when detect_encoding is set" do
|
48
|
+
path = 'foo.js'
|
49
|
+
expect(Dir).to receive(:glob).and_yield(path)
|
50
|
+
expect(cmd).to receive(:'`').at_least(1).times.with("file #{path}").and_return('gzip compressed')
|
51
|
+
allow(File).to receive(:read).with(path).and_return("")
|
52
|
+
expect_any_instance_of(AWS::S3::ObjectCollection).to receive(:create).with(anything(), anything(), hash_including(:content_encoding => 'gzip'))
|
53
|
+
cmd.run(['--bucket', 'example.com', '--detect-encoding'])
|
54
|
+
end
|
55
|
+
|
56
|
+
example "when dot_match is set" do
|
57
|
+
expect(Dir).to receive(:glob).with("**/*", File::FNM_DOTMATCH)
|
58
|
+
cmd.run(['--bucket', 'example.com', '--detect-encoding', '--include-dot-files'])
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,189 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe SnapDeploy::Provider::Heroku do
|
4
|
+
subject(:cmd) { SnapDeploy::Provider::Heroku.new(nil, {}, {}) }
|
5
|
+
|
6
|
+
let(:token) { SecureRandom.hex }
|
7
|
+
let(:branch) { SecureRandom.hex }
|
8
|
+
|
9
|
+
before do
|
10
|
+
allow(cmd).to receive(:token).and_return(token)
|
11
|
+
|
12
|
+
ENV['SNAP_BRANCH'] = branch
|
13
|
+
end
|
14
|
+
|
15
|
+
describe 'execution behavior' do
|
16
|
+
it 'should invoke methods in order' do
|
17
|
+
expect(cmd).to receive(:check_auth).ordered
|
18
|
+
expect(cmd).to receive(:maybe_create_app).ordered
|
19
|
+
expect(cmd).to receive(:setup_configuration).ordered
|
20
|
+
expect(cmd).to receive(:git_push).ordered
|
21
|
+
expect(cmd).to receive(:maybe_db_migrate).ordered
|
22
|
+
|
23
|
+
cmd.run(['--app-name', 'foo'])
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe 'check authentication' do
|
28
|
+
it 'should raise error on auth failure' do
|
29
|
+
stub_request(:get, 'https://api.heroku.com/account').
|
30
|
+
with(:headers => { 'Authorization' => "Bearer #{token}" }).
|
31
|
+
to_return(:status => 401, :body => {}.to_json, :headers => {})
|
32
|
+
|
33
|
+
expect do
|
34
|
+
cmd.parse(['--app-name', 'foo'])
|
35
|
+
cmd.send :check_auth
|
36
|
+
end.to raise_error(RuntimeError, 'Could not connect to heroku to check your credentials. The server returned status code 401.')
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should raise error when could not connect' do
|
40
|
+
stub_request(:get, 'https://api.heroku.com/account').
|
41
|
+
with(:headers => { 'Authorization' => "Bearer #{token}" }).
|
42
|
+
to_raise(EOFError)
|
43
|
+
|
44
|
+
expect do
|
45
|
+
cmd.parse(['--app-name', 'foo'])
|
46
|
+
cmd.send :check_auth
|
47
|
+
end.to raise_error(EOFError)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe 'create app' do
|
52
|
+
it 'should create app if one does not exist' do
|
53
|
+
stub_request(:get, 'https://api.heroku.com/apps/foo').
|
54
|
+
with(:headers => { 'Authorization' => "Bearer #{token}" }).
|
55
|
+
to_return(:status => 404)
|
56
|
+
|
57
|
+
stub_request(:post, 'https://api.heroku.com/apps').
|
58
|
+
with(:headers => { 'Authorization' => "Bearer #{token}" })
|
59
|
+
|
60
|
+
cmd.parse(['--app-name', 'foo'])
|
61
|
+
cmd.send(:maybe_create_app)
|
62
|
+
end
|
63
|
+
|
64
|
+
[401, 403].each do |code|
|
65
|
+
it "should raise error if we cannot verify if app exists (#{code})" do
|
66
|
+
stub_request(:get, 'https://api.heroku.com/apps/foo').
|
67
|
+
with(:headers => { 'Authorization' => "Bearer #{token}" }).
|
68
|
+
to_return(:status => code)
|
69
|
+
|
70
|
+
allow(cmd).to receive(:setup_configuration)
|
71
|
+
allow(cmd).to receive(:git_push)
|
72
|
+
|
73
|
+
expect do
|
74
|
+
cmd.parse(['--app-name', 'foo'])
|
75
|
+
cmd.send(:maybe_create_app)
|
76
|
+
end.to raise_error(RuntimeError, "You are not authorized to check if the app exists, perhaps you don't own that app?. The server returned status code #{code}.")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should create app if one does not exist' do
|
81
|
+
stub_request(:get, 'https://api.heroku.com/apps/foo').
|
82
|
+
with(:headers => { 'Authorization' => "Bearer #{token}" }).
|
83
|
+
to_return(:status => 404)
|
84
|
+
|
85
|
+
stub_request(:post, 'https://api.heroku.com/apps').
|
86
|
+
with(:headers => { 'Authorization' => "Bearer #{token}" })
|
87
|
+
|
88
|
+
allow(cmd).to receive(:setup_configuration)
|
89
|
+
allow(cmd).to receive(:git_push)
|
90
|
+
|
91
|
+
cmd.parse(['--app-name', 'foo', '--region', 'jhumri-taliya', '--stack-name', 'some-stack'])
|
92
|
+
cmd.send(:maybe_create_app)
|
93
|
+
expect(a_request(:post, 'https://api.heroku.com/apps').
|
94
|
+
with(:body => { name: 'foo', region: 'jhumri-taliya', stack: 'some-stack' }, :headers => { 'Authorization' => "Bearer #{token}" })).to have_been_made
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe 'setup_configuration' do
|
99
|
+
it 'should not send config vars if one is not specified' do
|
100
|
+
cmd.parse(['--app-name', 'foo'])
|
101
|
+
cmd.send(:setup_configuration)
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'should not set any config vars if there is no delta' do
|
105
|
+
stub_request(:get, 'https://api.heroku.com/apps/foo/config-vars').
|
106
|
+
with(:headers => { 'Authorization' => "Bearer #{token}" }).
|
107
|
+
to_return(:body => { 'FOO' => 'bar', 'BOO' => 'baz' }.to_json, :headers => { 'Content-Type' => 'application/json' })
|
108
|
+
|
109
|
+
cmd.parse(['--app-name', 'foo', '--config-var', 'FOO=bar', '--config-var', 'BOO=baz'])
|
110
|
+
cmd.send(:setup_configuration)
|
111
|
+
|
112
|
+
expect(a_request(:any, "api.heroku.com")).not_to have_been_made
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'should set any config vars if there is a delta' do
|
116
|
+
stub_request(:get, 'https://api.heroku.com/apps/foo/config-vars').
|
117
|
+
with(:headers => { 'Authorization' => "Bearer #{token}" }).
|
118
|
+
to_return(:body => { 'FOO' => 'oldfoo', 'BOO' => 'oldboo' }.to_json, :headers => { 'Content-Type' => 'application/json' })
|
119
|
+
|
120
|
+
stub_request(:patch, 'https://api.heroku.com/apps/foo/config-vars')
|
121
|
+
|
122
|
+
cmd.parse(['--app-name', 'foo', '--config-var', 'FOO=newfoo', '--config-var', 'BOO=oldboo', '--config-var', 'NEW_VAR=new_value'])
|
123
|
+
cmd.send(:setup_configuration)
|
124
|
+
|
125
|
+
expect(a_request(:patch, "https://api.heroku.com/apps/foo/config-vars").
|
126
|
+
with(:body => {'FOO' => 'newfoo', 'NEW_VAR' => 'new_value'}, :headers => { 'Authorization' => "Bearer #{token}"})).to have_been_made
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'should set buildpack url if one is specified' do
|
130
|
+
stub_request(:get, 'https://api.heroku.com/apps/foo/config-vars').
|
131
|
+
with(:headers => { 'Authorization' => "Bearer #{token}" }).
|
132
|
+
to_return(:body => { 'FOO' => 'oldfoo', 'BOO' => 'oldboo' }.to_json, :headers => { 'Content-Type' => 'application/json' })
|
133
|
+
|
134
|
+
stub_request(:patch, 'https://api.heroku.com/apps/foo/config-vars')
|
135
|
+
|
136
|
+
cmd.parse(['--app-name', 'foo', '--buildpack-url', 'https://github.com/heroku/heroku-buildpack-ruby'])
|
137
|
+
cmd.send(:setup_configuration)
|
138
|
+
|
139
|
+
expect(a_request(:patch, "https://api.heroku.com/apps/foo/config-vars").
|
140
|
+
with(:body => {'BUILDPACK_URL' => 'https://github.com/heroku/heroku-buildpack-ruby'}, :headers => { 'Authorization' => "Bearer #{token}"})).to have_been_made
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'should set buildpack url if one is specified along with any configs' do
|
144
|
+
stub_request(:get, 'https://api.heroku.com/apps/foo/config-vars').
|
145
|
+
with(:headers => { 'Authorization' => "Bearer #{token}" }).
|
146
|
+
to_return(:body => { 'FOO' => 'oldfoo', 'BOO' => 'oldboo' }.to_json, :headers => { 'Content-Type' => 'application/json' })
|
147
|
+
|
148
|
+
stub_request(:patch, 'https://api.heroku.com/apps/foo/config-vars')
|
149
|
+
|
150
|
+
cmd.parse(['--app-name', 'foo', '--config-var', 'FOO=newfoo', '--config-var', 'BOO=oldboo', '--config-var', 'NEW_VAR=new_value', '--buildpack-url', 'https://github.com/heroku/heroku-buildpack-ruby'])
|
151
|
+
cmd.send(:setup_configuration)
|
152
|
+
|
153
|
+
expect(a_request(:patch, "https://api.heroku.com/apps/foo/config-vars").
|
154
|
+
with(:body => {'FOO' => 'newfoo', 'NEW_VAR' => 'new_value', 'BUILDPACK_URL' => 'https://github.com/heroku/heroku-buildpack-ruby'}, :headers => { 'Authorization' => "Bearer #{token}"})).to have_been_made
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'should work with config vars which have a "=" in their values' do
|
158
|
+
stub_request(:get, 'https://api.heroku.com/apps/foo/config-vars').
|
159
|
+
with(:headers => { 'Authorization' => "Bearer #{token}" }).
|
160
|
+
to_return(:body => { 'FOO' => 'oldfoo' }.to_json, :headers => { 'Content-Type' => 'application/json' })
|
161
|
+
|
162
|
+
stub_request(:patch, 'https://api.heroku.com/apps/foo/config-vars')
|
163
|
+
|
164
|
+
cmd.parse(['--app-name', 'foo', '--config-var', 'FOO=new=foo==bar'])
|
165
|
+
cmd.send(:setup_configuration)
|
166
|
+
|
167
|
+
expect(a_request(:patch, "https://api.heroku.com/apps/foo/config-vars").
|
168
|
+
with(:body => {'FOO' => 'new=foo==bar'}, :headers => { 'Authorization' => "Bearer #{token}"})).to have_been_made
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
describe 'git push' do
|
173
|
+
it 'should push to heroku via https' do
|
174
|
+
cmd.parse(['--app-name', 'foo'])
|
175
|
+
system('true')
|
176
|
+
expect(cmd).to receive(:sh).with('git push https://git.heroku.com/foo.git HEAD:refs/heads/master -f').and_yield(true, $?)
|
177
|
+
cmd.send(:git_push)
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'should raise error when push fails' do
|
181
|
+
cmd.parse(['--app-name', 'foo'])
|
182
|
+
system('exit -1')
|
183
|
+
expect(cmd).to receive(:sh).with('git push https://git.heroku.com/foo.git HEAD:refs/heads/master -f').and_yield(false, $?)
|
184
|
+
expect do
|
185
|
+
cmd.send(:git_push)
|
186
|
+
end.to raise_error(RuntimeError, 'Could not push to heroku remote. The exit code was 255.')
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|