harrison 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +4 -0
- data/IDEAS +1 -1
- data/README.md +7 -3
- data/harrison.gemspec +1 -1
- data/lib/harrison/deploy.rb +47 -0
- data/lib/harrison/version.rb +1 -1
- data/spec/unit/harrison/deploy_spec.rb +111 -0
- metadata +4 -4
data/CHANGELOG
CHANGED
data/IDEAS
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
Ideas:
|
2
2
|
------
|
3
|
+
[ ] Split deploy into distinct stages (e.g. pre-deploy, deploy, post-deploy) and ensure stage succeeds on each host before attempting next stage.
|
3
4
|
[ ] Allow more elaborate hosts config, e.g.: h.hosts = [ { host: '10.16.18.207', tags: %w(util migrate) } ]
|
4
5
|
[ ] Some kind of --dry-run option.
|
5
6
|
[ ] Allow deploy_via to include alternate user/connection options.
|
@@ -9,4 +10,3 @@ Ideas:
|
|
9
10
|
[ ] Something like a "status" command that shows what commit is live for env (on each host?)
|
10
11
|
[ ] Move artifacts out of pkg/ (and into like pkg/deployed) once they have been deployed? (Some sort of flag for the significant env?)
|
11
12
|
[ ] Include branch name in artifact file name.
|
12
|
-
[ ] Make --purge the default behavior for the package step.
|
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Simple artifact-based deployment for web applications.
|
4
4
|
|
5
|
-
[![Build Status](https://travis-ci.org/
|
5
|
+
[![Build Status](https://travis-ci.org/puppetlabs/harrison.svg?branch=master)](https://travis-ci.org/puppetlabs/harrison)
|
6
6
|
|
7
7
|
## Installation
|
8
8
|
|
@@ -26,7 +26,7 @@ First, create a Harrisonfile in the root of your project. Here's an example:
|
|
26
26
|
# Project-wide Config
|
27
27
|
Harrison.config do |h|
|
28
28
|
h.project = 'harrison'
|
29
|
-
h.git_src = "git@github.com:
|
29
|
+
h.git_src = "git@github.com:puppetlabs/harrison.git"
|
30
30
|
end
|
31
31
|
|
32
32
|
Harrison.package do |h|
|
@@ -157,12 +157,16 @@ else
|
|
157
157
|
end
|
158
158
|
```
|
159
159
|
|
160
|
+
You can use the `--keep` option (or set it in the deploy section of your Harrisonfile) to specify the total number of
|
161
|
+
deploys you want to retain on each server after a successful deployment. The default is to keep all previous deploys
|
162
|
+
around indefinitely.
|
163
|
+
|
160
164
|
There are some additional options available, run `harrison deploy --help` to see everything available.
|
161
165
|
|
162
166
|
|
163
167
|
## Contributing
|
164
168
|
|
165
|
-
1. Fork it ( https://github.com/
|
169
|
+
1. Fork it ( https://github.com/puppetlabs/harrison/fork )
|
166
170
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
167
171
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
168
172
|
4. Push to the branch (`git push origin my-new-feature`)
|
data/harrison.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ["Jesse Scott"]
|
10
10
|
spec.email = ["jesse@puppetlabs.com"]
|
11
11
|
spec.summary = %q{Simple artifact-based deployment for web applications.}
|
12
|
-
spec.homepage = "https://github.com/
|
12
|
+
spec.homepage = "https://github.com/puppetlabs/harrison"
|
13
13
|
spec.license = "Apache 2.0"
|
14
14
|
|
15
15
|
spec.files = `git ls-files -z`.split("\x0")
|
data/lib/harrison/deploy.rb
CHANGED
@@ -11,11 +11,13 @@ module Harrison
|
|
11
11
|
self.class.option_helper(:env)
|
12
12
|
self.class.option_helper(:base_dir)
|
13
13
|
self.class.option_helper(:deploy_via)
|
14
|
+
self.class.option_helper(:keep)
|
14
15
|
|
15
16
|
# Command line opts for this action. Will be merged with common opts.
|
16
17
|
arg_opts = [
|
17
18
|
[ :hosts, "List of remote hosts to deploy to. Can also be specified in Harrisonfile.", :type => :strings ],
|
18
19
|
[ :env, "Environment to deploy to. This can be examined in your Harrisonfile to calculate target hosts.", :type => :string ],
|
20
|
+
[ :keep, "Number of recent deploys to keep after a successful deploy. (Including the most recent deploy.) Defaults to keeping all deploys forever.", :type => :integer ],
|
19
21
|
]
|
20
22
|
|
21
23
|
super(arg_opts, opts)
|
@@ -88,12 +90,42 @@ module Harrison
|
|
88
90
|
# Run user supplied deploy code to restart server or whatever.
|
89
91
|
super
|
90
92
|
|
93
|
+
# Cleanup old releases if a keep value is set.
|
94
|
+
if (self.keep)
|
95
|
+
cleanup_deploys(self.keep)
|
96
|
+
cleanup_releases
|
97
|
+
end
|
98
|
+
|
91
99
|
close(self.host)
|
92
100
|
end
|
93
101
|
|
94
102
|
puts "Sucessfully deployed #{artifact} to #{hosts.join(', ')}."
|
95
103
|
end
|
96
104
|
|
105
|
+
def cleanup_deploys(limit)
|
106
|
+
# Grab a list of deploys to be removed.
|
107
|
+
purge_deploys = self.deploys.sort.reverse.slice(limit..-1) || []
|
108
|
+
|
109
|
+
if purge_deploys.size > 0
|
110
|
+
puts "Purging #{purge_deploys.size} old deploys on #{self.host}, keeping #{limit}..."
|
111
|
+
|
112
|
+
purge_deploys.each do |stale_deploy|
|
113
|
+
remote_exec("cd deploys && rm -f #{stale_deploy}")
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def cleanup_releases
|
119
|
+
# Figure out which releases need to be kept.
|
120
|
+
keep_releases = self.active_releases
|
121
|
+
|
122
|
+
self.releases.each do |release|
|
123
|
+
unless keep_releases.include?(release)
|
124
|
+
remote_exec("cd releases && rm -rf #{release}")
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
97
129
|
def close(host=nil)
|
98
130
|
if host
|
99
131
|
@_conns[host].close if @_conns && @_conns[host]
|
@@ -114,5 +146,20 @@ module Harrison
|
|
114
146
|
def remote_project_dir
|
115
147
|
"#{base_dir}/#{project}"
|
116
148
|
end
|
149
|
+
|
150
|
+
# Return a sorted list of deploys, unsorted.
|
151
|
+
def deploys
|
152
|
+
remote_exec("cd deploys && ls -1").split("\n")
|
153
|
+
end
|
154
|
+
|
155
|
+
# Return a list of all releases, unsorted.
|
156
|
+
def releases
|
157
|
+
remote_exec("cd releases && ls -1").split("\n")
|
158
|
+
end
|
159
|
+
|
160
|
+
# Return a list of releases with at least 1 deploy pointing to them, unsorted.
|
161
|
+
def active_releases
|
162
|
+
self.deploys.collect { |deploy| remote_exec("cd deploys && basename `readlink #{deploy}`") }.uniq
|
163
|
+
end
|
117
164
|
end
|
118
165
|
end
|
data/lib/harrison/version.rb
CHANGED
@@ -121,6 +121,17 @@ describe Harrison::Deploy do
|
|
121
121
|
expect(output).to include('host1', 'host2', 'host3')
|
122
122
|
end
|
123
123
|
|
124
|
+
it 'should clean up old releases if passed a --keep option' do
|
125
|
+
instance.keep = 3
|
126
|
+
|
127
|
+
expect(instance).to receive(:cleanup_deploys).with(3)
|
128
|
+
expect(instance).to receive(:cleanup_releases)
|
129
|
+
|
130
|
+
output = capture(:stdout) do
|
131
|
+
instance.run
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
124
135
|
context 'when deploying from a remote artifact source' do
|
125
136
|
before(:each) do
|
126
137
|
instance.artifact = 'test_user@test_host1:/tmp/test_artifact.tar.gz'
|
@@ -150,6 +161,39 @@ describe Harrison::Deploy do
|
|
150
161
|
end
|
151
162
|
end
|
152
163
|
|
164
|
+
describe '#cleanup_deploys' do
|
165
|
+
before(:each) do
|
166
|
+
allow(instance).to receive(:deploys).and_return([ 'deploy_1', 'deploy_2', 'deploy_3', 'deploy_4', 'deploy_5' ])
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'should remove deploys beyond the passed in limit' do
|
170
|
+
expect(instance).to receive(:remote_exec).with(/rm -f deploy_2/).and_return('')
|
171
|
+
expect(instance).to receive(:remote_exec).with(/rm -f deploy_1/).and_return('')
|
172
|
+
|
173
|
+
output = capture(:stdout) do
|
174
|
+
instance.cleanup_deploys(3)
|
175
|
+
end
|
176
|
+
|
177
|
+
expect(output).to include('purging', 'deploys', 'keeping 3')
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
describe '#cleanup_releases' do
|
182
|
+
before(:each) do
|
183
|
+
allow(instance).to receive(:releases).and_return([ 'release_1', 'release_2', 'release_3', 'release_4', 'release_5' ])
|
184
|
+
allow(instance).to receive(:active_releases).and_return([ 'release_3', 'release_4', 'release_5' ])
|
185
|
+
end
|
186
|
+
|
187
|
+
it 'should remove inactive releases' do
|
188
|
+
expect(instance).to receive(:remote_exec).with(/rm -rf release_1/).and_return('')
|
189
|
+
expect(instance).to receive(:remote_exec).with(/rm -rf release_2/).and_return('')
|
190
|
+
|
191
|
+
capture(:stdout) do
|
192
|
+
instance.cleanup_releases
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
153
197
|
describe '#close' do
|
154
198
|
before(:each) do
|
155
199
|
@test_host1_ssh = double(:ssh, 'closed?' => false)
|
@@ -204,5 +248,72 @@ describe Harrison::Deploy do
|
|
204
248
|
expect(instance.send(:remote_project_dir)).to include('/test_base_dir', 'test_project')
|
205
249
|
end
|
206
250
|
end
|
251
|
+
|
252
|
+
describe '#deploys' do
|
253
|
+
it 'should invoke ls in the correct directory on the remote server' do
|
254
|
+
expect(instance).to receive(:remote_exec).with(/deploys.*ls -1/).and_return('')
|
255
|
+
|
256
|
+
instance.send(:deploys)
|
257
|
+
end
|
258
|
+
|
259
|
+
it 'should return an array of deploys' do
|
260
|
+
expect(instance).to receive(:remote_exec).and_return("deploy_1\ndeploy_2\ndeploy_3\n")
|
261
|
+
|
262
|
+
deploys = instance.send(:deploys)
|
263
|
+
|
264
|
+
expect(deploys).to respond_to(:size)
|
265
|
+
expect(deploys.size).to be 3
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
describe '#releases' do
|
270
|
+
it 'should invoke ls in the correct directory on the remote server' do
|
271
|
+
expect(instance).to receive(:remote_exec).with(/releases.*ls -1/).and_return('')
|
272
|
+
|
273
|
+
instance.send(:releases)
|
274
|
+
end
|
275
|
+
|
276
|
+
it 'should return an array of releases' do
|
277
|
+
expect(instance).to receive(:remote_exec).and_return("release_1\nrelease_2\nrelease_3\n")
|
278
|
+
|
279
|
+
releases = instance.send(:releases)
|
280
|
+
|
281
|
+
expect(releases).to respond_to(:size)
|
282
|
+
expect(releases.size).to be 3
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
describe '#active_releases' do
|
287
|
+
before(:each) do
|
288
|
+
allow(instance).to receive(:remote_exec).with(/readlink/) do |cmd|
|
289
|
+
"release_" + /`readlink deploy_([0-9]+)`/.match(cmd).captures[0]
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
it 'should return an array of releases' do
|
294
|
+
expect(instance).to receive(:deploys).and_return([ 'deploy_3', 'deploy_4', 'deploy_5' ])
|
295
|
+
|
296
|
+
active_releases = instance.send(:active_releases)
|
297
|
+
|
298
|
+
expect(active_releases).to respond_to(:size)
|
299
|
+
expect(active_releases.size).to be 3
|
300
|
+
end
|
301
|
+
|
302
|
+
it 'should only return distinct releases' do
|
303
|
+
expect(instance).to receive(:deploys).and_return([ 'deploy_3', 'deploy_4', 'deploy_5', 'deploy_3' ])
|
304
|
+
|
305
|
+
active_releases = instance.send(:active_releases)
|
306
|
+
|
307
|
+
expect(active_releases.size).to be 3
|
308
|
+
end
|
309
|
+
|
310
|
+
it 'should return releases corresponding to given deploys' do
|
311
|
+
expect(instance).to receive(:deploys).and_return([ 'deploy_3' ])
|
312
|
+
|
313
|
+
active_releases = instance.send(:active_releases)
|
314
|
+
|
315
|
+
expect(active_releases).to include('release_3')
|
316
|
+
end
|
317
|
+
end
|
207
318
|
end
|
208
319
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: harrison
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-09-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: trollop
|
@@ -174,7 +174,7 @@ files:
|
|
174
174
|
- spec/unit/harrison/package_spec.rb
|
175
175
|
- spec/unit/harrison/ssh_spec.rb
|
176
176
|
- spec/unit/harrison_spec.rb
|
177
|
-
homepage: https://github.com/
|
177
|
+
homepage: https://github.com/puppetlabs/harrison
|
178
178
|
licenses:
|
179
179
|
- Apache 2.0
|
180
180
|
post_install_message:
|
@@ -195,7 +195,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
195
195
|
version: '0'
|
196
196
|
segments:
|
197
197
|
- 0
|
198
|
-
hash:
|
198
|
+
hash: 1433589896306598119
|
199
199
|
requirements: []
|
200
200
|
rubyforge_project:
|
201
201
|
rubygems_version: 1.8.29
|