github_bitbucket_deployer 0.4.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4820cbe9e8b032c3db7d59d2be77d80539790037
4
- data.tar.gz: ac6b647de50319ee45de35979adc9654b3db9f15
3
+ metadata.gz: 26db8331ec93b1bfcca69796b62706b44bde7df7
4
+ data.tar.gz: ab86f9d0b91833e8b4c23dc516ddab529b1f409c
5
5
  SHA512:
6
- metadata.gz: bc6b5b1b659986d83c491d4d7f1bc903d8969c68126db2ae1bad6713d2e836dd96ac77525356cf31bf28269dc88a896f90368fa9721dafd573b56819ee235cea
7
- data.tar.gz: 39dd999a8fa195a7a6ff7094db494e3757f3d27b54c2f8755ccdd358463641a79a2ac89f82e84e47b90879e8704d9efbfc32a427302b90542be177d2dd6a12ca
6
+ metadata.gz: cd08ab565ec6cc99721f810869843ed9db8af8d9022d688fb3440f383d49913ad0467b5ca588e3352a959e2e39bf5a5993de7442ba611324d36f056adb91ac28
7
+ data.tar.gz: 2fec783ed7da9e3a094f3f71e8a9aa155156468477edbc69fe2a1dddec82ce4250fc459e47257ca07bc061e336c7b23147798976f6e7b5a84386c05e8907bf6b
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1 @@
1
+ 2.2.5
@@ -0,0 +1,5 @@
1
+ ## v1.0.0 (2016-11-04)
2
+
3
+ * Enhancements to error handling with general refactoring of
4
+ `GithubBitbucketDeployer::Git`
5
+ ([#2](https://github.com/g5search/github_bitbucket_deployer/pull/2))
data/README.md CHANGED
@@ -8,14 +8,12 @@ Ruby gem to deploy public and private Github repos to Bitbucket
8
8
 
9
9
  ## Current Version
10
10
 
11
- 0.3.1
12
-
11
+ 1.0.0
13
12
 
14
13
  ## Requirements
15
14
 
16
- * ["git", "~> 1.2.5"](http://rubygems.org/gems/git)
17
- * ["git-ssh-wrapper", "~> 0.1.0"](http://rubygems.org/gems/git-ssh-wrapper)
18
-
15
+ * [git](https://git-scm.com/) >= 1.6.0.0
16
+ * [ruby](https://www.ruby-lang.org/) >= 2.2
19
17
 
20
18
  ## Installation
21
19
 
@@ -15,11 +15,12 @@ Gem::Specification.new do |gem|
15
15
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
16
16
  gem.require_paths = ["lib"]
17
17
 
18
- gem.add_dependency "git", "~> 1.2.5"
19
- gem.add_dependency "git-ssh-wrapper", "~> 0.1.0"
18
+ gem.add_dependency "git", "~> 1.2", ">= 1.2.9.1"
19
+ gem.add_dependency "git-ssh-wrapper", "~> 0.1"
20
+ gem.add_dependency "retriable", "~> 2.1"
20
21
 
21
22
  gem.add_development_dependency "simplecov", "~> 0.7.1"
22
- gem.add_development_dependency "rspec", "~> 2.11.0"
23
- gem.add_development_dependency "guard-rspec", "~> 2.1.0"
24
- gem.add_development_dependency "rb-fsevent", "~> 0.9.2"
23
+ gem.add_development_dependency "rspec", "~> 3.5"
24
+ gem.add_development_dependency "fakefs", "~> 0.9.2"
25
+ gem.add_development_dependency "pry-byebug", "~> 3.3"
25
26
  end
@@ -0,0 +1,21 @@
1
+ require 'git'
2
+
3
+ # Patch ruby-git to support logger for Git.clone
4
+ # See https://github.com/schacon/ruby-git/issues/208
5
+ module CloneLoggerFix
6
+ module ClassMethods
7
+ def clone(repository, name, opts = {})
8
+ lib = ::Git::Lib.new(nil, opts[:log])
9
+ clone_opts = lib.clone(repository, name, opts)
10
+ new(clone_opts.merge(log: opts[:log]))
11
+ end
12
+ end
13
+
14
+ def self.prepended(base)
15
+ class << base
16
+ prepend ClassMethods
17
+ end
18
+ end
19
+ end
20
+
21
+ ::Git::Base.prepend(CloneLoggerFix)
@@ -1,8 +1,11 @@
1
- require "git"
2
- require "git-ssh-wrapper"
1
+ require 'git'
2
+ require 'git-ssh-wrapper'
3
+ require 'retriable'
4
+ require 'github_bitbucket_deployer/clone_logger_fix'
3
5
 
4
6
  module GithubBitbucketDeployer
5
7
  class Git
8
+ attr_reader :bitbucket_repo_url, :git_repo_name, :id_rsa, :repo_dir, :logger
6
9
 
7
10
  def initialize(options)
8
11
  @bitbucket_repo_url = options[:bitbucket_repo_url]
@@ -12,92 +15,91 @@ module GithubBitbucketDeployer
12
15
  @repo_dir = options[:repo_dir]
13
16
  end
14
17
 
15
- def push_app_to_bitbucket(remote="bitbucket", branch="master", &block)
16
- @logger.info "push_app_to_bitbucket"
17
- wrapper = ssh_wrapper
18
- run "cd #{repo.dir}; git remote rm #{remote}" if repo.remote(remote).url
19
- repo.add_remote(remote, @bitbucket_repo_url)
20
- yield(repo) if block_given?
21
- @logger.info "deploying #{repo.dir} to #{repo.remote(remote).url} from branch #{branch}"
22
- run "cd #{repo.dir}; env #{wrapper.git_ssh} git push -f #{remote} #{branch}"
23
- ensure
24
- wrapper.unlink
18
+ def push_app_to_bitbucket(remote = 'bitbucket', branch = 'master')
19
+ logger.info('push_app_to_bitbucket')
20
+ add_remote(remote)
21
+ with_ssh { yield(repo) } if block_given?
22
+ push(remote, branch)
25
23
  end
26
24
 
27
25
  def repo
28
26
  @repo ||= setup_repo
29
27
  end
30
28
 
31
- def setup_repo
32
- @logger.info "setup_repo"
33
- clone_or_pull
34
- open
35
- end
36
-
37
29
  def folder
38
30
  @folder ||= setup_folder
39
31
  end
40
32
 
41
- def setup_folder
42
- @logger.info "setup_folder"
43
- folder = File.join(@repo_dir, Zlib.crc32(@git_repo_name).to_s)
44
- FileUtils.mkdir_p(folder).first
33
+ def clone
34
+ logger.info("git clone: cloning #{bitbucket_repo_url} to #{folder}")
35
+ run { ::Git.clone(bitbucket_repo_url, folder, log: logger) }
45
36
  end
46
37
 
47
- def clone_or_pull
48
- @logger.info "clone_or_pull"
49
- exists_locally? ? pull : clone
38
+ def pull
39
+ logger.info("git pull: pulling from #{folder}")
40
+ run { open.pull }
41
+ open
50
42
  end
51
43
 
52
- def exists_locally?
53
- File.exists?(File.join(folder, ".git", "config"))
44
+ def open
45
+ logger.info('git open')
46
+ ::Git.open(folder, log: logger)
54
47
  end
55
48
 
56
- def clone
57
- @logger.info "git clone"
58
- wrapper = ssh_wrapper
59
- @logger.info "cloning #{@bitbucket_repo_url} to #{folder}"
60
- run "unset GIT_WORK_TREE; env #{wrapper.git_ssh} git clone #{@bitbucket_repo_url} #{folder}"
61
- ensure
62
- wrapper.unlink
49
+ def push(remote, branch)
50
+ logger.info("git push: deploying #{repo.dir} to " \
51
+ "#{repo.remote(remote).url} from branch #{branch}")
52
+ run { repo.push(remote, branch, force: true) }
63
53
  end
64
54
 
65
- def pull
66
- @logger.info "git pull"
67
- wrapper = ssh_wrapper
68
- dir = Dir.pwd # need to cd back to here
69
- @logger.info "pulling from #{folder}"
70
- run "cd #{folder}; env #{wrapper.git_ssh} git pull; cd #{dir}"
71
- ensure
72
- wrapper.unlink
55
+ def add_remote(remote = 'bitbucket')
56
+ logger.info("git add_remote: #{remote}")
57
+ repo.remote(remote).remove if repo.remote(remote).url
58
+ repo.add_remote(remote, bitbucket_repo_url)
73
59
  end
74
60
 
75
- def open
76
- @logger.info "git open"
77
- ::Git.open(folder)
61
+ private
62
+
63
+ def setup_folder
64
+ logger.info('setup_folder')
65
+ folder = File.join(repo_dir, Zlib.crc32(git_repo_name).to_s)
66
+ FileUtils.mkdir_p(folder).first
67
+ end
68
+
69
+ def setup_repo
70
+ logger.info('setup_repo')
71
+ update_working_copy
72
+ open
78
73
  end
79
74
 
80
- def ssh_wrapper
81
- GitSSHWrapper.new(private_key_path: id_rsa_path)
75
+ def update_working_copy
76
+ logger.info('update_working_copy')
77
+ exists_locally? ? pull : clone
78
+ end
79
+
80
+ def exists_locally?
81
+ git_config = File.join(folder, '.git', 'config')
82
+ File.exist?(git_config)
82
83
  end
83
84
 
84
- def id_rsa_path
85
- file = Tempfile.new("id_rsa")
86
- file.write(@id_rsa)
87
- file.rewind
88
- file.path
85
+ def run
86
+ Retriable.retriable(on: ::Git::GitExecuteError, tries: 3) do
87
+ with_ssh { yield }
88
+ end
89
+ rescue ::Git::GitExecuteError => error
90
+ logger.error(error)
91
+ raise GithubBitbucketDeployer::CommandException, error
89
92
  end
90
93
 
91
- def run(command)
92
- @logger.info "git run command: #{command}"
93
- result = system("#{command} 2>&1")
94
- sleep 20
95
- if result
96
- @logger.info $?.to_s
97
- else
98
- raise GithubBitbucketDeployer::CommandException, $?.to_s
94
+ def with_ssh
95
+ @old_git_ssh = ENV['GIT_SSH']
96
+
97
+ GitSSHWrapper.with_wrapper(private_key: id_rsa) do |wrapper|
98
+ wrapper.set_env
99
+ yield if block_given?
99
100
  end
101
+ ensure
102
+ ENV['GIT_SSH'] = @old_git_ssh
100
103
  end
101
104
  end
102
105
  end
103
-
@@ -1,3 +1,3 @@
1
1
  module GithubBitbucketDeployer
2
- VERSION = "0.4.2"
2
+ VERSION = '1.0.0'.freeze
3
3
  end
@@ -1,11 +1,9 @@
1
1
  require 'spec_helper'
2
- require 'github_bitbucket_deployer'
3
- require 'github_bitbucket_deployer/configuration'
4
2
 
5
3
  describe GithubBitbucketDeployer::Configuration do
6
- it { should respond_to :"[]" }
7
- it { should respond_to :to_hash }
8
- it { should respond_to :merge }
4
+ it { is_expected.to respond_to :"[]" }
5
+ it { is_expected.to respond_to :to_hash }
6
+ it { is_expected.to respond_to :merge }
9
7
 
10
8
  it "provides default values" do
11
9
  assert_config_default :id_rsa, ENV["ID_RSA"]
@@ -19,24 +17,24 @@ describe GithubBitbucketDeployer::Configuration do
19
17
  config = GithubBitbucketDeployer::Configuration.new
20
18
  hash = config.to_hash
21
19
  GithubBitbucketDeployer::Configuration::OPTIONS.each_pair do |key, value|
22
- config[key].should eq(hash[key])
20
+ expect(config[key]).to eq(hash[key])
23
21
  end
24
22
  end
25
23
 
26
24
  it "is mergable" do
27
25
  config = GithubBitbucketDeployer::Configuration.new
28
26
  hash = config.to_hash
29
- config.merge(:key => 'value').should eq(hash.merge(:key => 'value'))
27
+ expect(config.merge(:key => 'value')).to eq(hash.merge(:key => 'value'))
30
28
  end
31
29
 
32
30
  def assert_config_default(option, default_value, config = nil)
33
31
  config ||= GithubBitbucketDeployer::Configuration.new
34
- config.send(option).should eq(default_value)
32
+ expect(config.send(option)).to eq(default_value)
35
33
  end
36
34
 
37
35
  def assert_config_overridable(option, value = 'a value')
38
36
  config = GithubBitbucketDeployer::Configuration.new
39
37
  config.send(:"#{option}=", value)
40
- config.send(option).should eq(value)
38
+ expect(config.send(option)).to eq(value)
41
39
  end
42
40
  end
@@ -1,5 +1,442 @@
1
1
  require 'spec_helper'
2
- require 'github_bitbucket_deployer/git'
3
2
 
4
3
  describe GithubBitbucketDeployer::Git do
4
+ include GitHelpers
5
+
6
+ let(:git) { described_class.new(options) }
7
+
8
+ let(:options) do
9
+ { bitbucket_repo_url: bitbucket_repo_url,
10
+ git_repo_name: git_repo_name,
11
+ id_rsa: id_rsa,
12
+ logger: logger,
13
+ repo_dir: repo_dir }
14
+ end
15
+
16
+ let(:bitbucket_repo_url) { 'git@bitbucket.org:g5dev/some_repo.git' }
17
+ let(:git_repo_name) { 'some_repo' }
18
+ let(:local_repo_folder) { Zlib.crc32(git_repo_name) }
19
+ let(:id_rsa) { 'this is the value of my key' }
20
+ let(:logger) { double('logger', info: true, error: true) }
21
+ let(:repo_dir) { '/my_home/projects' }
22
+ let(:working_dir) { "#{repo_dir}/#{local_repo_folder}" }
23
+
24
+ let(:git_repo) do
25
+ instance_double(::Git::Base, remote: empty_remote,
26
+ dir: git_working_dir,
27
+ add_remote: true,
28
+ pull: true,
29
+ push: true)
30
+ end
31
+ let(:empty_remote) { instance_double(::Git::Remote, url: nil) }
32
+
33
+ let(:bitbucket_remote) do
34
+ instance_double(::Git::Remote, url: bitbucket_repo_url,
35
+ remove: true)
36
+ end
37
+ before do
38
+ allow(git_repo).to receive(:remote)
39
+ .with('bitbucket').and_return(bitbucket_remote)
40
+ end
41
+
42
+ let(:git_working_dir) do
43
+ instance_double(::Git::WorkingDirectory, path: working_dir,
44
+ to_s: working_dir)
45
+ end
46
+
47
+ before do
48
+ allow(::Git).to receive(:open).and_return(git_repo)
49
+ allow(::Git).to receive(:clone).and_return(git_repo)
50
+ end
51
+
52
+ describe '#initialize' do
53
+ subject { git }
54
+
55
+ it 'sets the bitbucket_repo_url' do
56
+ expect(git.bitbucket_repo_url).to eq(bitbucket_repo_url)
57
+ end
58
+
59
+ it 'sets the git_repo_name' do
60
+ expect(git.git_repo_name).to eq(git_repo_name)
61
+ end
62
+
63
+ it 'sets the id_rsa' do
64
+ expect(git.id_rsa).to eq(id_rsa)
65
+ end
66
+
67
+ it 'sets the logger' do
68
+ expect(git.logger).to eq(logger)
69
+ end
70
+
71
+ it 'sets the repo_dir' do
72
+ expect(git.repo_dir).to eq(repo_dir)
73
+ end
74
+ end
75
+
76
+ describe '#push_app_to_bitbucket', :fakefs do
77
+ subject { push_app }
78
+
79
+ context 'with default arguments' do
80
+ let(:push_app) { git.push_app_to_bitbucket }
81
+
82
+ context 'when local repo already exists' do
83
+ before { create_local_repo(working_dir) }
84
+
85
+ it 'pulls from the remote repo' do
86
+ expect(git_repo).to receive(:pull).and_return(true)
87
+ push_app
88
+ end
89
+
90
+ it 'removes the existing remote' do
91
+ expect(bitbucket_remote).to receive(:remove)
92
+ push_app
93
+ end
94
+
95
+ it 'creates the bitbucket remote anew' do
96
+ expect(git_repo).to receive(:add_remote)
97
+ .with('bitbucket', bitbucket_repo_url)
98
+ push_app
99
+ end
100
+
101
+ it 'force pushes master to bitbucket' do
102
+ expect(git_repo).to receive(:push)
103
+ .with('bitbucket', 'master', force: true)
104
+ push_app
105
+ end
106
+ end
107
+
108
+ context 'when local repo does not exist' do
109
+ before do
110
+ allow(git_repo).to receive(:remote)
111
+ .with('bitbucket').and_return(empty_remote)
112
+ end
113
+
114
+ it 'clones the bitbucket repo into the local folder' do
115
+ expect(::Git).to receive(:clone)
116
+ .with(bitbucket_repo_url, working_dir, log: logger)
117
+ .and_return(git_repo)
118
+ push_app
119
+ end
120
+
121
+ it 'creates the bitbucket remote' do
122
+ expect(git_repo).to receive(:add_remote)
123
+ .with('bitbucket', bitbucket_repo_url)
124
+ push_app
125
+ end
126
+
127
+ it 'force pushes master to bitbucket' do
128
+ expect(git_repo).to receive(:push)
129
+ .with('bitbucket', 'master', force: true)
130
+ push_app
131
+ end
132
+ end
133
+ end
134
+
135
+ context 'with custom arguments' do
136
+ let(:push_app) { git.push_app_to_bitbucket(remote_name, branch) }
137
+
138
+ let(:remote_name) { 'my_git_server' }
139
+ let(:branch) { 'my_topic_branch' }
140
+
141
+ before { create_local_repo(working_dir) }
142
+
143
+ it 'pulls from the remote repo' do
144
+ expect(git_repo).to receive(:pull).and_return(true)
145
+ push_app
146
+ end
147
+
148
+ it 'creates the new remote' do
149
+ expect(git_repo).to receive(:add_remote)
150
+ .with(remote_name, bitbucket_repo_url)
151
+ push_app
152
+ end
153
+
154
+ it 'yields to the block' do
155
+ expect do |block|
156
+ git.push_app_to_bitbucket(remote_name, branch, &block)
157
+ end.to yield_with_args(git_repo)
158
+ end
159
+
160
+ it 'forces pushes the branch' do
161
+ expect(git_repo).to receive(:push)
162
+ .with(remote_name, branch, force: true)
163
+ push_app
164
+ end
165
+ end
166
+ end
167
+
168
+ describe '#repo', :fakefs do
169
+ subject(:repo) { git.repo }
170
+
171
+ context 'when repo_dir exists' do
172
+ before { FileUtils.mkdir_p(repo_dir) }
173
+
174
+ context 'with a git repo' do
175
+ before { create_local_repo(working_dir) }
176
+
177
+ it { is_expected.to eq(git_repo) }
178
+
179
+ it 'points to the local working dir' do
180
+ expect(repo.dir.path).to eq(working_dir)
181
+ end
182
+
183
+ it 'pulls into the existing repo' do
184
+ expect(git_repo).to receive(:pull).and_return(true)
185
+ repo
186
+ end
187
+ end
188
+
189
+ context 'without a git repo' do
190
+ before do
191
+ FileUtils.rm_rf(working_dir)
192
+ end
193
+
194
+ it { is_expected.to eq(git_repo) }
195
+
196
+ it 'clones the repo locally' do
197
+ expect(::Git).to receive(:clone)
198
+ .with(bitbucket_repo_url, working_dir, log: logger)
199
+ .and_return(git_repo)
200
+ repo
201
+ end
202
+ end
203
+ end
204
+
205
+ context 'when repo_dir does not exist' do
206
+ before do
207
+ FileUtils.rm_rf(repo_dir)
208
+ end
209
+
210
+ it 'creates the local repo dir' do
211
+ repo
212
+ expect(File).to exist(repo_dir)
213
+ end
214
+
215
+ it { is_expected.to eq(git_repo) }
216
+
217
+ it 'clones the repo locally' do
218
+ expect(::Git).to receive(:clone)
219
+ .with(bitbucket_repo_url, working_dir, log: logger)
220
+ .and_return(git_repo)
221
+ repo
222
+ end
223
+ end
224
+ end
225
+
226
+ describe '#folder', :fakefs do
227
+ subject(:folder) { git.folder }
228
+
229
+ context 'when repo_dir exists' do
230
+ before { FileUtils.mkdir_p(repo_dir) }
231
+
232
+ it { is_expected.to eq(working_dir) }
233
+
234
+ it 'creates the local folder' do
235
+ expect(File).to exist(folder)
236
+ end
237
+ end
238
+
239
+ context 'when repo_dir does not exist' do
240
+ before { FileUtils.rm_rf(repo_dir) }
241
+
242
+ it { is_expected.to eq(working_dir) }
243
+
244
+ it 'creates the absolute path to the local folder' do
245
+ expect(File).to exist(folder)
246
+ end
247
+ end
248
+ end
249
+
250
+ describe '#clone', :fakefs do
251
+ subject(:clone) { git.clone }
252
+
253
+ it { is_expected.to be(git_repo) }
254
+
255
+ it 'clones the bitbucket repo into the local folder' do
256
+ expect(::Git).to receive(:clone)
257
+ .with(bitbucket_repo_url, working_dir, log: logger)
258
+ .and_return(git_repo)
259
+ clone
260
+ end
261
+
262
+ it_behaves_like 'a git error handler' do
263
+ before { allow(::Git).to receive(:clone).and_raise(error) }
264
+
265
+ let(:retry_git_command) do
266
+ expect(::Git).to have_received(:clone).exactly(retry_limit).times
267
+ end
268
+ end
269
+
270
+ it_behaves_like 'a git ssh wrapper' do
271
+ def run_git_command
272
+ expect(::Git).to receive(:clone) { yield }
273
+ end
274
+ end
275
+ end
276
+
277
+ describe '#pull', :fakefs do
278
+ subject(:pull) { git.pull }
279
+
280
+ it { is_expected.to be(git_repo) }
281
+
282
+ it 'pulls from the remote server' do
283
+ expect(git_repo).to receive(:pull)
284
+ pull
285
+ end
286
+
287
+ it 'does not change the current dir' do
288
+ expect { pull }.to_not change { Dir.pwd }
289
+ end
290
+
291
+ it_behaves_like 'a git error handler' do
292
+ before { allow(git_repo).to receive(:pull).and_raise(error) }
293
+
294
+ let(:retry_git_command) do
295
+ expect(git_repo).to have_received(:pull).exactly(retry_limit).times
296
+ end
297
+ end
298
+
299
+ it_behaves_like 'a git ssh wrapper' do
300
+ def run_git_command
301
+ expect(git_repo).to receive(:pull) { yield }
302
+ end
303
+ end
304
+ end
305
+
306
+ describe '#open', :fakefs do
307
+ subject(:open) { git.open }
308
+
309
+ it { is_expected.to eq(git_repo) }
310
+
311
+ it 'opens the local repo with logging' do
312
+ expect(::Git).to receive(:open)
313
+ .with(working_dir, log: logger).and_return(git_repo)
314
+ open
315
+ end
316
+ end
317
+
318
+ describe '#push', :fakefs do
319
+ subject(:push) { git.push(remote_name, branch) }
320
+
321
+ let(:remote_name) { 'bitbucket' }
322
+ let(:branch) { 'master' }
323
+
324
+ it 'force pushes the branch to the remote' do
325
+ expect(git_repo).to receive(:push).with(remote_name, branch, force: true)
326
+ push
327
+ end
328
+
329
+ it_behaves_like 'a git error handler' do
330
+ before { allow(git_repo).to receive(:push).and_raise(error) }
331
+
332
+ let(:retry_git_command) do
333
+ expect(git_repo).to have_received(:push).exactly(retry_limit).times
334
+ end
335
+ end
336
+
337
+ it_behaves_like 'a git ssh wrapper' do
338
+ def run_git_command
339
+ expect(git_repo).to receive(:push) { yield }
340
+ end
341
+ end
342
+ end
343
+
344
+ describe '#add_remote', :fakefs do
345
+ subject { add_remote }
346
+
347
+ let(:unrelated_remote) do
348
+ instance_double(::Git::Remote, url: 'git@heroku.com:my_app.git')
349
+ end
350
+
351
+ before do
352
+ allow(git_repo).to receive(:remote)
353
+ .with('heroku').and_return(unrelated_remote)
354
+ end
355
+
356
+ context 'with default remote name' do
357
+ let(:add_remote) { git.add_remote }
358
+
359
+ context 'when bitbucket remote already exists' do
360
+ it 'removes the existing remote' do
361
+ expect(bitbucket_remote).to receive(:remove)
362
+ add_remote
363
+ end
364
+
365
+ it 'does not remove the unrelated remote' do
366
+ expect(unrelated_remote).to_not receive(:remove)
367
+ add_remote
368
+ end
369
+
370
+ it 'adds the new bitbucket remote' do
371
+ expect(git_repo).to receive(:add_remote)
372
+ .with('bitbucket', bitbucket_repo_url)
373
+ add_remote
374
+ end
375
+ end
376
+
377
+ context 'when bitbucket remote does not exist' do
378
+ let(:bitbucket_remote) { empty_remote }
379
+
380
+ it 'does not remove any existing remotes' do
381
+ expect(empty_remote).to_not receive(:remove)
382
+ expect(unrelated_remote).to_not receive(:remove)
383
+ add_remote
384
+ end
385
+
386
+ it 'adds the new bitbucket remote' do
387
+ expect(git_repo).to receive(:add_remote)
388
+ .with('bitbucket', bitbucket_repo_url)
389
+ add_remote
390
+ end
391
+ end
392
+ end
393
+
394
+ context 'with custom remote name' do
395
+ let(:add_remote) { git.add_remote(remote_name) }
396
+
397
+ let(:custom_remote) do
398
+ instance_double(::Git::Remote, url: 'git@some_server.com:my_app.git',
399
+ remove: true)
400
+ end
401
+ let(:remote_name) { 'custom_remote' }
402
+ before do
403
+ allow(git_repo).to receive(:remote)
404
+ .with(remote_name).and_return(custom_remote)
405
+ end
406
+
407
+ context 'when custom remote already exists' do
408
+ it 'removes the existing remote' do
409
+ expect(custom_remote).to receive(:remove)
410
+ add_remote
411
+ end
412
+
413
+ it 'does not remove unrelated remotes' do
414
+ expect(unrelated_remote).to_not receive(:remove)
415
+ add_remote
416
+ end
417
+
418
+ it 'creates the new custom remote' do
419
+ expect(git_repo).to receive(:add_remote)
420
+ .with(remote_name, bitbucket_repo_url)
421
+ add_remote
422
+ end
423
+ end
424
+
425
+ context 'when custom remote does not already exist' do
426
+ let(:custom_remote) { empty_remote }
427
+
428
+ it 'does not remove any existing remotes' do
429
+ expect(empty_remote).to_not receive(:remove)
430
+ expect(unrelated_remote).to_not receive(:remove)
431
+ add_remote
432
+ end
433
+
434
+ it 'creates the new custom remote' do
435
+ expect(git_repo).to receive(:add_remote)
436
+ .with(remote_name, bitbucket_repo_url)
437
+ add_remote
438
+ end
439
+ end
440
+ end
441
+ end
5
442
  end
@@ -1,33 +1,33 @@
1
1
  require 'spec_helper'
2
- require 'github_bitbucket_deployer'
3
2
 
4
3
  describe GithubBitbucketDeployer do
5
- it { should respond_to :configuration }
6
- it { should respond_to :configure }
7
- it { should respond_to :deploy }
4
+ it { is_expected.to respond_to(:configuration) }
5
+ it { is_expected.to respond_to(:configure) }
6
+ it { is_expected.to respond_to(:deploy) }
7
+
8
+ describe ".configuration" do
9
+ subject(:config) { GithubBitbucketDeployer.configuration }
8
10
 
9
- describe "::configuration" do
10
11
  it "should be the configuration object" do
11
- GithubBitbucketDeployer.configuration.should(
12
- be_a_kind_of GithubBitbucketDeployer::Configuration)
12
+ expect(config).to be_a_kind_of(GithubBitbucketDeployer::Configuration)
13
13
  end
14
14
 
15
15
  it "give a new instance if non defined" do
16
16
  GithubBitbucketDeployer.configuration = nil
17
- GithubBitbucketDeployer.configuration.should(
18
- be_a_kind_of GithubBitbucketDeployer::Configuration)
17
+ expect(config).to be_a_kind_of(GithubBitbucketDeployer::Configuration)
19
18
  end
20
19
  end
21
20
 
22
- describe "::configure" do
21
+ describe ".configure" do
23
22
  it "should yield the configuration object" do
24
23
  GithubBitbucketDeployer.configure do |config|
25
- config.should equal(GithubBitbucketDeployer.configuration)
24
+ expect(config).to equal(GithubBitbucketDeployer.configuration)
26
25
  end
27
26
  end
28
27
  end
29
28
 
30
29
  describe "::deploy" do
30
+ subject(:deploy) { GithubBitbucketDeployer.deploy }
31
31
 
32
32
  context "when unconfigured" do
33
33
  before :each do
@@ -37,16 +37,15 @@ describe GithubBitbucketDeployer do
37
37
  end
38
38
 
39
39
  it "requires github_repo to be set" do
40
- lambda { GithubBitbucketDeployer.deploy }.should(
41
- raise_error ::GithubBitbucketDeployer::ConfigurationException)
40
+ expect { deploy }.to raise_error(GithubBitbucketDeployer::ConfigurationException)
42
41
  end
43
42
  end
44
43
 
45
44
  # TODO: how can I test these better?
46
45
  context "when configured" do
47
46
  before :each do
48
- @deployer = mock("github_bitbucket_deployer")
49
- @deployer.stub!(:deploy).and_return(true)
47
+ @deployer = double("github_bitbucket_deployer")
48
+ allow(@deployer).to receive(:deploy).and_return(true)
50
49
  end
51
50
 
52
51
  it "overrides defaults" do
@@ -54,9 +53,8 @@ describe GithubBitbucketDeployer do
54
53
  config.id_rsa = ""
55
54
  end
56
55
 
57
- override = ENV["ID_RSA"]
58
- override.should_not equal GithubBitbucketDeployer.configuration[:id_rsa]
59
- @deployer.deploy(id_rsa: override).should be true
56
+ override = 'override-value'
57
+ expect(@deployer.deploy(id_rsa: override)).to be true
60
58
  end
61
59
 
62
60
  end
@@ -3,12 +3,17 @@ SimpleCov.start
3
3
 
4
4
  require 'rubygems'
5
5
  require 'rspec'
6
- require 'rspec/autorun'
6
+ require 'pp' # See https://github.com/fakefs/fakefs/issues/99
7
+ require 'pry-byebug'
8
+ require 'fakefs/spec_helpers'
7
9
 
8
- RSpec.configure do |config|
9
- config.order = "random"
10
- end
10
+ Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each {|f| require f }
11
11
 
12
12
  ENV['ID_RSA']="id_rsa"
13
13
  ENV['REPO_DIR']="foo"
14
14
 
15
+ require 'github_bitbucket_deployer'
16
+
17
+ RSpec.configure do |config|
18
+ config.order = "random"
19
+ end
@@ -0,0 +1,9 @@
1
+ RSpec.configure do |config|
2
+ config.include FakeFS::SpecHelpers, fakefs: true
3
+ config.before(:each, fakefs: true) do
4
+ source_dir = File.join(File.dirname(__FILE__), '..', '..')
5
+ FakeFS::FileSystem.clone(source_dir)
6
+ FakeFS::FileSystem.add(Dir.tmpdir)
7
+ FakeFS::FileSystem.add('/tmp')
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ module GitHelpers
2
+ def create_local_repo(working_dir)
3
+ git_dir = "#{working_dir}/.git"
4
+ FileUtils.mkdir_p(git_dir)
5
+ Dir.chdir(git_dir) { FileUtils.touch('config') }
6
+ end
7
+ end
@@ -0,0 +1,46 @@
1
+ # Prerequisites:
2
+ # * set up any method stubs on the git repo to raise error, e.g.
3
+ # before { allow(git_repo).to receive(:pull).and raise_error(error) }
4
+ # * define a method named retry_git_command to set up retry expectations, e.g.
5
+ # let(:retry_git_command) do
6
+ # expect(git_repo).to have_received(:pull).exactly(retry_limit).times
7
+ # end
8
+ shared_examples_for 'a git error handler' do
9
+ let(:safe_subject) { subject rescue error }
10
+
11
+ context 'with Git::GitExecuteError' do
12
+ let(:error) { Git::GitExecuteError.new('some git error') }
13
+
14
+ let(:retry_limit) { 3 }
15
+
16
+ it 'retries 3 times' do
17
+ safe_subject
18
+ retry_git_command
19
+ end
20
+
21
+ it 'logs the error' do
22
+ expect(logger).to receive(:error)
23
+ safe_subject
24
+ end
25
+
26
+ it 'raises a GithubBitbucketDeployer::CommandException' do
27
+ expect { subject }
28
+ .to raise_error(GithubBitbucketDeployer::CommandException)
29
+ end
30
+ end
31
+
32
+ context 'with any other type of error' do
33
+ let(:error) { ArgumentError.new('some non-git error') }
34
+
35
+ let(:retry_limit) { 1 }
36
+
37
+ it 'only tries once' do
38
+ safe_subject
39
+ retry_git_command
40
+ end
41
+
42
+ it 'raises the original exception' do
43
+ expect { subject }.to raise_error(error)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,59 @@
1
+ # Prerequisites:
2
+ # Must define a method names run_git_command that yields control, e.g.
3
+ # def run_git_command
4
+ # expect(git_repo).to receive(:pull) { yield }
5
+ # end
6
+ shared_examples_for 'a git ssh wrapper' do
7
+ let(:temp_files) do
8
+ Dir.glob("#{Dir.tmpdir}/git-ssh-wrapper*").sort_by { |f| File.mtime(f) }
9
+ end
10
+
11
+ it 'constructs a wrapper with the private key' do
12
+ expect(GitSSHWrapper).to receive(:with_wrapper)
13
+ .with(private_key: id_rsa).at_least(:once)
14
+ subject
15
+ end
16
+
17
+ it 'writes the ssh wrapper to a tempfile' do
18
+ run_git_command do
19
+ expect(temp_files).to_not be_empty
20
+ end
21
+ subject
22
+ end
23
+
24
+ it 'sets the GIT_SSH env var during command execution' do
25
+ run_git_command do
26
+ expect(temp_files).to include(ENV['GIT_SSH'])
27
+ end
28
+ subject
29
+ end
30
+
31
+ context 'when command is successful' do
32
+ it 'resets the GIT_SSH env var after exiting' do
33
+ expect { subject }.to_not change { ENV['GIT_SSH'] }
34
+ end
35
+
36
+ it 'unlinks the temp ssh files' do
37
+ subject
38
+ expect(temp_files).to be_empty
39
+ end
40
+ end
41
+
42
+ context 'when command raises an error' do
43
+ let(:safe_subject) do
44
+ run_git_command do
45
+ raise GitExecuteError, 'some git error'
46
+ end
47
+ subject rescue 'whatever'
48
+ end
49
+
50
+ it 'resets the GIT_SSH env var after exiting' do
51
+ expect { safe_subject }.to_not change { ENV['GIT_SSH'] }.from(nil)
52
+ end
53
+
54
+ it 'unlinks the temp ssh files' do
55
+ safe_subject
56
+ expect(temp_files).to be_empty
57
+ end
58
+ end
59
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: github_bitbucket_deployer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jessica Lynn Suttles
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-09-23 00:00:00.000000000 Z
12
+ date: 2016-11-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: git
@@ -17,28 +17,48 @@ dependencies:
17
17
  requirements:
18
18
  - - "~>"
19
19
  - !ruby/object:Gem::Version
20
- version: 1.2.5
20
+ version: '1.2'
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.2.9.1
21
24
  type: :runtime
22
25
  prerelease: false
23
26
  version_requirements: !ruby/object:Gem::Requirement
24
27
  requirements:
25
28
  - - "~>"
26
29
  - !ruby/object:Gem::Version
27
- version: 1.2.5
30
+ version: '1.2'
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.2.9.1
28
34
  - !ruby/object:Gem::Dependency
29
35
  name: git-ssh-wrapper
30
36
  requirement: !ruby/object:Gem::Requirement
31
37
  requirements:
32
38
  - - "~>"
33
39
  - !ruby/object:Gem::Version
34
- version: 0.1.0
40
+ version: '0.1'
35
41
  type: :runtime
36
42
  prerelease: false
37
43
  version_requirements: !ruby/object:Gem::Requirement
38
44
  requirements:
39
45
  - - "~>"
40
46
  - !ruby/object:Gem::Version
41
- version: 0.1.0
47
+ version: '0.1'
48
+ - !ruby/object:Gem::Dependency
49
+ name: retriable
50
+ requirement: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.1'
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.1'
42
62
  - !ruby/object:Gem::Dependency
43
63
  name: simplecov
44
64
  requirement: !ruby/object:Gem::Requirement
@@ -59,42 +79,42 @@ dependencies:
59
79
  requirements:
60
80
  - - "~>"
61
81
  - !ruby/object:Gem::Version
62
- version: 2.11.0
82
+ version: '3.5'
63
83
  type: :development
64
84
  prerelease: false
65
85
  version_requirements: !ruby/object:Gem::Requirement
66
86
  requirements:
67
87
  - - "~>"
68
88
  - !ruby/object:Gem::Version
69
- version: 2.11.0
89
+ version: '3.5'
70
90
  - !ruby/object:Gem::Dependency
71
- name: guard-rspec
91
+ name: fakefs
72
92
  requirement: !ruby/object:Gem::Requirement
73
93
  requirements:
74
94
  - - "~>"
75
95
  - !ruby/object:Gem::Version
76
- version: 2.1.0
96
+ version: 0.9.2
77
97
  type: :development
78
98
  prerelease: false
79
99
  version_requirements: !ruby/object:Gem::Requirement
80
100
  requirements:
81
101
  - - "~>"
82
102
  - !ruby/object:Gem::Version
83
- version: 2.1.0
103
+ version: 0.9.2
84
104
  - !ruby/object:Gem::Dependency
85
- name: rb-fsevent
105
+ name: pry-byebug
86
106
  requirement: !ruby/object:Gem::Requirement
87
107
  requirements:
88
108
  - - "~>"
89
109
  - !ruby/object:Gem::Version
90
- version: 0.9.2
110
+ version: '3.3'
91
111
  type: :development
92
112
  prerelease: false
93
113
  version_requirements: !ruby/object:Gem::Requirement
94
114
  requirements:
95
115
  - - "~>"
96
116
  - !ruby/object:Gem::Version
97
- version: 0.9.2
117
+ version: '3.3'
98
118
  description: Deploys Github repos to bitbucket
99
119
  email:
100
120
  - jlsuttles@gmail.com
@@ -104,14 +124,17 @@ extensions: []
104
124
  extra_rdoc_files: []
105
125
  files:
106
126
  - ".gitignore"
127
+ - ".rspec"
128
+ - ".ruby-version"
107
129
  - ".travis.yml"
130
+ - CHANGELOG.md
108
131
  - Gemfile
109
- - Guardfile
110
132
  - LICENSE
111
133
  - README.md
112
134
  - Rakefile
113
135
  - github_bitbucket_deployer.gemspec
114
136
  - lib/github_bitbucket_deployer.rb
137
+ - lib/github_bitbucket_deployer/clone_logger_fix.rb
115
138
  - lib/github_bitbucket_deployer/configuration.rb
116
139
  - lib/github_bitbucket_deployer/exceptions.rb
117
140
  - lib/github_bitbucket_deployer/git.rb
@@ -120,6 +143,10 @@ files:
120
143
  - spec/lib/github_bitbucket_deployer/git_spec.rb
121
144
  - spec/lib/github_bitbucket_deployer_spec.rb
122
145
  - spec/spec_helper.rb
146
+ - spec/support/fakefs.rb
147
+ - spec/support/git_helpers.rb
148
+ - spec/support/shared_examples/git_error_handler.rb
149
+ - spec/support/shared_examples/git_ssh_wrapper.rb
123
150
  homepage: https://github.com/G5/github_bitbucket_deployer
124
151
  licenses: []
125
152
  metadata: {}
@@ -139,7 +166,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
139
166
  version: '0'
140
167
  requirements: []
141
168
  rubyforge_project:
142
- rubygems_version: 2.4.7
169
+ rubygems_version: 2.4.8
143
170
  signing_key:
144
171
  specification_version: 4
145
172
  summary: Deploys public and private Github repos to bitbucket
@@ -148,3 +175,7 @@ test_files:
148
175
  - spec/lib/github_bitbucket_deployer/git_spec.rb
149
176
  - spec/lib/github_bitbucket_deployer_spec.rb
150
177
  - spec/spec_helper.rb
178
+ - spec/support/fakefs.rb
179
+ - spec/support/git_helpers.rb
180
+ - spec/support/shared_examples/git_error_handler.rb
181
+ - spec/support/shared_examples/git_ssh_wrapper.rb
data/Guardfile DELETED
@@ -1,5 +0,0 @@
1
- guard 'rspec' do
2
- watch(%r{^spec/.+_spec\.rb$})
3
- watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
4
- watch('spec/spec_helper.rb') { "spec" }
5
- end