hillary 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,241 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hillary::Repo::Version do
4
+ include_context 'git repository'
5
+
6
+ describe '.create!' do
7
+ context 'when the repository is on master, but not a production build' do
8
+ let!(:version){Hillary::Repo::Version.create!(repo)}
9
+
10
+ it 'creates an rc tag' do
11
+ expect(version.rc_tag).to eq(repo.last_rc_tag.name)
12
+ expect(version.rc_tag).to match(Hillary::Repo::RC_TAG_REGEX)
13
+ end
14
+ end
15
+
16
+ context 'when the repository is on master and is a production build' do
17
+ before(:each){repo.create_rc_tag}
18
+
19
+ let!(:version){Hillary::Repo::Version.create!(repo, production: true)}
20
+
21
+ it 'creates a production tag' do
22
+ expect(version.production_tag).to eq(repo.last_production_tag.name)
23
+ expect(version.production_tag).to match(Hillary::Repo::PRODUCTION_TAG_REGEX)
24
+ end
25
+ end
26
+
27
+ context 'when the repository is on dev' do
28
+ before(:each){local_repo.git.checkout({b: true}, 'dev')}
29
+
30
+ let!(:version){Hillary::Repo::Version.create!(repo)}
31
+
32
+ it 'does not create a tag' do
33
+ expect(version.rc_tag).to be_nil
34
+ expect(version.production_tag).to be_nil
35
+ end
36
+ end
37
+ end
38
+
39
+ describe '#name' do
40
+ let(:version){Hillary::Repo::Version.new(repo)}
41
+
42
+ context 'when branch is dev' do
43
+ before(:each){local_repo.git.checkout({b: true}, 'dev')}
44
+
45
+ it 'returns the commit sha of the current branch' do
46
+ expect(version.name).to eq(local_repo.commits.last.sha)
47
+ end
48
+ end
49
+
50
+ context 'when branch is master, but not a production build' do
51
+ before(:each){repo.create_rc_tag}
52
+
53
+ it 'returns the last rc tag' do
54
+ expect(version.name).to eq(repo.last_rc_tag.name)
55
+ end
56
+ end
57
+
58
+ context 'when branch is master, but not a production build' do
59
+ before(:each) do
60
+ repo.create_rc_tag
61
+ repo.create_production_tag
62
+ end
63
+
64
+ let(:version){Hillary::Repo::Version.new(repo, production: true)}
65
+
66
+ it 'returns the last production tag' do
67
+ expect(version.name).to eq(repo.last_production_tag.name)
68
+ end
69
+ end
70
+ end
71
+
72
+ describe '#branch' do
73
+ let(:version){Hillary::Repo::Version.new(repo)}
74
+
75
+ context 'when branch is dev' do
76
+ before(:each){local_repo.git.checkout({b: true}, 'dev')}
77
+
78
+ it 'returns "dev"' do
79
+ expect(version.branch).to eq('dev')
80
+ end
81
+ end
82
+
83
+ context 'when branch is master' do
84
+ it 'returns "master"' do
85
+ expect(version.branch).to eq('master')
86
+ end
87
+ end
88
+ end
89
+
90
+ describe '#tag' do
91
+ let(:version){Hillary::Repo::Version.new(repo)}
92
+
93
+ context 'when the branch is dev and no rc tag points to the same commit' do
94
+ it 'returns nil' do
95
+ expect(version.tag).to be_nil
96
+ end
97
+ end
98
+
99
+ context 'when the branch is master, but not a production build' do
100
+ before(:each){repo.create_rc_tag}
101
+
102
+ it 'returns last rc tag' do
103
+ expect(version.tag).to eq(repo.last_rc_tag.name)
104
+ end
105
+ end
106
+
107
+ context 'when the branch is master and is a production build' do
108
+ before(:each) do
109
+ repo.create_rc_tag
110
+ repo.create_production_tag
111
+ end
112
+
113
+ let(:version){Hillary::Repo::Version.new(repo, production: true)}
114
+
115
+ it 'returns last production tag' do
116
+ expect(version.tag).to eq(repo.last_production_tag.name)
117
+ end
118
+ end
119
+ end
120
+
121
+ describe '#sha' do
122
+ let(:version){Hillary::Repo::Version.new(repo)}
123
+
124
+ it 'returns the sha of the current branch' do
125
+ expect(version.sha).to eq(local_repo.commits.last.sha)
126
+ end
127
+ end
128
+
129
+ describe '#rc_tag' do
130
+ let(:version){Hillary::Repo::Version.new(repo)}
131
+
132
+ before(:each){repo.create_rc_tag}
133
+
134
+ context 'when current head matches latest rc tag' do
135
+ it 'returns the rc tag' do
136
+ expect(version.rc_tag).to eq(repo.last_rc_tag.name)
137
+ end
138
+ end
139
+
140
+ context 'when current head does not match the latest rc tag' do
141
+ before(:each) do
142
+ add_file_to_local('pizza.md', 'add pizza')
143
+ end
144
+
145
+ it 'returns nil' do
146
+ expect(version.rc_tag).to be_nil
147
+ end
148
+ end
149
+ end
150
+
151
+ describe '#production_tag' do
152
+ let(:version){Hillary::Repo::Version.new(repo)}
153
+
154
+ before(:each) do
155
+ repo.create_rc_tag
156
+ repo.create_production_tag
157
+ end
158
+
159
+ context 'when lastest rc tag matches latest production tag' do
160
+ it 'returns the production tag' do
161
+ expect(version.production_tag).to eq(repo.last_production_tag.name)
162
+ end
163
+ end
164
+
165
+ context 'when latest rc tag does not match the latest production tag' do
166
+ before(:each) do
167
+ add_file_to_local('pizza.md', 'add pizza')
168
+
169
+ Timecop.freeze(Time.now + 30) do
170
+ repo.create_rc_tag
171
+ end
172
+ end
173
+
174
+ it 'returns nil' do # HERE
175
+ expect(version.production_tag).to be_nil
176
+ end
177
+ end
178
+ end
179
+
180
+ describe '#sluggable?' do
181
+ let(:version){Hillary::Repo::Version.new(repo)}
182
+
183
+ context 'when the branch is dev' do
184
+ before(:each){local_repo.git.checkout({b: true}, 'dev')}
185
+
186
+ it 'is sluggable' do
187
+ expect(version).to be_sluggable
188
+ end
189
+ end
190
+
191
+ context 'when the branch is master' do
192
+ it 'is sluggable' do
193
+ expect(version).to be_sluggable
194
+ end
195
+ end
196
+
197
+ context 'when the branch is anything else' do
198
+ before(:each){local_repo.git.checkout({b: true}, 'anything_else')}
199
+
200
+ it 'is not sluggable' do
201
+ expect(version).to_not be_sluggable
202
+ end
203
+ end
204
+ end
205
+
206
+ describe '#master?' do
207
+ let(:version){Hillary::Repo::Version.new(repo)}
208
+
209
+ context 'when branch is master' do
210
+ it 'is true' do
211
+ expect(version).to be_master
212
+ end
213
+ end
214
+
215
+ context 'when branch is not master' do
216
+ before(:each){local_repo.git.checkout({b: true}, 'anything_else')}
217
+
218
+ it 'is false' do
219
+ expect(version).to_not be_master
220
+ end
221
+ end
222
+ end
223
+
224
+ describe '#dev?' do
225
+ let(:version){Hillary::Repo::Version.new(repo)}
226
+
227
+ context 'when branch is dev' do
228
+ before(:each){local_repo.git.checkout({b: true}, 'dev')}
229
+
230
+ it 'is true' do
231
+ expect(version).to be_dev
232
+ end
233
+ end
234
+
235
+ context 'when branch is not dev' do
236
+ it 'is false' do
237
+ expect(version).to_not be_dev
238
+ end
239
+ end
240
+ end
241
+ end
@@ -0,0 +1,135 @@
1
+ require 'spec_helper'
2
+ require 'grit'
3
+ require 'fileutils'
4
+
5
+ describe Hillary::Repo do
6
+ shared_context 'specific time' do
7
+ around(:each) do |example|
8
+ Timecop.freeze(Time.at(0)) do
9
+ example.call
10
+ end
11
+ end
12
+ end
13
+
14
+ describe '.rc_tag_name' do
15
+ include_context 'specific time'
16
+
17
+ it 'generates an RC tag name' do
18
+ expect(described_class.rc_tag_name).to eq('RC1969_12_31_19_00_00')
19
+ end
20
+
21
+ it 'matches the RC tag format' do
22
+ expect(described_class.rc_tag_name).to match(described_class::RC_TAG_REGEX)
23
+ end
24
+ end
25
+
26
+ describe '.production_tag_name' do
27
+ include_context 'specific time'
28
+
29
+ it 'generates an production tag name' do
30
+ expect(described_class.production_tag_name).to eq('1969_12_31_19_00_00')
31
+ end
32
+
33
+ it 'matches the production tag format' do
34
+ expect(described_class.production_tag_name).to match(described_class::PRODUCTION_TAG_REGEX)
35
+ end
36
+ end
37
+
38
+ describe '#checkout' do
39
+ include_context 'git repository'
40
+
41
+ context 'when called with a branch that exists' do
42
+ before(:each) do
43
+ local_repo.git.branch({}, 'dev')
44
+ remote_repo.git.branch({}, 'dev')
45
+ add_file_to_remote('chicken.txt', 'chicken', 'dev')
46
+ repo.checkout('dev')
47
+ end
48
+
49
+ it 'checks out the specified branch' do
50
+ expect(local_repo.head.name).to eq('dev')
51
+ end
52
+
53
+ it 'updates the local branch from remote' do
54
+ expect(File.exist?('chicken.txt')).to eq(true)
55
+ end
56
+
57
+ it 'displays information about what is happening' do
58
+ expect(out.string).to eq("Checking out dev and updating from origin\n")
59
+ end
60
+ end
61
+
62
+ context 'when called with a branch that does not exist' do
63
+ it 'raises MissingHeadError' do
64
+ expect{repo.checkout('dev')}.to raise_error(Hillary::Repo::MissingHeadError)
65
+ end
66
+
67
+ it 'displays information about what is happening' do
68
+ repo.checkout('dev') rescue nil
69
+
70
+ expect(out.string).to eq("Checking out dev and updating from origin\n")
71
+ end
72
+ end
73
+
74
+ context 'when called on a repository that is dirty' do
75
+ before(:each) do
76
+ FileUtils.touch('blah')
77
+ local_repo.add('blah')
78
+ end
79
+
80
+ it 'raises DirtyProjectError' do
81
+ expect{repo.checkout('dev')}.to raise_error(Hillary::Repo::DirtyProjectError)
82
+ end
83
+ end
84
+ end
85
+
86
+ describe '#create_rc_tag' do
87
+ include_context 'git repository'
88
+
89
+ before(:each){repo.create_rc_tag('master', 'RC1969_12_31_19_00_00')}
90
+ let(:local_master){local_repo.get_head('master')}
91
+ let(:local_tag){local_repo.tags.first}
92
+ let(:remote_tag){remote_repo.tags.first}
93
+
94
+ it 'creates a tag pointing to the same commit as master' do
95
+ expect(local_tag.commit.sha).to eq(local_master.commit.sha)
96
+ end
97
+
98
+ it 'pushes the tag to origin' do
99
+ expect(remote_tag.commit.sha).to eq(local_master.commit.sha)
100
+ end
101
+
102
+ it 'displays information about what is happening' do
103
+ expect(out.string).to match(
104
+ %r{Tagging origin/master \([\da-f]+\) as RC1969_12_31_19_00_00\nPushing RC1969_12_31_19_00_00 to origin\n}
105
+ )
106
+ end
107
+ end
108
+
109
+ describe '#create_production_tag' do
110
+ include_context 'git repository'
111
+
112
+ before(:each) do
113
+ repo.create_rc_tag('master', 'RC1969_12_31_19_00_00')
114
+ repo.create_production_tag('2001_11_11_11_11_11')
115
+ end
116
+
117
+ let(:local_rc_tag){local_repo.tags.find{|tag| tag.name == 'RC1969_12_31_19_00_00'}}
118
+ let(:local_production_tag){local_repo.tags.find{|tag| tag.name == '2001_11_11_11_11_11'}}
119
+ let(:remote_production_tag){remote_repo.tags.find{|tag| tag.name == '2001_11_11_11_11_11'}}
120
+
121
+ it 'creates a tag pointing to the last RC' do
122
+ expect(local_production_tag.commit.sha).to eq(local_rc_tag.commit.sha)
123
+ end
124
+
125
+ it 'pushes the tag to origin' do
126
+ expect(remote_production_tag.commit.sha).to eq(local_rc_tag.commit.sha)
127
+ end
128
+
129
+ it 'displays information about what is happening' do
130
+ expect(out.string).to match(
131
+ %r{Tagging origin/master \([\da-f]+\) as RC1969_12_31_19_00_00\nPushing RC1969_12_31_19_00_00 to origin\nTagging RC1969_12_31_19_00_00 \([\da-f]+\) as 2001_11_11_11_11_11\nPushing 2001_11_11_11_11_11 to origin\n}
132
+ )
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hillary::Slug::Bucket do
4
+ around(:each) do |example|
5
+ Fog.mock!
6
+ example.run
7
+ Fog.unmock!
8
+ end
9
+
10
+ let(:access_key){'public'}
11
+ let(:secret_key){'secret'}
12
+ let(:storage){Fog::Storage.new(provider: 'AWS', aws_access_key_id: access_key, aws_secret_access_key: secret_key)}
13
+ let(:bucket_name){'slugbucket'}
14
+ let(:bucket){storage.directories.get(bucket_name)}
15
+ let(:slug_name){'g3_slug_RC2014_01_01_01_01_01.tar.gz'}
16
+ let(:canonical_slug_name){'g3_slug_b26206aaf36207304d4fa583ce9837d0bdb48966.tar.gz'}
17
+ let(:slug_path){'rc/' + slug_name}
18
+ let(:canonical_slug_path){'dev/' + canonical_slug_name}
19
+ let(:slug){bucket.files.get(slug_name)}
20
+ let(:canonical_slug){bucket.files.get(canonical_slug_name)}
21
+ let(:slug_file){Tempfile.new(slug_name)}
22
+ let(:slug_file_path){slug_file.path}
23
+
24
+ before(:each){storage.directories.create(key: bucket_name)}
25
+
26
+ subject{Hillary::Slug::Bucket.new(bucket_name, access_key, secret_key)}
27
+
28
+ describe '#write' do
29
+ it 'writes the file to the bucket with the given name' do
30
+ subject.write(canonical_slug_path, slug_file_path)
31
+ expect(bucket.files.get(canonical_slug_path).body).to eq('')
32
+ end
33
+ end
34
+
35
+ describe '#copy' do
36
+ it 'copies the specified file to the specified location' do
37
+ subject.write(canonical_slug_path, slug_file_path)
38
+ subject.copy(canonical_slug_path, slug_path)
39
+
40
+ expect(bucket.files.get(slug_path))
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,160 @@
1
+ require 'spec_helper'
2
+ require 'fileutils'
3
+
4
+ describe Hillary::Slug do
5
+ let(:version) do
6
+ double(
7
+ Hillary::Repo::Version,
8
+ sluggable?: true,
9
+ branch: 'dev',
10
+ name: 'b26206aaf36207304d4fa583ce9837d0bdb48966',
11
+ sha: 'b26206aaf36207304d4fa583ce9837d0bdb48966',
12
+ dev?: true,
13
+ master?: false,
14
+ production?: false
15
+ )
16
+ end
17
+ let(:out){StringIO.new}
18
+ let(:logger) do
19
+ Logger.new(out).tap do |logger|
20
+ end
21
+ end
22
+ let(:bucket){double(Hillary::Slug::Bucket, write: nil, copy: nil, name: 'gz-slugbucket')}
23
+ let(:path){File.expand_path('../../tmp/g3', __FILE__)}
24
+
25
+ describe '.build' do
26
+ context 'when the version is not sluggable' do
27
+ before(:each){allow(version).to receive(:sluggable?){false}}
28
+
29
+ it 'returns nil' do
30
+ slug = described_class.build(path, version, logger: logger, bucket: bucket)
31
+ expect(slug).to be_nil
32
+ end
33
+ end
34
+
35
+ context 'when the version is sluggable' do
36
+ let(:slug){double(Hillary::Slug)}
37
+
38
+ it 'returns a slug' do
39
+ expect(Hillary::Slug).to receive(:new).with(path, version, logger: logger, bucket: bucket){slug}
40
+ expect(slug).to receive(:build)
41
+
42
+ described_class.build(path, version, logger: logger, bucket: bucket)
43
+ end
44
+ end
45
+ end
46
+
47
+ describe '#build' do
48
+ context 'when branch is dev' do
49
+ subject(:slug){described_class.new(path, version, logger: logger, bucket: bucket)}
50
+ let(:slug_name){'g3_slug_b26206aaf36207304d4fa583ce9837d0bdb48966.tar.gz'}
51
+ let(:slug_path){Pathname.new(path).join('..', slug_name).expand_path}
52
+
53
+ describe 'when everything is successful' do
54
+ before(:each) do
55
+ FileUtils.mkdir_p(path)
56
+ allow(bucket).to receive(:write)
57
+ end
58
+
59
+ after(:each) do
60
+ FileUtils.rm_rf(slug_path)
61
+ FileUtils.rm_rf(path)
62
+ end
63
+
64
+ it 'creates the slug' do
65
+ slug.build
66
+
67
+ expect(File.exist?(slug_path)).to eq(true)
68
+ end
69
+
70
+ it 'writes the slug to the bucket' do
71
+ expect(bucket).to receive(:write).with('dev/' + slug_name, slug_path)
72
+
73
+ slug.build
74
+ end
75
+
76
+ it 'logs information about what is happening' do
77
+ slug.build
78
+
79
+ expect(out.string).to eq(
80
+ "Creating slug g3_slug_b26206aaf36207304d4fa583ce9837d0bdb48966.tar.gz\n"\
81
+ 'Uploading g3_slug_b26206aaf36207304d4fa583ce9837d0bdb48966.tar.gz '\
82
+ "to gz-slugbucket:/dev/g3_slug_b26206aaf36207304d4fa583ce9837d0bdb48966.tar.gz\n"
83
+ )
84
+ end
85
+ end
86
+
87
+ describe 'when archiving fails' do
88
+ it 'raises an error' do
89
+ expect{slug.build}.to raise_error(Hillary::Shellable::ExecutionError)
90
+ end
91
+ end
92
+ end
93
+
94
+ context 'when branch is master, but not production build' do
95
+ let(:version) do
96
+ double(
97
+ Hillary::Repo::Version,
98
+ sluggable?: true,
99
+ branch: 'master',
100
+ name: 'RC2014_01_01_01_01_01',
101
+ sha: 'b26206aaf36207304d4fa583ce9837d0bdb48966',
102
+ dev?: false,
103
+ master?: true,
104
+ production?: false
105
+ )
106
+ end
107
+
108
+ subject(:slug){described_class.new(path, version, logger: logger, bucket: bucket)}
109
+
110
+ it 'copies the canonical slug to rc slug name' do
111
+ expect(bucket).to receive(:copy).with('dev/g3_slug_b26206aaf36207304d4fa583ce9837d0bdb48966.tar.gz', 'rc/g3_slug_RC2014_01_01_01_01_01.tar.gz')
112
+
113
+ slug.build
114
+ end
115
+
116
+ it 'logs information about what is happening' do
117
+ slug.build
118
+
119
+ expect(out.string).to eq('Copying gz-slugbucket:/dev/g3_slug_b26206aaf36207304d4fa583ce9837d0bdb48966.tar.gz '\
120
+ "to gz-slugbucket:/rc/g3_slug_RC2014_01_01_01_01_01.tar.gz\n"
121
+ )
122
+ end
123
+ end
124
+
125
+ context 'when branch is master and is a production build' do
126
+ let(:version) do
127
+ double(
128
+ Hillary::Repo::Version,
129
+ sluggable?: true,
130
+ branch: 'master',
131
+ name: '2014_01_01_01_01_01',
132
+ sha: 'b26206aaf36207304d4fa583ce9837d0bdb48966',
133
+ dev?: false,
134
+ master?: true,
135
+ production?: true
136
+ )
137
+ end
138
+
139
+ subject(:slug){described_class.new(path, version, logger: logger, bucket: bucket)}
140
+
141
+ it 'copies the canonical slug to production slug name' do
142
+ expect(bucket).to receive(:copy).with(
143
+ 'dev/g3_slug_b26206aaf36207304d4fa583ce9837d0bdb48966.tar.gz',
144
+ 'production/g3_slug_2014_01_01_01_01_01.tar.gz'
145
+ )
146
+
147
+ slug.build
148
+ end
149
+
150
+ it 'logs information about what is happening' do
151
+ slug.build
152
+
153
+ expect(out.string).to eq(
154
+ 'Copying gz-slugbucket:/dev/g3_slug_b26206aaf36207304d4fa583ce9837d0bdb48966.tar.gz '\
155
+ "to gz-slugbucket:/production/g3_slug_2014_01_01_01_01_01.tar.gz\n"
156
+ )
157
+ end
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hillary do
4
+ it 'has a version number' do
5
+ expect(Hillary::VERSION).not_to be nil
6
+ end
7
+ end
@@ -0,0 +1,9 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'hillary'
3
+ require 'timecop'
4
+ require 'pry'
5
+
6
+ require 'hillary/slug'
7
+ require 'hillary/repo'
8
+
9
+ Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each{|path| require path}
@@ -0,0 +1,49 @@
1
+ shared_context 'git repository' do
2
+ subject(:repo){Hillary::Repo.new(local_repo_path, logger)}
3
+ let(:logger){Logger.new(out)}
4
+ let(:out){StringIO.new}
5
+ let(:local_repo_path){File.expand_path('../../tmp/local', __FILE__)}
6
+ let(:remote_repo_path){File.expand_path('../../tmp/remote.git', __FILE__)}
7
+ let!(:local_repo) do
8
+ Grit::Repo.init(local_repo_path).tap do |repo|
9
+ FileUtils.touch('taco.md')
10
+ repo.add('taco.md')
11
+ repo.commit_all('Initial commit')
12
+
13
+ repo.fork_bare(remote_repo_path)
14
+ repo.remote_add('origin', remote_repo_path)
15
+ repo.git.pull
16
+ end
17
+ end
18
+ let!(:remote_repo) do
19
+ Grit::Repo.init_bare(remote_repo_path)
20
+ end
21
+
22
+ around(:each) do |example|
23
+ FileUtils.mkdir_p(local_repo_path)
24
+ Dir.chdir(local_repo_path) do
25
+ example.call
26
+ end
27
+ end
28
+
29
+ after(:each) do
30
+ FileUtils.rm_rf(local_repo_path)
31
+ FileUtils.rm_rf(remote_repo_path)
32
+ end
33
+
34
+ def add_file_to_remote(name, content, branch)
35
+ index = remote_repo.index
36
+ parent_commit = remote_repo.get_head(branch).commit
37
+ index.read_tree(branch)
38
+ index.add(name, content)
39
+ index.commit("Add #{name}", [parent_commit], nil, nil, branch)
40
+ end
41
+
42
+ def add_file_to_local(name, message)
43
+ FileUtils.touch(name)
44
+ local_repo.add(name)
45
+ local_repo.commit_all(message)
46
+ local_repo.git.push({u: true}, 'origin', 'head')
47
+ local_repo.git.pull
48
+ end
49
+ end