git_duplicator 0.0.1 → 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.
@@ -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