blob: 1045174c86b6b9f32c852feb6e9a0f80062cb2c5 [file] [log] [blame]
Anthony Sottile635fa7d2015-03-20 16:15:09 -07001from __future__ import absolute_import
2from __future__ import unicode_literals
3
Alexander Dupuy5c752932015-05-07 23:04:15 +02004import os
Anthony Sottile4a01f642016-05-26 11:20:32 -07005import shutil
Guy Kisel779a4292015-03-13 16:30:14 -07006
7import pytest
8
9from pre_commit_hooks.check_merge_conflict import detect_merge_conflict
Anthony Sottile635fa7d2015-03-20 16:15:09 -070010from pre_commit_hooks.util import cmd_output
Anthony Sottile4a01f642016-05-26 11:20:32 -070011from testing.util import get_resource_path
Guy Kisel779a4292015-03-13 16:30:14 -070012
Anthony Sottile635fa7d2015-03-20 16:15:09 -070013
Anthony Sottile4ab79142018-01-21 15:31:23 -080014@pytest.fixture
Anthony Sottilea99475a2016-05-27 14:09:50 -070015def f1_is_a_conflict_file(tmpdir):
Anthony Sottile635fa7d2015-03-20 16:15:09 -070016 # Make a merge conflict
Anthony Sottilea99475a2016-05-27 14:09:50 -070017 repo1 = tmpdir.join('repo1')
18 repo1_f1 = repo1.join('f1')
19 repo2 = tmpdir.join('repo2')
20 repo2_f1 = repo2.join('f1')
Anthony Sottile635fa7d2015-03-20 16:15:09 -070021
Sander Maijers9e89b762016-06-12 18:49:44 +020022 cmd_output('git', 'init', '--', repo1.strpath)
Anthony Sottilea99475a2016-05-27 14:09:50 -070023 with repo1.as_cwd():
24 repo1_f1.ensure()
Sander Maijers9e89b762016-06-12 18:49:44 +020025 cmd_output('git', 'add', '--', repo1_f1.strpath)
26 cmd_output('git', 'commit', '--no-gpg-sign', '-m', 'commit1')
Anthony Sottilea99475a2016-05-27 14:09:50 -070027
28 cmd_output('git', 'clone', repo1.strpath, repo2.strpath)
Anthony Sottile635fa7d2015-03-20 16:15:09 -070029
30 # Commit in master
Anthony Sottilea99475a2016-05-27 14:09:50 -070031 with repo1.as_cwd():
32 repo1_f1.write('parent\n')
Sander Maijers9e89b762016-06-12 18:49:44 +020033 cmd_output('git', 'commit', '--no-gpg-sign', '-am', 'master commit2')
Anthony Sottile635fa7d2015-03-20 16:15:09 -070034
35 # Commit in clone and pull
Anthony Sottilea99475a2016-05-27 14:09:50 -070036 with repo2.as_cwd():
37 repo2_f1.write('child\n')
Sander Maijers9e89b762016-06-12 18:49:44 +020038 cmd_output('git', 'commit', '--no-gpg-sign', '-am', 'clone commit2')
Anthony Sottileda8ab1f2018-03-26 08:33:11 -070039 cmd_output('git', 'pull', '--no-rebase', retcode=None)
Anthony Sottile635fa7d2015-03-20 16:15:09 -070040 # We should end up in a merge conflict!
Anthony Sottilea99475a2016-05-27 14:09:50 -070041 f1 = repo2_f1.read()
William Tingc92b4652016-04-30 20:35:33 -070042 assert f1.startswith(
Anthony Sottile635fa7d2015-03-20 16:15:09 -070043 '<<<<<<< HEAD\n'
44 'child\n'
45 '=======\n'
46 'parent\n'
Anthony Sottile2a902e02017-07-12 18:35:24 -070047 '>>>>>>>',
William Tingc92b4652016-04-30 20:35:33 -070048 ) or f1.startswith(
49 '<<<<<<< HEAD\n'
50 'child\n'
51 # diff3 conflict style git merges add this line:
52 '||||||| merged common ancestors\n'
53 '=======\n'
54 'parent\n'
Anthony Sottile2a902e02017-07-12 18:35:24 -070055 '>>>>>>>',
Anthony Sottile6076fd12017-06-12 10:39:07 -070056 ) or f1.startswith(
57 # .gitconfig with [pull] rebase = preserve causes a rebase which
58 # flips parent / child
59 '<<<<<<< HEAD\n'
60 'parent\n'
61 '=======\n'
62 'child\n'
Anthony Sottile2a902e02017-07-12 18:35:24 -070063 '>>>>>>>',
Anthony Sottile635fa7d2015-03-20 16:15:09 -070064 )
Alexander Dupuy5c752932015-05-07 23:04:15 +020065 assert os.path.exists(os.path.join('.git', 'MERGE_MSG'))
Anthony Sottile9b1b44e2018-03-26 08:44:14 -070066 yield repo2
Anthony Sottile635fa7d2015-03-20 16:15:09 -070067
68
Anthony Sottile4ab79142018-01-21 15:31:23 -080069@pytest.fixture
Anthony Sottile9b1b44e2018-03-26 08:44:14 -070070def repository_pending_merge(tmpdir):
Alexander Dupuy5c752932015-05-07 23:04:15 +020071 # Make a (non-conflicting) merge
Anthony Sottilea99475a2016-05-27 14:09:50 -070072 repo1 = tmpdir.join('repo1')
73 repo1_f1 = repo1.join('f1')
74 repo2 = tmpdir.join('repo2')
75 repo2_f1 = repo2.join('f1')
76 repo2_f2 = repo2.join('f2')
77 cmd_output('git', 'init', repo1.strpath)
78 with repo1.as_cwd():
79 repo1_f1.ensure()
Sander Maijers9e89b762016-06-12 18:49:44 +020080 cmd_output('git', 'add', '--', repo1_f1.strpath)
81 cmd_output('git', 'commit', '--no-gpg-sign', '-m', 'commit1')
Alexander Dupuy5c752932015-05-07 23:04:15 +020082
Anthony Sottilea99475a2016-05-27 14:09:50 -070083 cmd_output('git', 'clone', repo1.strpath, repo2.strpath)
Alexander Dupuy5c752932015-05-07 23:04:15 +020084
85 # Commit in master
Anthony Sottilea99475a2016-05-27 14:09:50 -070086 with repo1.as_cwd():
87 repo1_f1.write('parent\n')
Sander Maijers9e89b762016-06-12 18:49:44 +020088 cmd_output('git', 'commit', '--no-gpg-sign', '-am', 'master commit2')
Alexander Dupuy5c752932015-05-07 23:04:15 +020089
90 # Commit in clone and pull without committing
Anthony Sottilea99475a2016-05-27 14:09:50 -070091 with repo2.as_cwd():
92 repo2_f2.write('child\n')
Sander Maijers9e89b762016-06-12 18:49:44 +020093 cmd_output('git', 'add', '--', repo2_f2.strpath)
94 cmd_output('git', 'commit', '--no-gpg-sign', '-m', 'clone commit2')
Anthony Sottile6076fd12017-06-12 10:39:07 -070095 cmd_output('git', 'pull', '--no-commit', '--no-rebase')
Alexander Dupuy5c752932015-05-07 23:04:15 +020096 # We should end up in a pending merge
Anthony Sottilea99475a2016-05-27 14:09:50 -070097 assert repo2_f1.read() == 'parent\n'
98 assert repo2_f2.read() == 'child\n'
Alexander Dupuy5c752932015-05-07 23:04:15 +020099 assert os.path.exists(os.path.join('.git', 'MERGE_HEAD'))
Anthony Sottile9b1b44e2018-03-26 08:44:14 -0700100 yield repo2
Alexander Dupuy5c752932015-05-07 23:04:15 +0200101
102
103@pytest.mark.usefixtures('f1_is_a_conflict_file')
104def test_merge_conflicts_git():
105 assert detect_merge_conflict(['f1']) == 1
106
107
Anthony Sottile635fa7d2015-03-20 16:15:09 -0700108@pytest.mark.parametrize(
Anthony Sottile9b1b44e2018-03-26 08:44:14 -0700109 'contents', (b'<<<<<<< HEAD\n', b'=======\n', b'>>>>>>> master\n'),
Guy Kisel779a4292015-03-13 16:30:14 -0700110)
Anthony Sottile9b1b44e2018-03-26 08:44:14 -0700111def test_merge_conflicts_failing(contents, repository_pending_merge):
112 repository_pending_merge.join('f2').write_binary(contents)
Alexander Dupuy5c752932015-05-07 23:04:15 +0200113 assert detect_merge_conflict(['f2']) == 1
Guy Kisel779a4292015-03-13 16:30:14 -0700114
115
Anthony Sottile635fa7d2015-03-20 16:15:09 -0700116@pytest.mark.parametrize(
Anthony Sottile9b1b44e2018-03-26 08:44:14 -0700117 'contents', (b'# <<<<<<< HEAD\n', b'# =======\n', b'import mod', b''),
Anthony Sottile635fa7d2015-03-20 16:15:09 -0700118)
Anthony Sottile9b1b44e2018-03-26 08:44:14 -0700119def test_merge_conflicts_ok(contents, f1_is_a_conflict_file):
120 f1_is_a_conflict_file.join('f1').write_binary(contents)
Anthony Sottile635fa7d2015-03-20 16:15:09 -0700121 assert detect_merge_conflict(['f1']) == 0
Guy Kisel779a4292015-03-13 16:30:14 -0700122
Guy Kisel779a4292015-03-13 16:30:14 -0700123
Anthony Sottile4a01f642016-05-26 11:20:32 -0700124@pytest.mark.usefixtures('f1_is_a_conflict_file')
125def test_ignores_binary_files():
126 shutil.copy(get_resource_path('img1.jpg'), 'f1')
127 assert detect_merge_conflict(['f1']) == 0
128
129
Anthony Sottilea99475a2016-05-27 14:09:50 -0700130def test_does_not_care_when_not_in_a_merge(tmpdir):
131 tmpdir.join('README.md').write('problem\n=======\n')
Anthony Sottile635fa7d2015-03-20 16:15:09 -0700132 assert detect_merge_conflict(['README.md']) == 0