github_bitbucket_deployer 0.4.2 → 1.0.0

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