diff --git a/pre_commit/git.py b/pre_commit/git.py index 3d3f58016..6d8da55fd 100644 --- a/pre_commit/git.py +++ b/pre_commit/git.py @@ -236,8 +236,11 @@ def get_best_candidate_tag(rev: str, git_repo: str) -> str: Multiple tags can exist on a SHA. Sometimes a moving tag is attached to a version tag. Try to pick the tag that looks like a version. """ + commit = cmd_output( + 'git', 'rev-list', '-n', '1', rev, cwd=git_repo, + )[1].strip() tags = cmd_output( - 'git', *NO_FS_MONITOR, 'tag', '--points-at', rev, cwd=git_repo, + 'git', *NO_FS_MONITOR, 'tag', '--points-at', commit, cwd=git_repo, )[1].splitlines() for tag in tags: if '.' in tag: diff --git a/tests/commands/autoupdate_test.py b/tests/commands/autoupdate_test.py index cbf22f393..6fb8c5ab4 100644 --- a/tests/commands/autoupdate_test.py +++ b/tests/commands/autoupdate_test.py @@ -49,6 +49,13 @@ def tagged(out_of_date): yield out_of_date +@pytest.fixture +def multiple_tagged(out_of_date): + cmd_output('git', 'tag', 'v1', cwd=out_of_date.path) + cmd_output('git', 'tag', 'v1.2.3', cwd=out_of_date.path) + yield out_of_date + + @pytest.fixture def hook_disappearing(tempdir_factory): path = make_repo(tempdir_factory, 'python_hooks_repo') @@ -102,6 +109,17 @@ def test_rev_info_update_tags_only_does_not_pick_tip(tagged): assert new_info.rev == 'v1.2.3' +def test_rev_info_update_tags_prefers_semver_tag(multiple_tagged): + git_commit(cwd=multiple_tagged.path) + config = make_config_from_repo( + multiple_tagged.path, + rev=multiple_tagged.original_rev, + ) + info = RevInfo.from_config(config) + new_info = info.update(tags_only=True, freeze=False) + assert new_info.rev == 'v1.2.3' + + def test_rev_info_update_tags_prefers_version_tag(tagged, out_of_date): cmd_output('git', 'tag', 'latest', cwd=out_of_date.path) config = make_config_from_repo(tagged.path, rev=tagged.original_rev) diff --git a/tests/git_test.py b/tests/git_test.py index 763aa0de5..c65997040 100644 --- a/tests/git_test.py +++ b/tests/git_test.py @@ -302,3 +302,18 @@ def test_no_git_env(): def test_init_repo_no_hooks(tmpdir): git.init_repo(str(tmpdir), remote='dne') assert not tmpdir.join('.git/hooks').exists() + + +def test_get_best_candidate_tag(in_git_dir): + git_commit() + cmd_output('git', 'tag', 'v1') + cmd_output('git', 'tag', 'v1.0.1') + commit = cmd_output( + 'git', 'rev-list', '-n', '1', 'v1', cwd=in_git_dir, + )[1].strip() + tags = cmd_output( + 'git', *git.NO_FS_MONITOR, 'tag', + '--points-at', commit, cwd=in_git_dir, + )[1].splitlines() + assert tags == ['v1', 'v1.0.1'] + assert git.get_best_candidate_tag('v1', in_git_dir) == 'v1.0.1'