hillary 0.0.1

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.
@@ -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