harrison 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +10 -0
- data/README.md +66 -23
- data/lib/harrison/package.rb +59 -11
- data/lib/harrison/version.rb +1 -1
- data/spec/unit/harrison/package_spec.rb +44 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fbd178c641c35846dfc9376babcf2af16ae15bbe
|
4
|
+
data.tar.gz: e27ddc623943e272a38f0fb72f69b1e312a4618e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ddabbccb099cf66d35df61f1b58589cff24eed24906f238b0785d3a4609cc165d6f91fe3eea1f51cb41c0d92f704d9424cacd4f7b03f641f71c9f4fa47103d47
|
7
|
+
data.tar.gz: 81cbf3d1f671f8fcd952756b81baecd9136dd694cdb33a3d3fdc1a6ab12029fa49cfbfd75cdf17d42c156f0bfba5de448dbca7a60e51346bc79e1832a37af384
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
0.6.0
|
2
|
+
-------------------
|
3
|
+
- Added ability to package from forks. When packaging from HEAD or a branch,
|
4
|
+
harrison will now check to see if that branch is tracking a remote branch.
|
5
|
+
If so, it will attempt to package code from that remote. If the branch
|
6
|
+
being packaged is not tracking a remote branch, or if what is being packaged
|
7
|
+
is not a branch, harrison will look for a remote named "origin" and package
|
8
|
+
from there. Lastly, if there is not a remote named "origin", it will package
|
9
|
+
from the configured "git_src".
|
10
|
+
|
1
11
|
0.5.0
|
2
12
|
-------------------
|
3
13
|
- BREAKING: Bumped net-ssh to 3.2.x which results in Harrison now
|
data/README.md
CHANGED
@@ -119,8 +119,9 @@ Harrison.deploy do |h|
|
|
119
119
|
end
|
120
120
|
```
|
121
121
|
|
122
|
-
Next, ensure that your SSH key is authorized to log in as the `user` you have
|
123
|
-
the Harrisonfile for each task. (Or be ready to type the password
|
122
|
+
Next, ensure that your SSH key is authorized to log in as the `user` you have
|
123
|
+
specified in the Harrisonfile for each task. (Or be ready to type the password
|
124
|
+
a lot. :weary:)
|
124
125
|
|
125
126
|
### Building a Release
|
126
127
|
|
@@ -130,18 +131,25 @@ Use the `harrison package` command:
|
|
130
131
|
$ harrison package
|
131
132
|
```
|
132
133
|
|
133
|
-
By default this will build and package `HEAD` of your current branch. You may
|
134
|
-
build using the `--commit` option:
|
134
|
+
By default this will build and package `HEAD` of your current branch. You may
|
135
|
+
specify another commit to build using the `--commit` option:
|
135
136
|
|
136
137
|
```
|
137
138
|
$ harrison package --commit mybranch
|
138
139
|
```
|
139
140
|
|
140
|
-
The `--commit` option understands anything that `git rev-parse` understands.
|
141
|
-
reference must be pushed to
|
142
|
-
you can build it.*
|
141
|
+
The `--commit` option understands anything that `git rev-parse` understands.
|
142
|
+
*NOTE: The commit you reference must be pushed to a repository accessible by
|
143
|
+
your build server before you can build it.*
|
143
144
|
|
144
|
-
|
145
|
+
By default, harrison will automatically detect the correct remote repository to
|
146
|
+
attempt to package from by first checking to see if the branch being deployed
|
147
|
+
is tracking a specific remote and if not, looking for a remote named "origin"
|
148
|
+
to package from. If neither of these is available, it will fall back to the
|
149
|
+
git\_src configured in your Harrisonfile.
|
150
|
+
|
151
|
+
The packaged release artifact will, by default, be saved into a local 'pkg'
|
152
|
+
subfolder:
|
145
153
|
|
146
154
|
```
|
147
155
|
$ harrison package
|
@@ -149,8 +157,8 @@ Packaging 5a547d8 for "harrison" on build-server.example.com...
|
|
149
157
|
Sucessfully packaged 5a547d8 to pkg/20140711170226-5a547d8.tar.gz
|
150
158
|
```
|
151
159
|
|
152
|
-
You can set the destination on the command line with the `--destination`
|
153
|
-
specify a new default in your Harrisonfile:
|
160
|
+
You can set the destination on the command line with the `--destination`
|
161
|
+
option, or specify a new default in your Harrisonfile:
|
154
162
|
|
155
163
|
```
|
156
164
|
h.destination = '/tmp'
|
@@ -162,16 +170,18 @@ You can also specify a remote destination:
|
|
162
170
|
h.destination = 'jesse@artifact-host.example.com:/tmp/artifacts'
|
163
171
|
```
|
164
172
|
|
165
|
-
The username is optional and, if omitted, the build user will be used. *NOTE:
|
166
|
-
must have already accepted the SSH host key of the
|
167
|
-
artifact.*
|
173
|
+
The username is optional and, if omitted, the build user will be used. *NOTE:
|
174
|
+
Your build server must have already accepted the SSH host key of the
|
175
|
+
destination server in order to transfer the artifact.*
|
168
176
|
|
169
|
-
There are some additional options available, run `harrison package --help` to
|
177
|
+
There are some additional options available, run `harrison package --help` to
|
178
|
+
see everything available.
|
170
179
|
|
171
180
|
|
172
181
|
### Deploying a Release
|
173
182
|
|
174
|
-
Use the `harrison deploy` command passing the artifact to be deployed as an
|
183
|
+
Use the `harrison deploy` command passing the artifact to be deployed as an
|
184
|
+
argument:
|
175
185
|
|
176
186
|
```
|
177
187
|
$ harrison deploy pkg/20140711170226-5a547d8.tar.gz
|
@@ -183,10 +193,11 @@ You can also deploy from a remote artifact source:
|
|
183
193
|
$ harrison deploy jesse@artifact-host.example.com:/tmp/artifacts/20140711170226-5a547d8.tar.gz
|
184
194
|
```
|
185
195
|
|
186
|
-
*NOTE: Each target server must have already accepted the SSH host key of the
|
187
|
-
transfer the artifact.*
|
196
|
+
*NOTE: Each target server must have already accepted the SSH host key of the
|
197
|
+
source server in order to transfer the artifact.*
|
188
198
|
|
189
|
-
By default, the artifact will be deployed to the list of hosts defined in your
|
199
|
+
By default, the artifact will be deployed to the list of hosts defined in your
|
200
|
+
Harrisonfile.
|
190
201
|
|
191
202
|
You can override the target hosts by passing a `--hosts` option:
|
192
203
|
|
@@ -200,7 +211,8 @@ You can also pass an `--env` option to deploy into multi-stage environments:
|
|
200
211
|
$ harrison deploy pkg/20140711170226-5a547d8.tar.gz --env prod
|
201
212
|
```
|
202
213
|
|
203
|
-
This value can then be tested to alter the default target hosts in your
|
214
|
+
This value can then be tested to alter the default target hosts in your
|
215
|
+
Harrisonfile:
|
204
216
|
|
205
217
|
```ruby
|
206
218
|
if h.env =~ /prod/
|
@@ -210,11 +222,42 @@ else
|
|
210
222
|
end
|
211
223
|
```
|
212
224
|
|
213
|
-
|
214
|
-
|
215
|
-
|
225
|
+
The hosts option in your Harrisonfile can also be defined as a block of code
|
226
|
+
which will be evaluated in order to calculate a list of hosts to deploy to.
|
227
|
+
The code block should evaluate to an array of hostnames, for example:
|
228
|
+
|
229
|
+
```ruby
|
230
|
+
h.hosts = Proc.new do |h; client, response, instances|
|
231
|
+
require 'aws-sdk'
|
232
|
+
|
233
|
+
AWS.config(region: 'us-west-2')
|
234
|
+
|
235
|
+
client = AWS.ec2.client
|
236
|
+
|
237
|
+
response = client.describe_instances(filters: [
|
238
|
+
{ name: 'tag:Name', values: ["app-server-*.#{h.env}.example.com"] },
|
239
|
+
{ name: 'instance-state-name', values: ['running'] },
|
240
|
+
])
|
241
|
+
|
242
|
+
instances = response.data[:reservation_set].flat_map do |r|
|
243
|
+
r[:instances_set] && r[:instances_set].collect do |i|
|
244
|
+
name_tag = i[:tag_set].find { |tag| tag[:key] == 'Name' }
|
245
|
+
|
246
|
+
name_tag[:value]
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
instances
|
251
|
+
end
|
252
|
+
```
|
253
|
+
|
254
|
+
You can use the `--keep` option (or set it in the deploy section of your
|
255
|
+
Harrisonfile) to specify the total number of deploys you want to retain on each
|
256
|
+
server after a successful deployment. The default is to keep all previous
|
257
|
+
deploys around indefinitely.
|
216
258
|
|
217
|
-
There are some additional options available, run `harrison deploy --help` to
|
259
|
+
There are some additional options available, run `harrison deploy --help` to
|
260
|
+
see everything available.
|
218
261
|
|
219
262
|
|
220
263
|
## Contributing
|
data/lib/harrison/package.rb
CHANGED
@@ -33,33 +33,54 @@ module Harrison
|
|
33
33
|
def run(&block)
|
34
34
|
return super if block_given?
|
35
35
|
|
36
|
+
# Find the URL of the remote in case it differs from git_src.
|
37
|
+
remote_url = find_remote(self.commit)
|
38
|
+
|
36
39
|
# Resolve commit ref to an actual short SHA.
|
37
40
|
resolve_commit!
|
38
41
|
|
39
|
-
puts "Packaging #{commit} for \"#{project}\" on #{host}..."
|
42
|
+
puts "Packaging #{commit} from #{remote_url} for \"#{project}\" on #{host}..."
|
40
43
|
|
41
44
|
# Make sure the folder to save the artifact to locally exists.
|
42
45
|
ensure_destination(destination)
|
43
46
|
|
44
|
-
#
|
45
|
-
|
46
|
-
|
47
|
-
# Make a build folder of the target commit.
|
48
|
-
remote_exec("rm -rf #{artifact_name(commit)} && cp -a cached #{artifact_name(commit)}")
|
47
|
+
# To avoid collisions, we use a version of the full URL as remote name.
|
48
|
+
remote_cache_name = remote_url.gsub(/[^a-z0-9_]/i, '_')
|
49
49
|
|
50
|
-
#
|
51
|
-
remote_exec
|
50
|
+
# Fetch/clone git repo on remote host.
|
51
|
+
remote_exec <<~ENDCMD
|
52
|
+
if [ -d cached ]
|
53
|
+
then
|
54
|
+
cd cached
|
55
|
+
if [ -d .git/refs/remotes/#{remote_cache_name} ]
|
56
|
+
then
|
57
|
+
git fetch #{remote_cache_name} -p
|
58
|
+
else
|
59
|
+
git remote add -f #{remote_cache_name} #{remote_url}
|
60
|
+
fi
|
61
|
+
else
|
62
|
+
git clone -o #{remote_cache_name} #{remote_url} cached
|
63
|
+
fi
|
64
|
+
ENDCMD
|
65
|
+
|
66
|
+
build_dir = remote_cache_name + '-' + artifact_name(commit)
|
67
|
+
|
68
|
+
# Clean up any stale build folder of the target remote/commit.
|
69
|
+
remote_exec("rm -rf #{build_dir} && mkdir -p #{build_dir}")
|
70
|
+
|
71
|
+
# Check out target commit into the build_dir.
|
72
|
+
remote_exec("cd cached && GIT_WORK_TREE=../#{build_dir} git checkout --detach -f #{commit} && git checkout -f -") # TODO: When git is upgraded: --ignore-other-worktrees
|
52
73
|
|
53
74
|
# Run user supplied build code in the context of the checked out code.
|
54
75
|
begin
|
55
|
-
@_remote_context = "#{remote_project_dir}/package/#{
|
76
|
+
@_remote_context = "#{remote_project_dir}/package/#{build_dir}"
|
56
77
|
super
|
57
78
|
ensure
|
58
79
|
@_remote_context = nil
|
59
80
|
end
|
60
81
|
|
61
82
|
# Package build folder into tgz.
|
62
|
-
remote_exec("rm -f #{artifact_name(commit)}.tar.gz && cd #{
|
83
|
+
remote_exec("rm -f #{artifact_name(commit)}.tar.gz && cd #{build_dir} && tar #{excludes_for_tar} -czf ../#{artifact_name(commit)}.tar.gz .")
|
63
84
|
|
64
85
|
if match = remote_regex.match(destination)
|
65
86
|
# Copy artifact to remote destination.
|
@@ -73,7 +94,8 @@ module Harrison
|
|
73
94
|
end
|
74
95
|
|
75
96
|
if purge
|
76
|
-
remote_exec("rm -rf #{
|
97
|
+
remote_exec("rm -rf #{build_dir}")
|
98
|
+
remote_exec("rm #{artifact_name(commit)}.tar.gz")
|
77
99
|
end
|
78
100
|
|
79
101
|
puts "Sucessfully packaged #{commit} to #{destination}/#{artifact_name(commit)}.tar.gz"
|
@@ -85,6 +107,32 @@ module Harrison
|
|
85
107
|
"#{remote_dir}/#{project}"
|
86
108
|
end
|
87
109
|
|
110
|
+
def find_remote(ref)
|
111
|
+
remote = nil
|
112
|
+
remote_url = nil
|
113
|
+
|
114
|
+
catch :failure do
|
115
|
+
# If it's a branch, try to resolve what it's tracking.
|
116
|
+
# This will exit non-zero (and throw :failure) if the ref is
|
117
|
+
# not a branch.
|
118
|
+
remote = exec("git rev-parse --symbolic-full-name #{ref}@{upstream} 2>/dev/null")&.match(/\Arefs\/remotes\/(.+)\/.+\Z/i)&.captures.first
|
119
|
+
end
|
120
|
+
|
121
|
+
# Fallback to 'origin' if not deploying a branch with a tracked
|
122
|
+
# upstream.
|
123
|
+
remote ||= 'origin'
|
124
|
+
|
125
|
+
catch :failure do
|
126
|
+
# Look for a URL for whatever remote we have. git-config exits
|
127
|
+
# non-zero if the requested value doesn't exist.
|
128
|
+
remote_url = exec("git config remote.#{remote}.url 2>/dev/null")
|
129
|
+
end
|
130
|
+
|
131
|
+
# If we found a remote_url, return that, otherwise fall back to
|
132
|
+
# configured git_src.
|
133
|
+
return remote_url || self.git_src
|
134
|
+
end
|
135
|
+
|
88
136
|
def resolve_commit!
|
89
137
|
self.commit = exec("git rev-parse --short #{self.commit} 2>/dev/null")
|
90
138
|
end
|
data/lib/harrison/version.rb
CHANGED
@@ -4,6 +4,7 @@ describe Harrison::Package do
|
|
4
4
|
before(:all) do
|
5
5
|
Harrison.class_variable_set(:@@config, Harrison::Config.new)
|
6
6
|
Harrison.config.project = 'test_project'
|
7
|
+
Harrison.config.git_src = 'git_src_from_config'
|
7
8
|
end
|
8
9
|
|
9
10
|
let(:instance) do
|
@@ -97,6 +98,49 @@ describe Harrison::Package do
|
|
97
98
|
end
|
98
99
|
end
|
99
100
|
|
101
|
+
describe '#find_remote' do
|
102
|
+
before(:each) do
|
103
|
+
allow(instance).to receive(:exec).with(/^git config remote.my_remote.url/).and_return('my_remote_url')
|
104
|
+
end
|
105
|
+
|
106
|
+
context 'when deploying a branch that is tracking a remote branch' do
|
107
|
+
before(:each) do
|
108
|
+
allow(instance).to receive(:exec).with(/^git rev-parse/).and_return('refs/remotes/my_remote/branch')
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'should return url for tracked remote' do
|
112
|
+
expect(instance.send(:find_remote, 'HEAD')).to eq 'my_remote_url'
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
context 'when deploying a tree-ish with no remote tracking' do
|
117
|
+
before(:each) do
|
118
|
+
allow(instance).to receive(:exec).with(/^git rev-parse/).and_throw(:failure)
|
119
|
+
end
|
120
|
+
|
121
|
+
context 'when an \'origin\' remote exists' do
|
122
|
+
before(:each) do
|
123
|
+
allow(instance).to receive(:exec).with(/^git config remote.origin.url/).and_return('origin_url')
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'should return url for origin' do
|
127
|
+
expect(instance.send(:find_remote, 'HEAD')).to eq 'origin_url'
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context 'when no \'origin\' remote exists' do
|
132
|
+
before(:each) do
|
133
|
+
allow(instance).to receive(:exec).with(/^git config remote.origin.url/).and_throw(:failure)
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'should return the configured git_src' do
|
137
|
+
# git_src is defined globally at the top of this file
|
138
|
+
expect(instance.send(:find_remote, 'HEAD')).to eq 'git_src_from_config'
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
100
144
|
describe '#resolve_commit!' do
|
101
145
|
it 'should resolve commit reference to a short sha using git rev-parse' do
|
102
146
|
instance.commit = 'giant'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: harrison
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jesse Scott
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-09-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: trollop
|