deploy-cli 0.2.4
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 +3 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +21 -0
- data/Rakefile +6 -0
- data/Readme.md +98 -0
- data/bin/deploy +70 -0
- data/deploy-cli.gemspec +21 -0
- data/lib/deploy/runner.rb +180 -0
- data/lib/deploy/version.rb +5 -0
- metadata +83 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a8d3b48b9a55f7de6d23279d0878765da1a43e86
|
4
|
+
data.tar.gz: ac3d941865566ebdbfb2805c553e02f7c62953d0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0d8322cea80d48de105f8101f9581e257d32847fc30cc6237944aca2fc7ff4c058fee45403327829a02c6e3ba7fdd845b8d88e5a40c9871928a409f46c60a348
|
7
|
+
data.tar.gz: b7daa65860485d737dce1f5894c9d8894269fc3c177bd91fc69178d3645849689b4c2494c84fec292117d639b465a4be72e89dacd92541d4b4609b964669247e
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
data/Rakefile
ADDED
data/Readme.md
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
# deploy
|
2
|
+
|
3
|
+
Deploy from a spec.
|
4
|
+
|
5
|
+
Does this by simply logging into each machine and do a `git pull origin`
|
6
|
+
followed by a `git rebase origin/<branch>`. Other strategies will follow, like
|
7
|
+
using rsync.
|
8
|
+
|
9
|
+
`before` and `after` actions can be triggered to, for example, clean up caches.
|
10
|
+
|
11
|
+
**This is very much a work in progress** to scratch an itch. Rubygems makes it
|
12
|
+
a very convenient way to share the scripts, even if it's not ready to be used en
|
13
|
+
masse ;-)
|
14
|
+
|
15
|
+
|
16
|
+
### Installation
|
17
|
+
|
18
|
+
gem install deploy-cli
|
19
|
+
|
20
|
+
|
21
|
+
### Usage
|
22
|
+
|
23
|
+
$ deploy
|
24
|
+
Commands:
|
25
|
+
deploy to [STAGE] # Runs a deployment
|
26
|
+
deploy help [COMMAND] # Describe available commands or one specific command
|
27
|
+
deploy version # Show the current version
|
28
|
+
|
29
|
+
|
30
|
+
This script assume there's either a `deploy.yaml` or a `deploy.rb` file on the
|
31
|
+
current directory. If not you can pass it with `--file deploy.rb`.
|
32
|
+
|
33
|
+
|
34
|
+
### Sample yaml spec (deploy.yaml)
|
35
|
+
|
36
|
+
```yaml
|
37
|
+
### Working yaml code
|
38
|
+
|
39
|
+
default: &SITE
|
40
|
+
user: deploy
|
41
|
+
before:
|
42
|
+
- echo "Started at `date`"
|
43
|
+
after:
|
44
|
+
- echo "Completed at `date`"
|
45
|
+
|
46
|
+
notifications:
|
47
|
+
email:
|
48
|
+
- me@example.com
|
49
|
+
slack:
|
50
|
+
service: token-goes-here
|
51
|
+
channel: "#deployments"
|
52
|
+
|
53
|
+
|
54
|
+
|
55
|
+
production:
|
56
|
+
<<: *SITE
|
57
|
+
path: /var/www/vhosts/example.com
|
58
|
+
branch: master
|
59
|
+
servers:
|
60
|
+
- web-01.example.com
|
61
|
+
- web-02.example.com
|
62
|
+
|
63
|
+
|
64
|
+
stage:
|
65
|
+
<<: *SITE
|
66
|
+
branch: dev
|
67
|
+
path: /var/www/vhosts/stage.example.com
|
68
|
+
servers:
|
69
|
+
- stage-01.example.com
|
70
|
+
|
71
|
+
```
|
72
|
+
|
73
|
+
### Pseudo ruby spec (deploy.rb)
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
### Pseudo code for a deploy DSL
|
77
|
+
|
78
|
+
stage :stage do
|
79
|
+
branch "master"
|
80
|
+
user "deploy"
|
81
|
+
path "/var/www/vhosts/stage.example.com"
|
82
|
+
servers [
|
83
|
+
"web-01.example.com",
|
84
|
+
"web-02.example.com",
|
85
|
+
]
|
86
|
+
|
87
|
+
notify :slack do
|
88
|
+
token ENV["SLACK_TOKEN"]
|
89
|
+
channel "#deployments"
|
90
|
+
message "#{s.user} deployed commit #{s.commit} to #{s.stage}."
|
91
|
+
emoji ":rocket:"
|
92
|
+
end
|
93
|
+
|
94
|
+
hook :before "echo 'Started at $(date)'"
|
95
|
+
hook :after "./clean-caches"
|
96
|
+
hook :after "echo 'Completed at $(date)'"
|
97
|
+
end
|
98
|
+
```
|
data/bin/deploy
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
3
|
+
|
4
|
+
require "thor"
|
5
|
+
require "yaml"
|
6
|
+
require "json"
|
7
|
+
require "deploy"
|
8
|
+
|
9
|
+
module Deploy
|
10
|
+
class Cli < Thor
|
11
|
+
class_option :file
|
12
|
+
|
13
|
+
desc "version", "Show the current version"
|
14
|
+
def version
|
15
|
+
puts "v#{VERSION}"
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "show STAGE", "Shows the deployment spec for STAGE"
|
19
|
+
def show stage
|
20
|
+
file = _find
|
21
|
+
data = YAML.load_file(file)
|
22
|
+
spec = data[stage.to_s]
|
23
|
+
puts JSON.dump(spec)
|
24
|
+
end
|
25
|
+
|
26
|
+
desc "to STAGE", "Deploys to STAGE"
|
27
|
+
def to stage
|
28
|
+
file = _find
|
29
|
+
abort "Error: Could not find a deploy file." unless file
|
30
|
+
if File.extname(file) == ".rb"
|
31
|
+
_from_ruby file, stage
|
32
|
+
elsif File.extname(file) == ".yaml"
|
33
|
+
_from_yaml file, stage
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def method_missing name
|
38
|
+
to name
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
def _find
|
43
|
+
return options[:file] if options[:file]
|
44
|
+
|
45
|
+
files = ["deploy.yaml"]
|
46
|
+
dirs = [ENV["HOME"], ".", "/etc/deploy-cli"]
|
47
|
+
dirs.each do |dir|
|
48
|
+
files.each do |file|
|
49
|
+
path = "#{dir}/#{file}"
|
50
|
+
if File.exists? path
|
51
|
+
return path
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
return false
|
56
|
+
end
|
57
|
+
|
58
|
+
def _from_yaml file, stage
|
59
|
+
data = YAML.load_file(file)
|
60
|
+
spec = data[stage.to_s]
|
61
|
+
Deploy::Runner.run spec
|
62
|
+
end
|
63
|
+
|
64
|
+
def _from_ruby file, stage
|
65
|
+
abort "Not ready yet"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
Deploy::Cli.start(ARGV)
|
data/deploy-cli.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
|
2
|
+
|
3
|
+
require "deploy/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "deploy-cli"
|
7
|
+
spec.version = Deploy::VERSION
|
8
|
+
spec.summary = "Deploy from a spec."
|
9
|
+
spec.description = "Deploy from a spec"
|
10
|
+
spec.homepage = "https://github.com/ptdorf/deploy-cli"
|
11
|
+
spec.authors = ["ptdorf"]
|
12
|
+
spec.email = ["ptdorf@gmail.com"]
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files`.split $/
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.require_paths = ["lib"]
|
18
|
+
|
19
|
+
spec.add_dependency "thor"
|
20
|
+
spec.add_development_dependency "rake"
|
21
|
+
end
|
@@ -0,0 +1,180 @@
|
|
1
|
+
require "date"
|
2
|
+
require "json"
|
3
|
+
|
4
|
+
module Deploy
|
5
|
+
|
6
|
+
class Runner
|
7
|
+
BLACK = "1"
|
8
|
+
BLUE = "38;5;27;1"
|
9
|
+
|
10
|
+
def self.run(spec)
|
11
|
+
self.new(spec).deploy
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(spec)
|
15
|
+
@spec = spec
|
16
|
+
end
|
17
|
+
|
18
|
+
def deploy
|
19
|
+
@before = @spec["before"]
|
20
|
+
@after = @spec["after"]
|
21
|
+
@cleanup = @spec["cleanup"]
|
22
|
+
|
23
|
+
ok = true
|
24
|
+
tasks "BEFORE", @before
|
25
|
+
|
26
|
+
@spec["servers"].each do |server|
|
27
|
+
log "[Server #{server}]", BLUE
|
28
|
+
|
29
|
+
ok = ok && justdoit(server)
|
30
|
+
|
31
|
+
@commit = ssh(server, "git log -1 --pretty=%s")
|
32
|
+
@author = ssh(server, "git log -1 --pretty=%an")
|
33
|
+
@hash = ssh(server, "git log -1 --pretty=%h")
|
34
|
+
@date = ssh(server, "git log -1 --pretty=%ad")
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
tasks "AFTER", @after if ok
|
39
|
+
tasks "CLEANUP", @cleanup
|
40
|
+
|
41
|
+
notify
|
42
|
+
end
|
43
|
+
|
44
|
+
def tasks(type, tasks)
|
45
|
+
return unless tasks
|
46
|
+
log "#{type} ACTIONS"
|
47
|
+
if tasks.kind_of? Array
|
48
|
+
tasks.each do |t|
|
49
|
+
task t
|
50
|
+
end
|
51
|
+
else
|
52
|
+
task tasks
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def task(cmd)
|
57
|
+
puts "$ #{cmd}"
|
58
|
+
system(cmd)
|
59
|
+
puts
|
60
|
+
end
|
61
|
+
|
62
|
+
def justdoit(server)
|
63
|
+
log "CURRENT STATUS"
|
64
|
+
status = ssh(server, "git status")
|
65
|
+
puts status
|
66
|
+
puts
|
67
|
+
# return unless status.include? "working directory clean"
|
68
|
+
|
69
|
+
log "CURRENT RELEASE"
|
70
|
+
puts ssh(server, "git log -1")
|
71
|
+
puts
|
72
|
+
|
73
|
+
# TODO Figure this out
|
74
|
+
log "PULLING FROM ORIGIN"
|
75
|
+
fetched = ssh(server, "git fetch #{@spec["remote"]}")
|
76
|
+
puts fetched == "" ? "(none)" : fetched
|
77
|
+
puts
|
78
|
+
# return unless fetched.size > 0
|
79
|
+
|
80
|
+
log "REBASING"
|
81
|
+
rebased = ssh(server, "git rebase #{@spec["remote"]}/#{@spec["branch"]}")
|
82
|
+
puts rebased
|
83
|
+
puts
|
84
|
+
# return if rebased.include? "is up to date"
|
85
|
+
|
86
|
+
log "NEW STATUS"
|
87
|
+
status = ssh(server, "git status")
|
88
|
+
puts status
|
89
|
+
puts
|
90
|
+
|
91
|
+
log "NEW RELEASE"
|
92
|
+
puts ssh(server, "git log -1")
|
93
|
+
puts
|
94
|
+
|
95
|
+
true
|
96
|
+
end
|
97
|
+
|
98
|
+
def notify
|
99
|
+
return unless @spec["notifications"]
|
100
|
+
return unless @spec["notifications"]["slack"]
|
101
|
+
|
102
|
+
site = @spec["site"]
|
103
|
+
service = @spec["notifications"]["slack"]["service"]
|
104
|
+
channel = @spec["notifications"]["slack"]["channel"]
|
105
|
+
url = "https://hooks.slack.com/services/#{service}"
|
106
|
+
|
107
|
+
payload = {
|
108
|
+
"channel" => channel,
|
109
|
+
"username" => "Deployment #{DateTime.now}",
|
110
|
+
"text" => "New deployment to <#{site}>",
|
111
|
+
"icon_emoji" => ":dotser:",
|
112
|
+
"attachments" => [
|
113
|
+
{
|
114
|
+
# "fallback" => "[fallback] Required text summary of the attachment that is shown by clients that understand attachments but choose not to show them.",
|
115
|
+
# "pretext" => "[pretext] Optional text that should appear above the formatted data",
|
116
|
+
# "text" => "[text] Optional text that should appear within the attachment",
|
117
|
+
"_color" => "warning",
|
118
|
+
"fields" => [
|
119
|
+
{
|
120
|
+
"title" => "Commit",
|
121
|
+
"value" => @commit,
|
122
|
+
"short" => true,
|
123
|
+
},
|
124
|
+
{
|
125
|
+
"title" => "Date",
|
126
|
+
"value" => @date,
|
127
|
+
"short" => true,
|
128
|
+
},
|
129
|
+
{
|
130
|
+
"title" => "Author",
|
131
|
+
"value" => @author,
|
132
|
+
"short" => true,
|
133
|
+
},
|
134
|
+
{
|
135
|
+
"title" => "Hash",
|
136
|
+
"value" => @hash,
|
137
|
+
"short" => true,
|
138
|
+
},
|
139
|
+
{
|
140
|
+
"title" => "Site",
|
141
|
+
"value" => site,
|
142
|
+
"short" => true,
|
143
|
+
},
|
144
|
+
{
|
145
|
+
"title" => "Branch",
|
146
|
+
"value" => @spec["branch"],
|
147
|
+
"short" => true,
|
148
|
+
},
|
149
|
+
]
|
150
|
+
}
|
151
|
+
]
|
152
|
+
}.to_json
|
153
|
+
|
154
|
+
# puts "curl -s -X POST --data-urlencode 'payload=#{payload}' #{url}"
|
155
|
+
`curl -s -X POST --data-urlencode 'payload=#{payload}' #{url}`
|
156
|
+
end
|
157
|
+
|
158
|
+
private
|
159
|
+
def ssh(server, cmd)
|
160
|
+
full = "ssh -A #{@spec['user']}@#{server}"
|
161
|
+
full += " 'cd #{@spec['path']} && #{cmd}'"
|
162
|
+
output = `#{full}`.chomp
|
163
|
+
code = $?.exitstatus
|
164
|
+
abort "Command <#{full}> failed with status #{code}." if code != 0
|
165
|
+
output
|
166
|
+
end
|
167
|
+
|
168
|
+
# def which_branch
|
169
|
+
# ssh "git rev-parse --abbrev-ref HEAD"
|
170
|
+
# end
|
171
|
+
#
|
172
|
+
# def which_remote
|
173
|
+
# ssh "git rev-parse --abbrev-ref HEAD"
|
174
|
+
# end
|
175
|
+
|
176
|
+
def log(message, color = BLACK)
|
177
|
+
puts "\033[#{color}m#{message}\033[0m"
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
metadata
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: deploy-cli
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.4
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- ptdorf
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-08-29 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: thor
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: Deploy from a spec
|
42
|
+
email:
|
43
|
+
- ptdorf@gmail.com
|
44
|
+
executables:
|
45
|
+
- deploy
|
46
|
+
extensions: []
|
47
|
+
extra_rdoc_files: []
|
48
|
+
files:
|
49
|
+
- ".gitignore"
|
50
|
+
- Gemfile
|
51
|
+
- Gemfile.lock
|
52
|
+
- Rakefile
|
53
|
+
- Readme.md
|
54
|
+
- bin/deploy
|
55
|
+
- deploy-cli.gemspec
|
56
|
+
- lib/deploy.rb
|
57
|
+
- lib/deploy/runner.rb
|
58
|
+
- lib/deploy/version.rb
|
59
|
+
homepage: https://github.com/ptdorf/deploy-cli
|
60
|
+
licenses:
|
61
|
+
- MIT
|
62
|
+
metadata: {}
|
63
|
+
post_install_message:
|
64
|
+
rdoc_options: []
|
65
|
+
require_paths:
|
66
|
+
- lib
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
requirements: []
|
78
|
+
rubyforge_project:
|
79
|
+
rubygems_version: 2.6.6
|
80
|
+
signing_key:
|
81
|
+
specification_version: 4
|
82
|
+
summary: Deploy from a spec.
|
83
|
+
test_files: []
|