1 import sys
, os
, subprocess
2 from tempfile
import TemporaryDirectory
3 from unittest
import TestCase
4 from pathlib
import Path
7 class CommitDropTest(TestCase
):
8 def test_drop_single_commit_by_hash(self
):
9 hash1
= self
.create_commit('commit 1')
10 self
.create_commit('commit 2')
14 self
.assertEqual(['commit 2'], self
.git
.log())
16 def test_drop_commits_by_desc(self
):
17 self
.create_commit('commit 1 is good')
18 self
.create_commit('commit 2 is bad')
19 self
.create_commit('commit 3 is good')
20 self
.create_commit('commit 4 is bad')
24 expected
= ['commit 1 is good', 'commit 3 is good']
25 self
.assertEqual(expected
, self
.git
.log())
27 def test_drop_sequential_commits_in_single_plugin_instance(self
):
28 self
.create_commit('commit 1')
29 hash2
= self
.create_commit('commit 2')
30 hash3
= self
.create_commit('commit 3')
31 hash4
= self
.create_commit('commit 4')
32 self
.create_commit('commit 5')
34 self
.drop(','.join((hash2
, hash3
, hash4
)))
36 expected
= ['commit 1', 'commit 5']
37 self
.assertEqual(expected
, self
.git
.log())
39 def test_drop_sequential_commits_in_multiple_plugin_instances(self
):
40 self
.create_commit('commit 1')
41 hash2
= self
.create_commit('commit 2')
42 hash3
= self
.create_commit('commit 3')
43 hash4
= self
.create_commit('commit 4')
44 self
.create_commit('commit 5')
46 self
.drop(hash2
, hash3
, hash4
)
48 expected
= ['commit 1', 'commit 5']
49 self
.assertEqual(expected
, self
.git
.log())
51 def test_drop_nonsequential_commits(self
):
52 self
.create_commit('commit 1')
53 hash2
= self
.create_commit('commit 2')
54 self
.create_commit('commit 3')
55 hash4
= self
.create_commit('commit 4')
57 self
.drop(','.join((hash2
, hash4
)))
59 expected
= ['commit 1', 'commit 3']
60 self
.assertEqual(expected
, self
.git
.log())
62 def test_drop_head(self
):
63 self
.create_commit('first')
64 self
.create_commit('middle')
65 hash_last
= self
.create_commit('last')
69 self
.assertEqual(['first', 'middle'], self
.git
.log())
71 def test_drop_merge_commit(self
):
72 initial_hash
= self
.create_commit('initial')
73 self
.create_commit('branch A')
74 self
.hg
.checkout(initial_hash
)
75 self
.create_commit('branch B')
77 merge_hash
= self
.create_commit('merge to drop')
78 self
.create_commit('last')
82 expected_commits
= ['initial', 'branch A', 'branch B', 'last']
83 self
.assertEqual(expected_commits
, self
.git
.log())
84 self
.assertEqual(['branch B', 'branch A'], self
.git_parents('last'))
86 def test_drop_different_commits_in_multiple_plugin_instances(self
):
87 self
.create_commit('good commit')
88 bad_hash
= self
.create_commit('bad commit')
89 self
.create_commit('awful commit')
90 self
.create_commit('another good commit')
92 self
.drop('^awful.*', bad_hash
)
94 expected
= ['good commit', 'another good commit']
95 self
.assertEqual(expected
, self
.git
.log())
97 def test_drop_same_commit_in_multiple_plugin_instances(self
):
98 self
.create_commit('good commit')
99 bad_hash
= self
.create_commit('bad commit')
100 self
.create_commit('another good commit')
102 self
.drop('^bad.*', bad_hash
)
104 expected
= ['good commit', 'another good commit']
105 self
.assertEqual(expected
, self
.git
.log())
108 self
.tempdir
= TemporaryDirectory()
110 self
.hg
= HgDriver(Path(self
.tempdir
.name
) / 'hgrepo')
113 self
.git
= GitDriver(Path(self
.tempdir
.name
) / 'gitrepo')
116 self
.export
= ExportDriver(self
.hg
.repodir
, self
.git
.repodir
)
119 self
.tempdir
.cleanup()
121 def create_commit(self
, message
):
122 self
.write_file_data('Data for %r.' % message
)
123 return self
.hg
.commit(message
)
125 def write_file_data(self
, data
, filename
='test_file.txt'):
126 path
= self
.hg
.repodir
/ filename
127 with path
.open('w') as f
:
130 def drop(self
, *spec
):
131 self
.export
.run_with_drop(*spec
)
133 def git_parents(self
, message
):
134 matches
= self
.git
.grep_log(message
)
135 if len(matches
) != 1:
136 raise Exception('No unique commit with message %r.' % message
)
137 subject
, parents
= self
.git
.details(matches
[0])
138 return [self
.git
.details(p
)[0] for p
in parents
]
142 def __init__(self
, sourcedir
, targetdir
, *, quiet
=True):
143 self
.sourcedir
= Path(sourcedir
)
144 self
.targetdir
= Path(targetdir
)
146 self
.python_executable
= str(
147 Path
.cwd() / os
.environ
.get('PYTHON', sys
.executable
))
148 self
.script
= Path(__file__
).parent
/ '../hg-fast-export.sh'
150 def run_with_drop(self
, *plugin_args
):
151 cmd
= [self
.script
, '-r', str(self
.sourcedir
)]
152 for arg
in plugin_args
:
153 cmd
.extend(['--plugin', 'drop=' + arg
])
154 output
= subprocess
.DEVNULL
if self
.quiet
else None
155 subprocess
.run(cmd
, check
=True, cwd
=str(self
.targetdir
),
156 env
={'PYTHON': self
.python_executable
},
157 stdout
=output
, stderr
=output
)
161 def __init__(self
, repodir
):
162 self
.repodir
= Path(repodir
)
166 self
.run_command('init')
168 def commit(self
, message
):
169 self
.run_command('commit', '-A', '-m', message
)
170 return self
.run_command('id', '--id', '--debug').strip()
173 output
= self
.run_command('log', '-T', '{desc}\n')
174 commits
= output
.strip().splitlines()
178 def checkout(self
, rev
):
179 self
.run_command('checkout', '-r', rev
)
182 self
.run_command('merge', '--tool', ':local')
184 def run_command(self
, *args
):
185 p
= subprocess
.run(('hg', '-yq') + args
,
186 cwd
=str(self
.repodir
),
194 def __init__(self
, repodir
):
195 self
.repodir
= Path(repodir
)
199 self
.run_command('init')
202 output
= self
.run_command('log', '--format=%s', '--reverse')
203 return output
.strip().splitlines()
205 def grep_log(self
, pattern
):
206 output
= self
.run_command('log', '--format=%H',
207 '-F', '--grep', pattern
)
208 return output
.strip().splitlines()
210 def details(self
, commit_hash
):
212 output
= self
.run_command('show', '-s', '--format=' + fmt
,
214 subject
, parents
= output
.splitlines()
215 return subject
, parents
.split()
217 def run_command(self
, *args
):
218 p
= subprocess
.run(('git', '--no-pager') + args
,
219 cwd
=str(self
.repodir
),