git_duplicator 0.0.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,26 +1,25 @@
1
1
  require 'http'
2
- require_relative '../helpers/authorization_header'
3
-
4
2
  module GitDuplicator
5
3
  module Services
6
4
  class GithubRepository < ServiceRepository
7
5
  BASE_URI = 'https://api.github.com'
8
6
 
9
- attr_accessor :credentials, :options
7
+ attr_accessor :credentials, :remote_options, :working_directory
10
8
 
11
9
  # Initializer
12
- # @param [String] name name of the repository
13
- # @param [String] owner owner of the repository
14
- # @param [Hash] credentials
15
- # @option credentials [Symbol] :oauth2_token used in oAuth2 authentication
16
- # @option credentials [Symbol] :username used in basic authentication
17
- # @option credentials [Symbol] :password used in basic authentication
18
- # @param [Hash] options options for creation
19
- # @see https://developer.github.com/v3/repos/#create
20
- def initialize(name, owner, credentials = {}, options = {})
21
- super(name, owner)
22
- self.credentials = credentials
23
- self.options = options
10
+ # @param [Hash] options
11
+ # * :credentials (Hash) credentials for remote service
12
+ # * :oauth2_token (Symbol) used in oAuth2 authentication
13
+ # * :username (Symbol) used in basic authentication
14
+ # * :password (Symbol) used in basic authentication
15
+ # * :remote_options (Hash) creation options for remote service
16
+ # @see @see https://developer.github.com/v3/repos/#create
17
+ # * :working_directory (String) assing a working directory
18
+ def initialize(name, owner, options = {})
19
+ self.credentials = options.fetch(:credentials) { {} }
20
+ self.remote_options = options.fetch(:remote_options) { {} }
21
+ self.working_directory = options.fetch(:working_directory) { nil }
22
+ super(name, owner, working_directory)
24
23
  end
25
24
 
26
25
  # URL of the repositroy
@@ -33,7 +32,7 @@ module GitDuplicator
33
32
  def create
34
33
  request_url = BASE_URI + '/user/repos'
35
34
  response = HTTP.with(headers(:post, request_url))
36
- .post(request_url, json: options.merge(name: name))
35
+ .post(request_url, json: remote_options.merge(name: name))
37
36
  code, body = response.code.to_i, response.body
38
37
  fail(RepositoryCreationError, body) unless 201 == code
39
38
  end
@@ -1,9 +1,9 @@
1
1
  module GitDuplicator
2
2
  # Gem's version
3
3
  class Version
4
- MAJOR = 0
4
+ MAJOR = 1
5
5
  MINOR = 0
6
- PATCH = 1
6
+ PATCH = 0
7
7
 
8
8
  class << self
9
9
  # @return [String]
@@ -0,0 +1,112 @@
1
+ require_relative '../../helper'
2
+
3
+ module GitDuplicator
4
+
5
+ describe Duplicator do
6
+ let(:path) { '/somepath' }
7
+ let(:from) do
8
+ double(name: 'somename', bare_clone: nil, mirror: nil, url: 'somewhere1')
9
+ end
10
+ let(:to) { double(delete: nil, create: nil, url: 'somewhere2') }
11
+ let(:duplicator) { described_class.new(from, to, options) }
12
+
13
+ describe '#perform_mirror' do
14
+ let(:options) { {} }
15
+ it 'raises an exception in case of not defined' do
16
+ expect { duplicator.perform_mirror }
17
+ .to raise_error(NotImplementedError)
18
+ end
19
+ end
20
+
21
+ describe '#perform_clone_source' do
22
+ let(:options) { {} }
23
+ it 'raises an exception in case of not defined' do
24
+ expect { duplicator.perform_clone_source }
25
+ .to raise_error(NotImplementedError)
26
+ end
27
+ end
28
+
29
+ describe '#perform_clean_up' do
30
+ let(:options) { {} }
31
+ it 'raises an exception in case of not defined' do
32
+ expect { duplicator.perform_clean_up }
33
+ .to raise_error(NotImplementedError)
34
+ end
35
+ end
36
+
37
+ describe '#perform' do
38
+ before do
39
+ allow(duplicator).to receive(:perform_clone_source)
40
+ allow(duplicator).to receive(:perform_mirror)
41
+ allow(duplicator).to receive(:perform_clean_up)
42
+ end
43
+ context 'force_create_destination is set' do
44
+ let(:options) { { clone_path: path, force_create_destination: true } }
45
+
46
+ it 'deletes existing destination repo' do
47
+ expect(to).to receive(:delete)
48
+ duplicator.perform
49
+ end
50
+
51
+ it 'creates the destination repo' do
52
+ expect(to).to receive(:create)
53
+ duplicator.perform
54
+ end
55
+
56
+ it 'clones the source repo' do
57
+ expect(duplicator).to receive(:clone_source)
58
+ duplicator.perform
59
+ end
60
+
61
+ it 'mirrors to destination' do
62
+ expect(duplicator).to receive(:mirror)
63
+ duplicator.perform
64
+ end
65
+
66
+ it 'cleans up' do
67
+ expect(duplicator).to receive(:clean_up)
68
+ duplicator.perform
69
+ end
70
+
71
+ it 'logs 5 times' do
72
+ expect(duplicator.logger).to receive(:info).exactly(5).times
73
+ duplicator.perform
74
+ end
75
+ end
76
+
77
+ context 'force_create_destination is false' do
78
+ let(:options) { { clone_path: path } }
79
+
80
+ it 'deletes existing destination repo' do
81
+ expect(to).not_to receive(:delete)
82
+ duplicator.perform
83
+ end
84
+
85
+ it 'creates the destination repo' do
86
+ expect(to).not_to receive(:create)
87
+ duplicator.perform
88
+ end
89
+
90
+ it 'clones the source repo' do
91
+ expect(duplicator).to receive(:clone_source)
92
+ duplicator.perform
93
+ end
94
+
95
+ it 'mirrors to destination' do
96
+ expect(duplicator).to receive(:mirror)
97
+ duplicator.perform
98
+ end
99
+
100
+ it 'cleans up' do
101
+ expect(duplicator).to receive(:clean_up)
102
+ duplicator.perform
103
+ end
104
+
105
+ it 'logs 3 times' do
106
+ expect(duplicator.logger).to receive(:info).exactly(3).times
107
+ duplicator.perform
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,35 @@
1
+ require_relative '../../helper'
2
+
3
+ module GitDuplicator
4
+ describe MirrorDuplicator do
5
+ let(:path) { '/somepath' }
6
+ let(:from) do
7
+ double(name: 'somename', bare_clone: nil, mirror: nil, url: 'somewhere1')
8
+ end
9
+ let(:options) { { clone_path: path, force_create_destination: true } }
10
+ let(:to) { double(delete: nil, create: nil, url: 'somewhere2') }
11
+ let(:duplicator) { described_class.new(from, to, options) }
12
+
13
+ describe '#clone_source' do
14
+ it 'bare clones the source repo' do
15
+ expect(from).to receive(:bare_clone).with(path)
16
+ duplicator.perform
17
+ end
18
+ end
19
+
20
+ describe '#mirror' do
21
+ it 'mirrors from bare clone to destination' do
22
+ expect(from).to receive(:mirror).with(to.url)
23
+ duplicator.perform
24
+ end
25
+ end
26
+
27
+ describe '#clean_up' do
28
+ it 'mirrors from bare clone to destination' do
29
+ expect(FileUtils).to receive(:rm_rf)
30
+ .with("#{duplicator.clone_path}/#{from.name}")
31
+ duplicator.perform
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,39 @@
1
+ require_relative '../../helper'
2
+
3
+ module GitDuplicator
4
+ describe UpdateDuplicator do
5
+ let(:path) { '/somepath' }
6
+ let(:from) do
7
+ double(name: 'somename', mirror_clone: nil, set_mirrored_remote: nil,
8
+ update_mirrored: nil, url: 'somewhere1')
9
+ end
10
+ let(:options) { { clone_path: path, force_create_destination: true } }
11
+ let(:to) { double(delete: nil, create: nil, url: 'somewhere2') }
12
+ let(:duplicator) { described_class.new(from, to, options) }
13
+
14
+ describe '#clone_source' do
15
+ it 'bare clones the source repo' do
16
+ expect(from).to receive(:mirror_clone).with(path)
17
+ duplicator.perform
18
+ end
19
+ end
20
+
21
+ describe '#mirror' do
22
+ it 'sets the remote for push' do
23
+ expect(from).to receive(:set_mirrored_remote).with(to.url)
24
+ duplicator.perform
25
+ end
26
+
27
+ it 'mirrors from mirror clone to destination' do
28
+ expect(from).to receive(:update_mirrored)
29
+ duplicator.perform
30
+ end
31
+ end
32
+
33
+ describe '#clean_up' do
34
+ it 'mirrors from bare clone to destination' do
35
+ expect(duplicator.perform).to be_nil
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,188 @@
1
+ require_relative '../helper'
2
+
3
+ def random_name
4
+ rand(36**5).to_s(36)
5
+ end
6
+
7
+ describe GitDuplicator do
8
+ before(:each) { WebMock.allow_net_connect! }
9
+ let(:clone_path) { '/tmp' }
10
+ let(:credentials) do
11
+ { consumer_key: ENV['BITBUCKET_CONSUMER_KEY'],
12
+ consumer_secret: ENV['BITBUCKET_CONSUMER_SECRET'],
13
+ token: ENV['BITBUCKET_TOKEN'],
14
+ token_secret: ENV['BITBUCKET_TOKEN_SECRET'] }
15
+ end
16
+ let(:options) { { credentials: credentials } }
17
+
18
+ describe '#perform' do
19
+ it 'mirrors from service to service without ' \
20
+ 'force_create_destination option' do
21
+ skip
22
+ # Setup
23
+ from = GitDuplicator::Services::GithubRepository
24
+ .new('naught', 'avdi')
25
+ to = GitDuplicator::Services::BitbucketRepository
26
+ .new(ENV['TESTING_REPO'], ENV['BITBUCKET_USER'], options)
27
+ to.create
28
+ GitDuplicator.perform(from, to, clone_path: clone_path)
29
+ source_name = random_name
30
+ mirrored_name = random_name
31
+
32
+ # Exercise
33
+ source = Git.clone(from.url, source_name, path: clone_path)
34
+ mirrored = Git.clone(to.url, mirrored_name, path: clone_path)
35
+
36
+ # Verify
37
+ expect(mirrored.object('HEAD^').to_s).to eq(source.object('HEAD^').to_s)
38
+
39
+ # Teardown
40
+ FileUtils.rm_rf("#{clone_path}/#{source_name}")
41
+ FileUtils.rm_rf("#{clone_path}/#{mirrored_name}")
42
+ to.delete
43
+ end
44
+
45
+ it 'mirrors from service to service with ' \
46
+ 'force_create_destination option' do
47
+ skip
48
+ # Setup
49
+ from = GitDuplicator::Services::GithubRepository
50
+ .new('naught', 'avdi')
51
+ to = GitDuplicator::Services::BitbucketRepository
52
+ .new(ENV['TESTING_REPO'], ENV['BITBUCKET_USER'], options)
53
+ GitDuplicator.perform(from, to,
54
+ clone_path: clone_path,
55
+ force_create_destination: true)
56
+ source_name = random_name
57
+ mirrored_name = random_name
58
+
59
+ # Exercise
60
+ source = Git.clone(from.url, source_name, path: clone_path)
61
+ mirrored = Git.clone(to.url, mirrored_name, path: clone_path)
62
+
63
+ # Verify
64
+ expect(mirrored.object('HEAD^').to_s).to eq(source.object('HEAD^').to_s)
65
+
66
+ # Teardown
67
+ FileUtils.rm_rf("#{clone_path}/#{source_name}")
68
+ FileUtils.rm_rf("#{clone_path}/#{mirrored_name}")
69
+ to.delete
70
+ end
71
+
72
+ it 'mirrors from basic to service with ' \
73
+ 'force_create_destination option' do
74
+ skip
75
+ # Setup
76
+ from = GitDuplicator::Repository
77
+ .new('naught', 'https://github.com/avdi/naught.git')
78
+ to = GitDuplicator::Services::BitbucketRepository
79
+ .new(ENV['TESTING_REPO'], ENV['BITBUCKET_USER'], options)
80
+ GitDuplicator.perform(from, to,
81
+ clone_path: clone_path,
82
+ force_create_destination: true)
83
+ source_name = random_name
84
+ mirrored_name = random_name
85
+
86
+ # Exercise
87
+ source = Git.clone(from.url, source_name, path: clone_path)
88
+ mirrored = Git.clone(to.url, mirrored_name, path: clone_path)
89
+
90
+ # Verify
91
+ expect(mirrored.object('HEAD^').to_s).to eq(source.object('HEAD^').to_s)
92
+
93
+ # Teardown
94
+ FileUtils.rm_rf("#{clone_path}/#{source_name}")
95
+ FileUtils.rm_rf("#{clone_path}/#{mirrored_name}")
96
+ to.delete
97
+ end
98
+ end
99
+
100
+ describe '#perform_for_updates' do
101
+ it 'mirrors from service to service without ' \
102
+ 'force_create_destination option' do
103
+ skip
104
+ # Setup
105
+ from = GitDuplicator::Services::GithubRepository
106
+ .new('naught', 'avdi')
107
+ to = GitDuplicator::Services::BitbucketRepository
108
+ .new(ENV['TESTING_REPO'], ENV['BITBUCKET_USER'], options)
109
+ to.create
110
+ GitDuplicator.perform_for_update(from, to, clone_path: clone_path)
111
+ source_name = from.name
112
+ mirrored_name = random_name
113
+
114
+ # Exercise
115
+ source = Git.bare("#{clone_path}/#{source_name}")
116
+ mirrored = Git.clone(to.url, mirrored_name, path: clone_path)
117
+
118
+ # Verify
119
+ expect(mirrored.object('HEAD^').to_s).to eq(source.object('HEAD^').to_s)
120
+
121
+ # Teardown
122
+ FileUtils.rm_rf("#{clone_path}/#{source_name}")
123
+ FileUtils.rm_rf("#{clone_path}/#{mirrored_name}")
124
+ to.delete
125
+ end
126
+
127
+ it 'mirrors from service to service with ' \
128
+ 'force_create_destination option' do
129
+ skip
130
+ # Setup
131
+ from = GitDuplicator::Services::GithubRepository
132
+ .new('naught', 'avdi')
133
+ to = GitDuplicator::Services::BitbucketRepository
134
+ .new(ENV['TESTING_REPO'], ENV['BITBUCKET_USER'], options)
135
+ GitDuplicator.perform_for_update(from, to,
136
+ clone_path: clone_path,
137
+ force_create_destination: true)
138
+ source_name = from.name
139
+ mirrored_name = random_name
140
+
141
+ # Exercise
142
+ source = Git.bare("#{clone_path}/#{source_name}")
143
+ mirrored = Git.clone(to.url, mirrored_name, path: clone_path)
144
+
145
+ # Verify
146
+ expect(mirrored.object('HEAD^').to_s).to eq(source.object('HEAD^').to_s)
147
+
148
+ # Teardown
149
+ FileUtils.rm_rf("#{clone_path}/#{source_name}")
150
+ FileUtils.rm_rf("#{clone_path}/#{mirrored_name}")
151
+ to.delete
152
+ end
153
+
154
+ it 'mirrors from basic to service with ' \
155
+ 'force_create_destination option' do
156
+ skip
157
+ # Setup
158
+ from = GitDuplicator::Repository
159
+ .new('naught', 'https://github.com/avdi/naught.git')
160
+ to = GitDuplicator::Services::BitbucketRepository
161
+ .new(ENV['TESTING_REPO'], ENV['BITBUCKET_USER'], options)
162
+ GitDuplicator.perform_for_update(from, to,
163
+ clone_path: clone_path,
164
+ force_create_destination: true)
165
+ source_name = from.name
166
+ mirrored_name = random_name
167
+
168
+ # Exercise
169
+ source = Git.bare("#{clone_path}/#{source_name}")
170
+ mirrored = Git.clone(to.url, mirrored_name, path: clone_path)
171
+
172
+ # Verify
173
+ expect(mirrored.object('HEAD^').to_s).to eq(source.object('HEAD^').to_s)
174
+
175
+ local_repo = GitDuplicator::Repository.new(
176
+ 'naught',
177
+ 'https://github.com/avdi/naught.git',
178
+ "#{clone_path}/#{source_name}"
179
+ )
180
+ local_repo.update_mirrored
181
+
182
+ #Teardown
183
+ FileUtils.rm_rf("#{clone_path}/#{source_name}")
184
+ FileUtils.rm_rf("#{clone_path}/#{mirrored_name}")
185
+ to.delete
186
+ end
187
+ end
188
+ end
@@ -1,102 +1,32 @@
1
1
  require_relative '../helper'
2
2
 
3
- def random_name
4
- rand(36**5).to_s(36)
5
- end
6
-
7
3
  describe GitDuplicator do
8
- before(:each) { WebMock.allow_net_connect! }
9
4
  let(:clone_path) { '/tmp' }
10
-
5
+ let(:credentials) do
6
+ { consumer_key: ENV['BITBUCKET_CONSUMER_KEY'],
7
+ consumer_secret: ENV['BITBUCKET_CONSUMER_SECRET'],
8
+ token: ENV['BITBUCKET_TOKEN'],
9
+ token_secret: ENV['BITBUCKET_TOKEN_SECRET'] }
10
+ end
11
+ let(:options) { { clone_path: clone_path } }
12
+ let(:from) { GitDuplicator::Repository }
13
+ let(:to) { GitDuplicator::Repository }
14
+ let(:result) { double(perform: nil) }
11
15
  describe '#perform' do
12
-
13
- let(:credentials) do
14
- { consumer_key: ENV['BITBUCKET_CONSUMER_KEY'],
15
- consumer_secret: ENV['BITBUCKET_CONSUMER_SECRET'],
16
- token: ENV['BITBUCKET_TOKEN'],
17
- token_secret: ENV['BITBUCKET_TOKEN_SECRET'] }
16
+ it 'delegates to MirrorDuplicator' do
17
+ expect(GitDuplicator::MirrorDuplicator)
18
+ .to receive(:new).with(from, to, options).and_return(result)
19
+ expect(result).to receive(:perform)
20
+ GitDuplicator.perform(from, to, options)
18
21
  end
22
+ end
19
23
 
20
- it 'mirrors from service to service without ' \
21
- 'force_create_destination option' do
22
- skip
23
- # Setup
24
- from = GitDuplicator::Services::GithubRepository
25
- .new('naught', 'avdi')
26
- to = GitDuplicator::Services::BitbucketRepository
27
- .new(ENV['TESTING_REPO'], ENV['BITBUCKET_USER'], credentials)
28
- to.create
29
- GitDuplicator.perform(from, to, clone_path: clone_path)
30
- mirrored_name = random_name
31
- result_name = random_name
32
-
33
- # Exercise
34
- mirrored = Git.clone(from.url, mirrored_name, path: clone_path)
35
- result = Git.clone(from.url, result_name, path: clone_path)
36
-
37
- # Verify
38
- expect(result.object('HEAD^').to_s).to eq(mirrored.object('HEAD^').to_s)
39
-
40
- # Teardown
41
- FileUtils.rm_rf("#{clone_path}/#{mirrored_name}")
42
- FileUtils.rm_rf("#{clone_path}/#{result_name}")
43
- to.delete
44
- end
45
-
46
- it 'mirrors from service to service with ' \
47
- 'force_create_destination option' do
48
- skip
49
- # Setup
50
- from = GitDuplicator::Services::GithubRepository
51
- .new('naught', 'avdi')
52
- to = GitDuplicator::Services::BitbucketRepository
53
- .new(ENV['TESTING_REPO'], ENV['BITBUCKET_USER'], credentials)
54
- GitDuplicator.perform(from, to,
55
- clone_path: clone_path,
56
- force_create_destination: true)
57
- mirrored_name = random_name
58
- result_name = random_name
59
-
60
- # Exercise
61
- mirrored = Git.clone(from.url, mirrored_name, path: clone_path)
62
- result = Git.clone(from.url, result_name, path: clone_path)
63
-
64
- # Verify
65
- expect(result.object('HEAD^').to_s).to eq(mirrored.object('HEAD^').to_s)
66
-
67
- # Teardown
68
- FileUtils.rm_rf("#{clone_path}/#{mirrored_name}")
69
- FileUtils.rm_rf("#{clone_path}/#{result_name}")
70
- to.delete
71
- end
72
-
73
- it 'mirrors from basic to service with ' \
74
- 'force_create_destination option' do
75
- skip
76
- # Setup
77
- from = GitDuplicator::Repository
78
- .new('naught', 'https://github.com/avdi/naught.git')
79
- to = GitDuplicator::Services::BitbucketRepository
80
- .new(ENV['TESTING_REPO'], ENV['BITBUCKET_USER'], credentials)
81
- GitDuplicator.perform(from, to,
82
- clone_path: clone_path,
83
- force_create_destination: true)
84
- mirrored_name = random_name
85
- result_name = random_name
86
-
87
- # Exercise
88
- mirrored = Git.clone(from.url, mirrored_name, path: clone_path)
89
- result = Git.clone(from.url, result_name, path: clone_path)
90
-
91
- # Verify
92
- expect(result.object('HEAD^').to_s).to eq(mirrored.object('HEAD^').to_s)
93
-
94
- # Teardown
95
- FileUtils.rm_rf("#{clone_path}/#{mirrored_name}")
96
- FileUtils.rm_rf("#{clone_path}/#{result_name}")
97
- to.delete
24
+ describe '#perform_for_update' do
25
+ it 'delegates to UpdateDuplicator' do
26
+ expect(GitDuplicator::UpdateDuplicator)
27
+ .to receive(:new).with(from, to, options).and_return(result)
28
+ expect(result).to receive(:perform)
29
+ GitDuplicator.perform_for_update(from, to, options)
98
30
  end
99
-
100
31
  end
101
-
102
32
  end