Allow bisecting with no old commit. (#3641)

Fixes #3598.
This commit is contained in:
Oliver Chang 2020-04-15 08:59:33 +10:00 committed by GitHub
parent 896ed726e2
commit 0399965d7e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 38 additions and 31 deletions

View File

@ -55,8 +55,7 @@ def main():
help='The newest commit SHA to be bisected.',
required=True)
parser.add_argument('--old_commit',
help='The oldest commit SHA to be bisected.',
required=True)
help='The oldest commit SHA to be bisected.')
parser.add_argument('--fuzz_target',
help='The name of the fuzzer to be built.',
required=True)
@ -111,7 +110,7 @@ def bisect(old_commit, new_commit, test_case_path, fuzz_target, build_data): #
"""
with tempfile.TemporaryDirectory() as tmp_dir:
repo_url, repo_path = build_specified_commit.detect_main_repo(
build_data.project_name, commit=old_commit)
build_data.project_name, commit=new_commit)
if not repo_url or not repo_path:
raise ValueError('Main git repo can not be determined.')
@ -120,7 +119,7 @@ def bisect(old_commit, new_commit, test_case_path, fuzz_target, build_data): #
bisect_repo_manager = repo_manager.RepoManager(
repo_url, host_src_dir, repo_name=os.path.basename(repo_path))
commit_list = bisect_repo_manager.get_commit_list(old_commit, new_commit)
commit_list = bisect_repo_manager.get_commit_list(new_commit, old_commit)
old_idx = len(commit_list) - 1
new_idx = 0
logging.info('Testing against new_commit (%s)', commit_list[new_idx])
@ -132,18 +131,19 @@ def bisect(old_commit, new_commit, test_case_path, fuzz_target, build_data): #
test_case_path)
# Check if the error is persistent through the commit range
logging.info('Testing against old_commit (%s)', commit_list[old_idx])
build_specified_commit.build_fuzzers_from_commit(
commit_list[old_idx],
bisect_repo_manager,
host_src_dir,
build_data,
)
if old_commit:
logging.info('Testing against old_commit (%s)', commit_list[old_idx])
build_specified_commit.build_fuzzers_from_commit(
commit_list[old_idx],
bisect_repo_manager,
host_src_dir,
build_data,
)
if expected_error_code == helper.reproduce_impl(build_data.project_name,
fuzz_target, False, [], [],
test_case_path):
return commit_list[old_idx]
if expected_error_code == helper.reproduce_impl(build_data.project_name,
fuzz_target, False, [],
[], test_case_path):
return commit_list[old_idx]
while old_idx - new_idx > 1:
curr_idx = (old_idx + new_idx) // 2

View File

@ -124,37 +124,44 @@ class RepoManager:
check_result=True)
return out.strip('\n')
def get_commit_list(self, old_commit, new_commit):
def get_commit_list(self, newest_commit, oldest_commit=None):
"""Gets the list of commits(inclusive) between the old and new commits.
Args:
old_commit: The oldest commit to be in the list.
new_commit: The newest commit to be in the list.
newest_commit: The newest commit to be in the list.
oldest_commit: The (optional) oldest commit to be in the list.
Returns:
The list of commit SHAs from newest to oldest.
Raises:
ValueError: When either the old or new commit does not exist.
ValueError: When either the oldest or newest commit does not exist.
RuntimeError: When there is an error getting the commit list.
"""
self.fetch_unshallow()
if not self.commit_exists(old_commit):
raise ValueError('The old commit %s does not exist' % old_commit)
if not self.commit_exists(new_commit):
raise ValueError('The new commit %s does not exist' % new_commit)
if old_commit == new_commit:
return [old_commit]
out, _, err_code = utils.execute(
['git', 'rev-list', old_commit + '..' + new_commit], self.repo_dir)
if oldest_commit and not self.commit_exists(oldest_commit):
raise ValueError('The oldest commit %s does not exist' % oldest_commit)
if not self.commit_exists(newest_commit):
raise ValueError('The newest commit %s does not exist' % newest_commit)
if oldest_commit == newest_commit:
return [oldest_commit]
if oldest_commit:
commit_range = oldest_commit + '..' + newest_commit
else:
commit_range = newest_commit
out, _, err_code = utils.execute(['git', 'rev-list', commit_range],
self.repo_dir)
commits = out.split('\n')
commits = [commit for commit in commits if commit]
if err_code or not commits:
raise RuntimeError('Error getting commit list between %s and %s ' %
(old_commit, new_commit))
(oldest_commit, newest_commit))
# Make sure result is inclusive
commits.append(old_commit)
if oldest_commit:
commits.append(oldest_commit)
return commits
def fetch_unshallow(self):

View File

@ -92,7 +92,7 @@ class RepoManagerGetCommitListUnitTest(unittest.TestCase):
'97dee00a3c4ce95071c3e061592f5fd577dea886',
'04ea24ee15bbe46a19e5da6c5f022a2ffdfbdb3b'
]
result_list = test_repo_manager.get_commit_list(old_commit, new_commit)
result_list = test_repo_manager.get_commit_list(new_commit, old_commit)
self.assertListEqual(commit_list, result_list)
def test_invalid_commit_list(self):
@ -108,7 +108,7 @@ class RepoManagerGetCommitListUnitTest(unittest.TestCase):
test_repo_manager.get_commit_list(new_commit, 'fakecommit')
with self.assertRaises(RuntimeError):
# pylint: disable=arguments-out-of-order
test_repo_manager.get_commit_list(new_commit, old_commit)
test_repo_manager.get_commit_list(old_commit, new_commit)
class GitDiffUnitTest(unittest.TestCase):