deploy_s3 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/LICENSE.md +21 -0
- data/README.md +32 -0
- data/Rakefile +10 -0
- data/bin/ds3 +89 -0
- data/deploy_s3.gemspec +25 -0
- data/lib/deploy_s3/main.rb +91 -0
- data/lib/deploy_s3/remote.rb +18 -0
- data/lib/deploy_s3/version.rb +3 -0
- data/lib/deploy_s3.rb +3 -0
- data/spec/deploy_s3/main_spec.rb +52 -0
- data/spec/spec_helper.rb +2 -0
- metadata +118 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4bb777889b634b9cae981e66a96f1fc990ef07f1
|
4
|
+
data.tar.gz: 4090cec2ab0d3dc45d436dea2ae9b57ad30bb966
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2de46f99b955502a84b315aa043c5be4d0b34af435c49752d346f8ba0c96f6daf6510d24488f50ed67681534bc04e573ad38196a60a68c3c32da883dbc464702
|
7
|
+
data.tar.gz: 91d879284cb307797b0087d7c024c9c228a5b12fb57b9430e7d130b3d944bdcd50b4bdec206e5ea4082fcde159b20e8b856476fbd93b90b40e4aeb3ac40a18f9
|
data/.gitignore
ADDED
data/LICENSE.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2014 Stefan Penner and ember-cli contributors
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# deploy_s3
|
2
|
+
|
3
|
+
deploy_s3 evolved out of Movable Ink's deployments, which typically involved capistrano. Over time, the capistrano scripts got heavier and multiple datacenters were added, each with dozens of machines. We used Chef for provisioning, and found that it was impossible to keep capistrano up-to-date with the comings and goings of new machines. A separation was needed.
|
4
|
+
|
5
|
+
## The deploy_s3 workflow
|
6
|
+
|
7
|
+
The goal of deploy_s3 is to separate deployment into two parts: specifying that a new version of code should be deployed, and actually deploying that code to the machines that need it.
|
8
|
+
|
9
|
+
A typical deployment would look like this:
|
10
|
+
|
11
|
+
» ds3 production
|
12
|
+
Attempting to deploy d836d33
|
13
|
+
|
14
|
+
Difference of 6 new commit(s) between de0aed0 and d836d33:
|
15
|
+
|
16
|
+
d836d33 Michael Nutt 8 minutes ago ignore our own .deploy
|
17
|
+
9046842 Michael Nutt 8 minutes ago make bin executable
|
18
|
+
b2b4038 Michael Nutt 8 minutes ago clean up gemspec
|
19
|
+
e57b428 Michael Nutt 18 minutes ago refactoring
|
20
|
+
4fba6fa Michael Nutt 26 minutes ago add commit comparisons
|
21
|
+
349c4ce Michael Nutt 76 minutes ago first pass at sending to s3
|
22
|
+
|
23
|
+
Deploy? ([y]es / [n]o / [g]ithub) : y
|
24
|
+
Deployed d836d33
|
25
|
+
|
26
|
+
deploy_s3 relies on a `.deploy` file to tell it where to write the git hash. Right now it is tied to Amazon S3, but using fog it could send to any cloud provider.
|
27
|
+
|
28
|
+
Movable Ink uses Chef to push out new code, and Chef can simply read s3 for the revision to know exactly which version to deploy. This allows newly provisioned machines to get the latest deployed version while not requiring changes to the provisioning system every time the project is updated.
|
29
|
+
|
30
|
+
## License
|
31
|
+
|
32
|
+
The MIT License. See LICENSE.md.
|
data/Rakefile
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'rspec/core/rake_task'
|
2
|
+
require 'bundler/gem_tasks'
|
3
|
+
|
4
|
+
# Default directory to look in is `/specs`
|
5
|
+
# Run with `rake spec`
|
6
|
+
RSpec::Core::RakeTask.new(:spec) do |task|
|
7
|
+
task.rspec_opts = ['--color', '--format', 'nested']
|
8
|
+
end
|
9
|
+
|
10
|
+
task :default => :spec
|
data/bin/ds3
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'deploy_s3'
|
5
|
+
rescue LoadError
|
6
|
+
require 'rubygems'
|
7
|
+
require 'deploy_s3'
|
8
|
+
end
|
9
|
+
|
10
|
+
require 'optparse'
|
11
|
+
require 'highline/import'
|
12
|
+
require 'colorize'
|
13
|
+
|
14
|
+
options = {}
|
15
|
+
|
16
|
+
options[:environment] = ARGV.pop
|
17
|
+
|
18
|
+
options[:rev] = ENV['REV']
|
19
|
+
|
20
|
+
optparse = OptionParser.new do |opts|
|
21
|
+
opts.banner = "Usage: ds3 [environment] [options]"
|
22
|
+
|
23
|
+
opts.on("-c", "--config", String, "Location of .deploy configuration file") do |c|
|
24
|
+
options[:config_file] = c
|
25
|
+
end
|
26
|
+
|
27
|
+
opts.on("-r", "--rev", String, "Revision to deploy (can be sha, branch, etc)") do |r|
|
28
|
+
options[:rev] = r
|
29
|
+
end
|
30
|
+
end
|
31
|
+
optparse.parse!
|
32
|
+
|
33
|
+
unless options[:environment]
|
34
|
+
puts "Error: environment required"
|
35
|
+
puts optparse
|
36
|
+
exit 1
|
37
|
+
end
|
38
|
+
|
39
|
+
deploy = DeployS3::Main.new(options)
|
40
|
+
|
41
|
+
if deploy.up_to_date
|
42
|
+
puts "Everything up-to-date (#{deploy.environment.green}: #{deploy.remote_sha.green})"
|
43
|
+
exit 0
|
44
|
+
end
|
45
|
+
|
46
|
+
if deploy.remote_sha.nil?
|
47
|
+
puts "New deployment: #{deploy.local_sha}"
|
48
|
+
else
|
49
|
+
puts "Attempting to deploy #{deploy.local_sha.bold}", ""
|
50
|
+
|
51
|
+
commits = "#{deploy.commit_count} new commit(s)".green
|
52
|
+
puts "Difference of #{commits} between #{deploy.remote_sha} and #{deploy.local_sha}:", ""
|
53
|
+
|
54
|
+
if deploy.commit_count > 0
|
55
|
+
puts deploy.diff.yellow, ""
|
56
|
+
else
|
57
|
+
puts " There are no new commits.", ""
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
if deploy.older_local_sha
|
62
|
+
puts "WARNING: The commit you are deploying is older than what is currently on #{deploy.environment}. Missing commits: ".bold, ""
|
63
|
+
puts deploy.reverse_diff.red
|
64
|
+
puts ""
|
65
|
+
end
|
66
|
+
|
67
|
+
confirm = ask("Deploy? ([y]es / [n]o / [g]ithub) : ") { |yn| yn.limit = 1, yn.validate = /([yng]|yes|no|github)/i }
|
68
|
+
|
69
|
+
case confirm.downcase
|
70
|
+
when 'y', 'yes'
|
71
|
+
deploy.run!
|
72
|
+
|
73
|
+
puts "Deployed #{deploy.remote_sha}"
|
74
|
+
when 'g', 'github'
|
75
|
+
url = DeployS3::Remote.comparison(deploy.remote_sha, deploy.local_sha)
|
76
|
+
if url
|
77
|
+
if `which open`.size > 0
|
78
|
+
`open #{url}`
|
79
|
+
else
|
80
|
+
puts " Github: #{url}"
|
81
|
+
end
|
82
|
+
else
|
83
|
+
puts "Unrecognized repository; can't open github"
|
84
|
+
puts "(try `git config --get remote.origin.url`)"
|
85
|
+
exit 1
|
86
|
+
end
|
87
|
+
when 'n', 'no'
|
88
|
+
puts "Bye."
|
89
|
+
end
|
data/deploy_s3.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
$:.push File.expand_path("../lib", __FILE__)
|
2
|
+
require "deploy_s3/version"
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "deploy_s3"
|
6
|
+
s.version = DeployS3::VERSION
|
7
|
+
s.platform = Gem::Platform::RUBY
|
8
|
+
s.authors = ["Michael Nutt"]
|
9
|
+
s.email = ["michael@movableink.com"]
|
10
|
+
s.homepage = "https://github.com/movableink/deploy_s3"
|
11
|
+
s.summary = %q{Writes project deployment hash to s3 file}
|
12
|
+
s.licenses = "MIT"
|
13
|
+
s.description = %q{Separate out the deployment concerns from your application by using deploy_s3 to write your latest deployed git hash to s3. Then let your provisioning system (for instance, chef + deploy_revision provider) take care of actually deploying new code. deploy_s3 shows diffs between your current branch and the deployed revision.}
|
14
|
+
|
15
|
+
s.add_runtime_dependency "fog", "~> 1.25"
|
16
|
+
s.add_runtime_dependency "highline", "~> 1.6"
|
17
|
+
s.add_runtime_dependency "colorize", "~> 0.7"
|
18
|
+
|
19
|
+
s.add_development_dependency "rspec", "~> 2.5"
|
20
|
+
|
21
|
+
s.files = `git ls-files`.split("\n")
|
22
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
23
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
24
|
+
s.require_paths = ["lib"]
|
25
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'fog'
|
2
|
+
|
3
|
+
module DeployS3
|
4
|
+
class Main
|
5
|
+
def initialize(options)
|
6
|
+
config_path = options[:config_file] || "./.deploy"
|
7
|
+
@config = options[:config] || YAML::load_file(config_path)
|
8
|
+
|
9
|
+
raise "Missing s3: option in .deploy file" unless @config['s3']
|
10
|
+
|
11
|
+
@path = @config['s3'].split("/")
|
12
|
+
@bucket = @path.shift
|
13
|
+
@options = options
|
14
|
+
end
|
15
|
+
|
16
|
+
def environment
|
17
|
+
@options[:environment]
|
18
|
+
end
|
19
|
+
|
20
|
+
def save_sha
|
21
|
+
directory = connection.directories.get(@bucket)
|
22
|
+
file = directory.files.create(:key => key,
|
23
|
+
:body => local_sha)
|
24
|
+
@_remote_sha = nil
|
25
|
+
end
|
26
|
+
|
27
|
+
def run!
|
28
|
+
if @config['before_hook']
|
29
|
+
`#{@config['before_hook']}`
|
30
|
+
end
|
31
|
+
|
32
|
+
save_sha
|
33
|
+
|
34
|
+
if @config['after_hook']
|
35
|
+
`#{@config['after_hook']}`
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def connection
|
40
|
+
@_connection ||= Fog::Storage.new(:provider => 'AWS')
|
41
|
+
end
|
42
|
+
|
43
|
+
def remote_sha
|
44
|
+
return @_remote_sha if @_remote_sha
|
45
|
+
|
46
|
+
directory = connection.directories.get(@bucket)
|
47
|
+
file = directory.files.get(key)
|
48
|
+
@_remote_sha = file.body if file
|
49
|
+
end
|
50
|
+
|
51
|
+
def filename
|
52
|
+
[environment, 'sha'].join('.')
|
53
|
+
end
|
54
|
+
|
55
|
+
def key
|
56
|
+
[@path, filename].join("/")
|
57
|
+
end
|
58
|
+
|
59
|
+
def up_to_date
|
60
|
+
local_sha == remote_sha
|
61
|
+
end
|
62
|
+
|
63
|
+
def local_sha
|
64
|
+
rev = @options[:rev] || @config[:branch] || 'head'
|
65
|
+
execute("git rev-parse --verify --short #{rev}").chomp
|
66
|
+
end
|
67
|
+
|
68
|
+
def diff
|
69
|
+
execute "git log --pretty=format:' %h %<(20)%an %ar\t %s' -10 #{remote_sha}..#{local_sha}"
|
70
|
+
end
|
71
|
+
|
72
|
+
def reverse_diff
|
73
|
+
execute "git log --pretty=format:' %h %<(20)%an %ar\t %s' -10 #{local_sha}..#{remote_sha}"
|
74
|
+
end
|
75
|
+
|
76
|
+
def older_local_sha
|
77
|
+
return false unless remote_sha
|
78
|
+
execute("git merge-base --is-ancestor #{local_sha} #{remote_sha}") && $?.exitstatus == 0
|
79
|
+
end
|
80
|
+
|
81
|
+
def commit_count
|
82
|
+
diff.split("\n").size
|
83
|
+
end
|
84
|
+
|
85
|
+
protected
|
86
|
+
|
87
|
+
def execute(cmd)
|
88
|
+
`#{cmd}`
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module DeployS3
|
2
|
+
class Remote
|
3
|
+
def self.comparison(from, to)
|
4
|
+
origin_url = `git config --get remote.origin.url`.chomp
|
5
|
+
|
6
|
+
github_url = self.github_from_url origin_url
|
7
|
+
"#{github_url}/compare/#{from}...#{to}" if github_url
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.github_from_url(url)
|
11
|
+
if url =~ /git@github.com:(.*?).git/
|
12
|
+
"https://github.com/#{$1}"
|
13
|
+
elsif url =~ /(.*?):\/\/github.com\/(.*?).git/
|
14
|
+
"https://github.com/#{$1}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/deploy_s3.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DeployS3::Main do
|
4
|
+
let(:deploy) {
|
5
|
+
DeployS3::Main.new(:environment => 'production',
|
6
|
+
:config => {'s3' => 'my-bucket/deployments/foo'})
|
7
|
+
}
|
8
|
+
|
9
|
+
describe '#environment' do
|
10
|
+
it 'uses the passed environment' do
|
11
|
+
expect(deploy.environment).to eq('production')
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#filename' do
|
16
|
+
it 'computes the filename' do
|
17
|
+
expect(deploy.filename).to eql('production.sha')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#key' do
|
22
|
+
it 'computes the key' do
|
23
|
+
expect(deploy.key).to eq('deployments/foo/production.sha')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#diff' do
|
28
|
+
it 'uses git to find the commits between two shas' do
|
29
|
+
deploy.should_receive(:remote_sha).and_return("remote")
|
30
|
+
deploy.should_receive(:local_sha).and_return("local")
|
31
|
+
|
32
|
+
cmd = "git log --pretty=format:' %h %<(20)%an %ar\t %s' -10 remote..local"
|
33
|
+
deploy.should_receive(:execute).with(cmd)
|
34
|
+
|
35
|
+
deploy.diff
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '#up_to_date' do
|
40
|
+
it 'returns true when shas match' do
|
41
|
+
deploy.should_receive(:remote_sha).and_return("same")
|
42
|
+
deploy.should_receive(:local_sha).and_return("same")
|
43
|
+
expect(deploy.up_to_date).to be_true
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'returns true when shas differ' do
|
47
|
+
deploy.should_receive(:remote_sha).and_return("remote")
|
48
|
+
deploy.should_receive(:local_sha).and_return("local")
|
49
|
+
expect(deploy.up_to_date).to be_false
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: deploy_s3
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Michael Nutt
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-01-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: fog
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.25'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.25'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: highline
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.6'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.6'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: colorize
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.7'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.7'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.5'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '2.5'
|
69
|
+
description: Separate out the deployment concerns from your application by using deploy_s3
|
70
|
+
to write your latest deployed git hash to s3. Then let your provisioning system
|
71
|
+
(for instance, chef + deploy_revision provider) take care of actually deploying
|
72
|
+
new code. deploy_s3 shows diffs between your current branch and the deployed revision.
|
73
|
+
email:
|
74
|
+
- michael@movableink.com
|
75
|
+
executables:
|
76
|
+
- ds3
|
77
|
+
extensions: []
|
78
|
+
extra_rdoc_files: []
|
79
|
+
files:
|
80
|
+
- ".gitignore"
|
81
|
+
- LICENSE.md
|
82
|
+
- README.md
|
83
|
+
- Rakefile
|
84
|
+
- bin/ds3
|
85
|
+
- deploy_s3.gemspec
|
86
|
+
- lib/deploy_s3.rb
|
87
|
+
- lib/deploy_s3/main.rb
|
88
|
+
- lib/deploy_s3/remote.rb
|
89
|
+
- lib/deploy_s3/version.rb
|
90
|
+
- spec/deploy_s3/main_spec.rb
|
91
|
+
- spec/spec_helper.rb
|
92
|
+
homepage: https://github.com/movableink/deploy_s3
|
93
|
+
licenses:
|
94
|
+
- MIT
|
95
|
+
metadata: {}
|
96
|
+
post_install_message:
|
97
|
+
rdoc_options: []
|
98
|
+
require_paths:
|
99
|
+
- lib
|
100
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
requirements: []
|
111
|
+
rubyforge_project:
|
112
|
+
rubygems_version: 2.4.5
|
113
|
+
signing_key:
|
114
|
+
specification_version: 4
|
115
|
+
summary: Writes project deployment hash to s3 file
|
116
|
+
test_files:
|
117
|
+
- spec/deploy_s3/main_spec.rb
|
118
|
+
- spec/spec_helper.rb
|