git_lib 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.dependabot/config.yml +10 -0
- data/.github/workflows/gem_release.yml +37 -0
- data/.gitignore +53 -0
- data/.jenkins/Jenkinsfile +72 -0
- data/.jenkins/ruby_build_pod.yml +19 -0
- data/.rspec +3 -0
- data/.rubocop.yml +43 -0
- data/.ruby-version +1 -0
- data/Appraisals +13 -0
- data/CHANGELOG.md +24 -0
- data/Gemfile +21 -0
- data/Gemfile.lock +121 -0
- data/README.md +9 -0
- data/Rakefile +17 -0
- data/gemfiles/.bundle/config +2 -0
- data/gemfiles/rails_4.gemfile +21 -0
- data/gemfiles/rails_5.gemfile +21 -0
- data/gemfiles/rails_6.gemfile +21 -0
- data/git_lib.gemspec +25 -0
- data/lib/git/git.rb +186 -0
- data/lib/git/git_branch.rb +35 -0
- data/lib/git/git_commit.rb +23 -0
- data/lib/git/git_conflict.rb +29 -0
- data/lib/git/git_error.rb +14 -0
- data/lib/git/git_test_helpers.rb +38 -0
- data/lib/git/version.rb +5 -0
- data/lib/git_lib.rb +7 -0
- data/spec/lib/git/git_branch_spec.rb +57 -0
- data/spec/lib/git/git_conflict_spec.rb +50 -0
- data/spec/lib/git/git_error_spec.rb +19 -0
- data/spec/lib/git/git_spec.rb +436 -0
- data/spec/spec_helper.rb +30 -0
- metadata +100 -0
data/lib/git/version.rb
ADDED
data/lib/git_lib.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require_relative '../../../lib/git/git_branch.rb'
|
5
|
+
|
6
|
+
describe 'Git::GitBranch' do
|
7
|
+
it 'can be created' do
|
8
|
+
last_modified_date = Time.current
|
9
|
+
branch = Git::GitBranch.new('repository_name', 'name', last_modified_date, 'author_name', 'author@email.com')
|
10
|
+
|
11
|
+
expect(branch.repository_name).to eq('repository_name')
|
12
|
+
expect(branch.name).to eq('name')
|
13
|
+
expect(branch.last_modified_date).to eq(last_modified_date)
|
14
|
+
expect(branch.author_name).to eq('author_name')
|
15
|
+
expect(branch.author_email).to eq('author@email.com')
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'implements regexp operator' do
|
19
|
+
branch = Git::GitBranch.new('repository_name', 'verylongname', Time.current, 'author_name', 'author@email.com')
|
20
|
+
|
21
|
+
expect(branch =~ /.*long.*/).to be_truthy
|
22
|
+
expect(branch =~ /nomatch/).to be_falsey
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'implements equality operator' do
|
26
|
+
last_modified_date = Time.current
|
27
|
+
branch_a = Git::GitBranch.new('repository_name', 'name', last_modified_date, 'author_name', 'author@email.com')
|
28
|
+
|
29
|
+
branch_b = Git::GitBranch.new('repository_name', 'name', last_modified_date, 'author_name', 'author@email.com')
|
30
|
+
expect(branch_a).to eq(branch_b)
|
31
|
+
|
32
|
+
branch_c = Git::GitBranch.new('different', 'name', last_modified_date, 'author_name', 'author@email.com')
|
33
|
+
expect(branch_a).not_to eq(branch_c)
|
34
|
+
|
35
|
+
branch_d = Git::GitBranch.new('repository_name', 'different', last_modified_date, 'author_name', 'author@email.com')
|
36
|
+
expect(branch_a).not_to eq(branch_d)
|
37
|
+
|
38
|
+
branch_e = Git::GitBranch.new('repository_name', 'name', Time.current, 'author_name', 'author@email.com')
|
39
|
+
expect(branch_a).not_to eq(branch_e)
|
40
|
+
|
41
|
+
branch_f = Git::GitBranch.new('repository_name', 'name', last_modified_date, 'different', 'author@email.com')
|
42
|
+
expect(branch_a).not_to eq(branch_f)
|
43
|
+
|
44
|
+
branch_g = Git::GitBranch.new('repository_name', 'name', last_modified_date, 'author_name', 'different@email.com')
|
45
|
+
expect(branch_a).not_to eq(branch_g)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'returns its name when converted to string' do
|
49
|
+
branch = Git::GitBranch.new('repository_name', 'name', Time.current, 'author_name', 'author@email.com')
|
50
|
+
expect(branch.to_s).to eq('name')
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'parses branch name from ref' do
|
54
|
+
expect(Git::GitBranch.name_from_ref('refs/heads/branch_name')).to eq('branch_name')
|
55
|
+
expect(Git::GitBranch.name_from_ref('branch_name')).to eq('branch_name')
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require_relative '../../../lib/git/git_conflict.rb'
|
5
|
+
|
6
|
+
describe 'Git::GitConflict' do
|
7
|
+
it 'can be created' do
|
8
|
+
conflict = Git::GitConflict.new('repository_name', 'branch_a', 'branch_b', ['file1', 'file2'])
|
9
|
+
|
10
|
+
expect(conflict.repository_name).to eq('repository_name')
|
11
|
+
expect(conflict.branch_a).to eq('branch_a')
|
12
|
+
expect(conflict.branch_b).to eq('branch_b')
|
13
|
+
expect(conflict.conflicting_files).to eq(['file1', 'file2'])
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'cannot be created without conflicting files' do
|
17
|
+
expect { Git::GitConflict.new('repository_name', 'branch_a', 'branch_b', nil) }.to \
|
18
|
+
raise_exception(ArgumentError, 'Must specify conflicting file list')
|
19
|
+
expect { Git::GitConflict.new('repository_name', 'branch_a', 'branch_b', []) }.to \
|
20
|
+
raise_exception(ArgumentError, 'Must specify conflicting file list')
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'implements equality operator' do
|
24
|
+
conflict_a = Git::GitConflict.new('repository_name', 'branch_a', 'branch_b', ['file1', 'file2'])
|
25
|
+
|
26
|
+
conflict_b = Git::GitConflict.new('repository_name', 'branch_a', 'branch_b', ['file1', 'file2'])
|
27
|
+
expect(conflict_a).to eq(conflict_b)
|
28
|
+
|
29
|
+
conflict_c = Git::GitConflict.new('different', 'branch_a', 'branch_b', ['file1', 'file2'])
|
30
|
+
expect(conflict_a).not_to eq(conflict_c)
|
31
|
+
|
32
|
+
conflict_d = Git::GitConflict.new('repository_name', 'different', 'branch_b', ['file1', 'file2'])
|
33
|
+
expect(conflict_a).not_to eq(conflict_d)
|
34
|
+
|
35
|
+
conflict_e = Git::GitConflict.new('repository_name', 'branch_a', 'different', ['file1', 'file2'])
|
36
|
+
expect(conflict_a).not_to eq(conflict_e)
|
37
|
+
|
38
|
+
conflict_f = Git::GitConflict.new('repository_name', 'branch_a', 'branch_b', ['different', 'file2'])
|
39
|
+
expect(conflict_a).not_to eq(conflict_f)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'can determine if it contains the specified branch' do
|
43
|
+
conflict = Git::GitConflict.new('repository_name', 'branch_a', 'branch_b', ['file1', 'file2'])
|
44
|
+
|
45
|
+
expect(conflict.contains_branch('branch_a')).to be_truthy
|
46
|
+
expect(conflict.contains_branch('branch_b')).to be_truthy
|
47
|
+
|
48
|
+
expect(conflict.contains_branch('branch_c')).to be_falsey
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require_relative '../../../lib/git/git_error.rb'
|
5
|
+
|
6
|
+
describe 'Git::GitError' do
|
7
|
+
it 'can be raised' do
|
8
|
+
expect { raise Git::GitError.new('command', 200, 'error_message') }.to \
|
9
|
+
raise_exception(Git::GitError, "Git command command failed with exit code 200. Message:\nerror_message")
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'can be printed' do
|
13
|
+
begin
|
14
|
+
raise Git::GitError.new('command', 200, 'error_message')
|
15
|
+
rescue Git::GitError => e
|
16
|
+
expect(e.message).to eq("Git command command failed with exit code 200. Message:\nerror_message")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,436 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require_relative '../../../lib/git/git.rb'
|
5
|
+
|
6
|
+
# rubocop:disable Metrics/LineLength
|
7
|
+
describe 'Git::Git' do
|
8
|
+
include FakeFS::SpecHelpers
|
9
|
+
|
10
|
+
def create_mock_open_status(status)
|
11
|
+
status_object = double
|
12
|
+
allow(status_object).to receive(:success?) { status == 1 }
|
13
|
+
allow(status_object).to receive(:to_s) { status.to_s }
|
14
|
+
status_object
|
15
|
+
end
|
16
|
+
|
17
|
+
def mock_execute(stdout_andstderr_str, status, execution_count: 1, expected_command: anything)
|
18
|
+
# mock the call and repsonse to execute the git command
|
19
|
+
expect(Open3).to receive(:capture2e).exactly(execution_count).times do |*args|
|
20
|
+
if !expected_command.is_a?(RSpec::Mocks::ArgumentMatchers::AnyArgMatcher) && !expected_command.nil?
|
21
|
+
# remove the options hash, we are not going to verify it's contents
|
22
|
+
args.reject! { |arg| arg.is_a?(Hash) }
|
23
|
+
|
24
|
+
# confirm we got the args we expected
|
25
|
+
expect(args).to eq(expected_command.split(/ /))
|
26
|
+
end
|
27
|
+
[stdout_andstderr_str, create_mock_open_status(status)]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'can be created' do
|
32
|
+
git = Git::Git.new('repository_name')
|
33
|
+
|
34
|
+
expect(git.repository_url).to eq('git@github.com:repository_name.git')
|
35
|
+
expect(git.repository_path).to eq('/tmp/git/repository_name')
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'can be created with a different cache path' do
|
39
|
+
git = Git::Git.new('repository_name', git_cache_path: './mycache')
|
40
|
+
|
41
|
+
expect(git.repository_url).to eq('git@github.com:repository_name.git')
|
42
|
+
expect(git.repository_path).to eq('./mycache/repository_name')
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'with a git repository' do
|
46
|
+
before do
|
47
|
+
@git = Git::Git.new('repository_name')
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'can execute a command' do
|
51
|
+
mock_execute('sample output', 1)
|
52
|
+
expect(@git.execute('sample command')).to eq('sample output')
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'raises GitError when a command fails' do
|
56
|
+
mock_execute('sample output', 0)
|
57
|
+
expect { @git.execute('sample command') }.to raise_exception(Git::GitError)
|
58
|
+
end
|
59
|
+
|
60
|
+
describe 'clone_repository' do
|
61
|
+
it 'can clone into a new directory' do
|
62
|
+
response = \
|
63
|
+
"Cloning into '#{@git.repository_name}'..." \
|
64
|
+
'remote: Counting objects: 1080, done.' \
|
65
|
+
'remote: Compressing objects: 100% (83/83), done.' \
|
66
|
+
'remote: Total 1080 (delta 34), reused 0 (delta 0), pack-reused 994' \
|
67
|
+
'Receiving objects: 100% (1080/1080), 146.75 KiB | 0 bytes/s, done.' \
|
68
|
+
'Resolving deltas: 100% (641/641), done.' \
|
69
|
+
'Checking connectivity... done.'
|
70
|
+
mock_execute(response, 1)
|
71
|
+
@git.clone_repository('default_branch')
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'can update a previously cloned repository' do
|
75
|
+
expect(@git).to receive(:reset).exactly(1).times
|
76
|
+
expect(@git).to receive(:checkout_branch)
|
77
|
+
mock_execute('Success', 1, execution_count: 3)
|
78
|
+
FileUtils.mkpath(@git.repository_path)
|
79
|
+
@git.clone_repository('default_branch')
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe 'push' do
|
84
|
+
it 'can push a branch' do
|
85
|
+
response = \
|
86
|
+
'Counting objects: 20, done.' \
|
87
|
+
'Delta compression using up to 8 threads.' \
|
88
|
+
'Compressing objects: 100% (18/18), done.' \
|
89
|
+
'Writing objects: 100% (20/20), 2.47 KiB | 0 bytes/s, done.' \
|
90
|
+
'Total 20 (delta 11), reused 0 (delta 0)' \
|
91
|
+
"To #{@git.repository_url}" \
|
92
|
+
'19087ab..9cdd9db master -> master'
|
93
|
+
mock_execute(response, 1)
|
94
|
+
expect(@git.push).to eq(true)
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'can push a branch using dry run' do
|
98
|
+
response = \
|
99
|
+
"To #{@git.repository_url}" \
|
100
|
+
'19087ab..9cdd9db master -> master'
|
101
|
+
mock_execute(response, 1, expected_command: '/usr/bin/git push --dry-run origin')
|
102
|
+
expect(@git.push(dry_run: true)).to eq(true)
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'can detect if a push results in a no-op' do
|
106
|
+
mock_execute("Everything up-to-date\n", 1)
|
107
|
+
expect(@git.push).to eq(false)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe 'checkout_branch' do
|
112
|
+
it 'can checkout a branch' do
|
113
|
+
expect(@git).to receive(:reset).exactly(2).times
|
114
|
+
mock_execute('Success', 1)
|
115
|
+
@git.checkout_branch('branch_name')
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'escapes backticks in branch names' do
|
119
|
+
expect(@git).to receive(:reset).exactly(2).times
|
120
|
+
mock_execute('sample output', 1, expected_command: '/usr/bin/git checkout branch_\\`name')
|
121
|
+
@git.checkout_branch('branch_`name')
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
describe 'reset' do
|
126
|
+
it 'can reset a branch to HEAD of origin' do
|
127
|
+
expect(@git).to receive(:current_branch_name).and_return('master')
|
128
|
+
mock_execute("HEAD is now at beb5e09 Merge branch 'master'", 1)
|
129
|
+
@git.reset
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'escapes backticks in branch names' do
|
133
|
+
expect(@git).to receive(:current_branch_name).and_return('branch_`name')
|
134
|
+
mock_execute('sample output', 1, expected_command: '/usr/bin/git reset --hard origin/branch_\\`name')
|
135
|
+
@git.reset
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe 'get_branch_list' do
|
140
|
+
it 'can parse a branch list' do
|
141
|
+
mock_execute(
|
142
|
+
"origin/test_1~2015-10-19 17:58:24 -0700~Nicholas Ellis~<nellis@invoca.com>\norigin/test_build~2015-10-19 15:03:22 -0700~Bob Smith~<bob@invoca.com>\norigin/test_build_b~2015-10-19 16:52:40 -0700~Nicholas Ellis~<nellis@invoca.com>",
|
143
|
+
1
|
144
|
+
)
|
145
|
+
|
146
|
+
branch_list = []
|
147
|
+
branch_list << Git::GitBranch.new(
|
148
|
+
'repository_name',
|
149
|
+
'test_1',
|
150
|
+
DateTime.iso8601('2015-10-19T17:58:24-0700'),
|
151
|
+
'Nicholas Ellis',
|
152
|
+
'nellis@invoca.com'
|
153
|
+
)
|
154
|
+
branch_list << Git::GitBranch.new(
|
155
|
+
'repository_name',
|
156
|
+
'test_build',
|
157
|
+
DateTime.iso8601('2015-10-19T15:03:22-0700'),
|
158
|
+
'Bob Smith',
|
159
|
+
'bob@invoca.com'
|
160
|
+
)
|
161
|
+
branch_list << Git::GitBranch.new(
|
162
|
+
'repository_name',
|
163
|
+
'test_build_b',
|
164
|
+
DateTime.iso8601('2015-10-19T16:52:40-0700'),
|
165
|
+
'Nicholas Ellis',
|
166
|
+
'nellis@invoca.com'
|
167
|
+
)
|
168
|
+
|
169
|
+
expect(@git.branch_list).to eq(branch_list)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
describe 'merge_branches' do
|
174
|
+
it 'returns false, with conflicts, if merge is not clean' do
|
175
|
+
expect(@git).to receive(:current_branch_name).and_return('91/eb/WEB-1723_Ringswitch_DB_Conn_Loss')
|
176
|
+
mock_execute(
|
177
|
+
"From github.com:/Invoca/web\n" \
|
178
|
+
" * branch 85/t/trello_adwords_dashboard_tiles_auto_adjust_font_size -> FETCH_HEAD\n" \
|
179
|
+
"warning: Cannot merge binary files: test/fixtures/whitepages.sql (HEAD vs. fedc8e0cfa136d5e1f84005ab6d82235122b0006)\n" \
|
180
|
+
"Auto-merging test/workers/adwords_detail_worker_test.rb\n" \
|
181
|
+
"CONFLICT (content): Merge conflict in test/workers/adwords_detail_worker_test.rb\n" \
|
182
|
+
"CONFLICT (modify/delete): pegasus/backdraft/pegasus_dashboard/spec/views/call_cost_tile_spec.js deleted in fedc8e0cfa136d5e1f84005ab6d82235122b0006 and modified in HEAD. Version HEAD of pegasus/backdraft/pegasus_dashboard/spec/views/call_cost_tile_spec.js left in tree.\n" \
|
183
|
+
" Auto-merging pegasus/backdraft/dist/pegasus_dashboard.js\n" \
|
184
|
+
"Automatic merge failed; fix conflicts and then commit the result.\n",
|
185
|
+
0
|
186
|
+
)
|
187
|
+
|
188
|
+
conflict = Git::GitConflict.new(
|
189
|
+
'repository_name',
|
190
|
+
'91/eb/WEB-1723_Ringswitch_DB_Conn_Loss',
|
191
|
+
'85/t/trello_adwords_dashboard_tiles_auto_adjust_font_size',
|
192
|
+
['test/workers/adwords_detail_worker_test.rb', 'pegasus/backdraft/pegasus_dashboard/spec/views/call_cost_tile_spec.js']
|
193
|
+
)
|
194
|
+
expect(
|
195
|
+
@git.merge_branches(
|
196
|
+
'91/eb/WEB-1723_Ringswitch_DB_Conn_Loss',
|
197
|
+
'85/t/trello_adwords_dashboard_tiles_auto_adjust_font_size'
|
198
|
+
)
|
199
|
+
).to eq([false, conflict])
|
200
|
+
end
|
201
|
+
|
202
|
+
it 'aborts unsuccessful merge if requested' do
|
203
|
+
expect(@git).to receive(:current_branch_name).and_return('91/eb/WEB-1723_Ringswitch_DB_Conn_Loss')
|
204
|
+
mock_execute(
|
205
|
+
"From github.com:/Invoca/web\n" \
|
206
|
+
" * branch 85/t/trello_adwords_dashboard_tiles_auto_adjust_font_size -> FETCH_HEAD\n" \
|
207
|
+
"warning: Cannot merge binary files: test/fixtures/whitepages.sql (HEAD vs. fedc8e0cfa136d5e1f84005ab6d82235122b0006)\n" \
|
208
|
+
"Auto-merging test/workers/adwords_detail_worker_test.rb\n" \
|
209
|
+
"CONFLICT (content): Merge conflict in test/workers/adwords_detail_worker_test.rb\n" \
|
210
|
+
"CONFLICT (modify/delete): pegasus/backdraft/pegasus_dashboard/spec/views/call_cost_tile_spec.js deleted in fedc8e0cfa136d5e1f84005ab6d82235122b0006 and modified in HEAD. Version HEAD of pegasus/backdraft/pegasus_dashboard/spec/views/call_cost_tile_spec.js left in tree.\n" \
|
211
|
+
" Auto-merging pegasus/backdraft/dist/pegasus_dashboard.js\n" \
|
212
|
+
'Automatic merge failed; fix conflicts and then commit the result.',
|
213
|
+
0
|
214
|
+
)
|
215
|
+
expect(@git).to receive(:reset)
|
216
|
+
|
217
|
+
conflict = Git::GitConflict.new(
|
218
|
+
'repository_name',
|
219
|
+
'91/eb/WEB-1723_Ringswitch_DB_Conn_Loss',
|
220
|
+
'85/t/trello_adwords_dashboard_tiles_auto_adjust_font_size',
|
221
|
+
[
|
222
|
+
'test/workers/adwords_detail_worker_test.rb',
|
223
|
+
'pegasus/backdraft/pegasus_dashboard/spec/views/call_cost_tile_spec.js'
|
224
|
+
]
|
225
|
+
)
|
226
|
+
expect(
|
227
|
+
@git.merge_branches(
|
228
|
+
'91/eb/WEB-1723_Ringswitch_DB_Conn_Loss',
|
229
|
+
'85/t/trello_adwords_dashboard_tiles_auto_adjust_font_size',
|
230
|
+
keep_changes: false
|
231
|
+
)
|
232
|
+
).to eq([false, conflict])
|
233
|
+
end
|
234
|
+
|
235
|
+
it 'aborts successful merge if requested' do
|
236
|
+
expect(@git).to receive(:current_branch_name).and_return('91/eb/WEB-1723_Ringswitch_DB_Conn_Loss')
|
237
|
+
mock_execute(
|
238
|
+
"From github.com:/Invoca/web\n" \
|
239
|
+
" * branch 85/t/trello_adwords_dashboard_tiles_auto_adjust_font_size -> FETCH_HEAD\n" \
|
240
|
+
"Auto-merging test/workers/adwords_detail_worker_test.rb\n" \
|
241
|
+
" Auto-merging pegasus/backdraft/dist/pegasus_dashboard.js\n",
|
242
|
+
1
|
243
|
+
)
|
244
|
+
expect(@git).to receive(:reset)
|
245
|
+
|
246
|
+
expect(
|
247
|
+
@git.merge_branches(
|
248
|
+
'91/eb/WEB-1723_Ringswitch_DB_Conn_Loss',
|
249
|
+
'85/t/trello_adwords_dashboard_tiles_auto_adjust_font_size',
|
250
|
+
keep_changes: false
|
251
|
+
)
|
252
|
+
).to eq([true, nil])
|
253
|
+
end
|
254
|
+
|
255
|
+
it 'returns true, with no conflicts, if merge is clean' do
|
256
|
+
expect(@git).to receive(:current_branch_name).and_return('91/eb/WEB-1723_Ringswitch_DB_Conn_Loss')
|
257
|
+
mock_execute(
|
258
|
+
"From github.com:/Invoca/web\n" \
|
259
|
+
" * branch 85/t/trello_adwords_dashboard_tiles_auto_adjust_font_size -> FETCH_HEAD\n" \
|
260
|
+
"Auto-merging test/workers/adwords_detail_worker_test.rb\n" \
|
261
|
+
" Auto-merging pegasus/backdraft/dist/pegasus_dashboard.js\n",
|
262
|
+
1
|
263
|
+
)
|
264
|
+
|
265
|
+
expect(
|
266
|
+
@git.merge_branches(
|
267
|
+
'91/eb/WEB-1723_Ringswitch_DB_Conn_Loss',
|
268
|
+
'85/t/trello_adwords_dashboard_tiles_auto_adjust_font_size'
|
269
|
+
)
|
270
|
+
).to eq([true, nil])
|
271
|
+
end
|
272
|
+
|
273
|
+
it 'returns false, with no conflicts, if nothing is merged' do
|
274
|
+
expect(@git).to receive(:current_branch_name).and_return('91/eb/WEB-1723_Ringswitch_DB_Conn_Loss')
|
275
|
+
mock_execute(
|
276
|
+
"From github.com:mikeweaver/git-conflict-detector\n" \
|
277
|
+
" * branch master -> FETCH_HEAD\n" \
|
278
|
+
"Already up-to-date.\n",
|
279
|
+
1
|
280
|
+
)
|
281
|
+
expect(
|
282
|
+
@git.merge_branches(
|
283
|
+
'91/eb/WEB-1723_Ringswitch_DB_Conn_Loss',
|
284
|
+
'85/t/trello_adwords_dashboard_tiles_auto_adjust_font_size'
|
285
|
+
)
|
286
|
+
).to eq([false, nil])
|
287
|
+
end
|
288
|
+
|
289
|
+
it 'checks out branch if needed' do
|
290
|
+
expect(@git).to receive(:current_branch_name).and_return('not_the_right_branch')
|
291
|
+
expect(@git).to receive(:checkout_branch)
|
292
|
+
mock_execute(
|
293
|
+
"From github.com:mikeweaver/git-conflict-detector\n" \
|
294
|
+
" * branch master -> FETCH_HEAD\n" \
|
295
|
+
"Already up-to-date.\n",
|
296
|
+
1
|
297
|
+
)
|
298
|
+
expect(
|
299
|
+
@git.merge_branches(
|
300
|
+
'91/eb/WEB-1723_Ringswitch_DB_Conn_Loss',
|
301
|
+
'85/t/trello_adwords_dashboard_tiles_auto_adjust_font_size'
|
302
|
+
)
|
303
|
+
).to eq([false, nil])
|
304
|
+
end
|
305
|
+
|
306
|
+
it 'merges a tag, if requested' do
|
307
|
+
expect(@git).to receive(:current_branch_name).and_return('91/eb/WEB-1723_Ringswitch_DB_Conn_Loss')
|
308
|
+
mock_execute(
|
309
|
+
"From github.com:/Invoca/web\n" \
|
310
|
+
" * branch 85/t/trello_adwords_dashboard_tiles_auto_adjust_font_size -> FETCH_HEAD\n" \
|
311
|
+
"Auto-merging test/workers/adwords_detail_worker_test.rb\n" \
|
312
|
+
" Auto-merging pegasus/backdraft/dist/pegasus_dashboard.js\n",
|
313
|
+
1
|
314
|
+
)
|
315
|
+
|
316
|
+
expect(
|
317
|
+
@git.merge_branches(
|
318
|
+
'91/eb/WEB-1723_Ringswitch_DB_Conn_Loss',
|
319
|
+
'85/t/trello_adwords_dashboard_tiles_auto_adjust_font_size',
|
320
|
+
source_tag_name: 'tag_name'
|
321
|
+
)
|
322
|
+
).to eq([true, nil])
|
323
|
+
end
|
324
|
+
|
325
|
+
it 'escapes backticks and spaces in branch names but not commit messages' do
|
326
|
+
expect(@git).to receive(:current_branch_name).and_return('target`name')
|
327
|
+
mock_execute(
|
328
|
+
"From github.com:/Invoca/web\n" \
|
329
|
+
" * branch 85/t/trello_adwords_dashboard_tiles_auto_adjust_font_size -> FETCH_HEAD\n" \
|
330
|
+
"Auto-merging test/workers/adwords_detail_worker_test.rb\n",
|
331
|
+
1,
|
332
|
+
expected_command: '/usr/bin/git merge --no-edit -m "commit `message" origin/source\\`name\ space'
|
333
|
+
)
|
334
|
+
|
335
|
+
@git.merge_branches(
|
336
|
+
'target`name',
|
337
|
+
'source`name space',
|
338
|
+
commit_message: 'commit `message'
|
339
|
+
)
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
describe 'lookup_tag' do
|
344
|
+
it 'can lookup a tag' do
|
345
|
+
mock_execute("tag-exists\n", 1)
|
346
|
+
expect(@git.lookup_tag('tag-e*')).to eq('tag-exists')
|
347
|
+
end
|
348
|
+
|
349
|
+
it 'raises when the tag cannot be found' do
|
350
|
+
mock_execute('fatal: No names found, cannot describe anything.', 0)
|
351
|
+
expect { @git.lookup_tag('does-not-exist') }.to raise_exception(Git::GitError)
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
describe 'file_diff_branch_with_ancestor' do
|
356
|
+
it 'can diff the branch' do
|
357
|
+
mock_execute("file1.txt\nfile2.txt\n", 1)
|
358
|
+
expect(@git.file_diff_branch_with_ancestor('branch', 'ancestor_branch')).to eq(['file1.txt', 'file2.txt'])
|
359
|
+
end
|
360
|
+
|
361
|
+
it 'can handle an up to date branch' do
|
362
|
+
mock_execute('', 1)
|
363
|
+
expect(@git.file_diff_branch_with_ancestor('branch', 'ancestor_branch')).to eq([])
|
364
|
+
end
|
365
|
+
|
366
|
+
it 'escapes backticks in branch names' do
|
367
|
+
mock_execute(
|
368
|
+
"file1.txt\nfile2.txt\n",
|
369
|
+
1,
|
370
|
+
expected_command: '/usr/bin/git diff --name-only $(git merge-base origin/ancestor\\`_branch origin/branch\\`name)..origin/branch\\`name'
|
371
|
+
)
|
372
|
+
@git.file_diff_branch_with_ancestor('branch`name', 'ancestor`_branch')
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
describe 'commit_diff_refs' do
|
377
|
+
it 'can diff a branch' do
|
378
|
+
mocked_output = ["efd778098239838c165ffab2f12ad293f32824c8\tAuthor 1\tauthor1@email.com\t2016-07-14T10:09:45-07:00\tMerge branch 'production'\n",
|
379
|
+
"667f3e5347c48c04663209682642fd8d6d93fde2\tAuthor 2\tauthor2@email.com\t2016-07-14T16:46:35-07:00\tMerge pull request #5584 from Owner/repo/dimension_repair\n"].join
|
380
|
+
expected_array = [Git::GitCommit.new('efd778098239838c165ffab2f12ad293f32824c8', "Merge branch 'production'", nil, 'Author 1', 'author1@email.com'),
|
381
|
+
Git::GitCommit.new('667f3e5347c48c04663209682642fd8d6d93fde2', 'Merge pull request #5584 from Owner/repo/dimension_repair', nil, 'Author 2', 'author2@email.com')]
|
382
|
+
mock_execute(
|
383
|
+
mocked_output,
|
384
|
+
1,
|
385
|
+
expected_command: "/usr/bin/git log --format=%H\t%an\t%ae\t%aI\t%s --no-color origin/ancestor_branch..origin/branch"
|
386
|
+
)
|
387
|
+
expect(@git.commit_diff_refs('branch', 'ancestor_branch')).to eq(expected_array)
|
388
|
+
end
|
389
|
+
|
390
|
+
it 'can handle a comparison with no changes' do
|
391
|
+
mock_execute('', 1)
|
392
|
+
expect(@git.commit_diff_refs('branch', 'ancestor_branch')).to eq([])
|
393
|
+
end
|
394
|
+
|
395
|
+
it 'can fetch before doing the comparison' do
|
396
|
+
mock_execute('', 1)
|
397
|
+
expect(@git).to receive(:fetch_all)
|
398
|
+
expect(@git.commit_diff_refs('branch', 'ancestor_branch', fetch: true)).to eq([])
|
399
|
+
end
|
400
|
+
|
401
|
+
it 'can diff a sha with a branch' do
|
402
|
+
mock_execute(
|
403
|
+
'',
|
404
|
+
1,
|
405
|
+
expected_command: "/usr/bin/git log --format=%H\t%an\t%ae\t%aI\t%s --no-color origin/ancestor_branch..e2a7e607745d63da4d7f8486e0619e91a410f796"
|
406
|
+
)
|
407
|
+
@git.commit_diff_refs('e2a7e607745d63da4d7f8486e0619e91a410f796', 'ancestor_branch')
|
408
|
+
end
|
409
|
+
|
410
|
+
it 'can diff a sha with a sha' do
|
411
|
+
mock_execute(
|
412
|
+
'',
|
413
|
+
1,
|
414
|
+
expected_command: "/usr/bin/git log --format=%H\t%an\t%ae\t%aI\t%s --no-color c5e8de4eb36a2d1b9f66543966ede9ce9cc28a89..e2a7e607745d63da4d7f8486e0619e91a410f796"
|
415
|
+
)
|
416
|
+
@git.commit_diff_refs('e2a7e607745d63da4d7f8486e0619e91a410f796', 'c5e8de4eb36a2d1b9f66543966ede9ce9cc28a89')
|
417
|
+
end
|
418
|
+
|
419
|
+
it 'escapes backticks in ref names' do
|
420
|
+
mock_execute(
|
421
|
+
'',
|
422
|
+
1,
|
423
|
+
expected_command: "/usr/bin/git log --format=%H\t%an\t%ae\t%aI\t%s --no-color origin/ancestor\\`_branch..origin/branch\\`name"
|
424
|
+
)
|
425
|
+
@git.commit_diff_refs('branch`name', 'ancestor`_branch')
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
describe 'get_current_branch_name' do
|
430
|
+
it 'can get the branch name' do
|
431
|
+
mock_execute("path/branch\n", 1)
|
432
|
+
expect(@git.current_branch_name).to eq('path/branch')
|
433
|
+
end
|
434
|
+
end
|
435
|
+
end
|
436
|
+
end
|