Fix _has_unstaged_config false negative check report

This commit is contained in:
v.kapitonov 2023-11-11 09:36:01 +03:00
parent 14169eb31d
commit fcbee7e6f2
2 changed files with 90 additions and 3 deletions

View file

@ -327,9 +327,18 @@ def _has_unmerged_paths() -> bool:
def _has_unstaged_config(config_file: str) -> bool: def _has_unstaged_config(config_file: str) -> bool:
retcode, _, _ = cmd_output_b( retcode = 0
'git', 'diff', '--quiet', '--no-ext-diff', config_file, check=False, if os.path.islink(config_file):
) real_config_file = os.path.realpath(config_file)
_, is_real_file_in_git_dir, _, = cmd_output_b(
'git', 'ls-files', config_file,
)
if is_real_file_in_git_dir:
cmd = ('git', 'diff', '--quiet', '--no-ext-diff', real_config_file)
retcode, _, _ = cmd_output_b(*cmd, check=False)
else:
cmd = ('git', 'diff', '--quiet', '--no-ext-diff', config_file)
retcode, _, _ = cmd_output_b(*cmd, check=False)
# be explicit, other git errors don't mean it has an unstaged config. # be explicit, other git errors don't mean it has an unstaged config.
return retcode == 1 return retcode == 1

View file

@ -3,6 +3,7 @@ from __future__ import annotations
import os.path import os.path
import shlex import shlex
import sys import sys
import tempfile
import time import time
from collections.abc import MutableMapping from collections.abc import MutableMapping
from unittest import mock from unittest import mock
@ -16,6 +17,7 @@ from pre_commit.commands.run import _compute_cols
from pre_commit.commands.run import _full_msg from pre_commit.commands.run import _full_msg
from pre_commit.commands.run import _get_skips from pre_commit.commands.run import _get_skips
from pre_commit.commands.run import _has_unmerged_paths from pre_commit.commands.run import _has_unmerged_paths
from pre_commit.commands.run import _has_unstaged_config
from pre_commit.commands.run import _start_msg from pre_commit.commands.run import _start_msg
from pre_commit.commands.run import Classifier from pre_commit.commands.run import Classifier
from pre_commit.commands.run import filter_by_include_exclude from pre_commit.commands.run import filter_by_include_exclude
@ -1217,3 +1219,79 @@ def test_pre_commit_env_variable_set(cap_out, store, repo_with_passing_hook):
cap_out, store, repo_with_passing_hook, args, environ, cap_out, store, repo_with_passing_hook, args, environ,
) )
assert environ['PRE_COMMIT'] == '1' assert environ['PRE_COMMIT'] == '1'
@pytest.mark.parametrize(
('config_before', 'config_after', 'retval'),
(
({'config with change': 1}, {'config with change': 0}, True),
({'config without change': 1}, {'config without change': 1}, False),
),
)
def test_has_unstaged_config(
config_before,
config_after,
retval,
tempdir_factory,
monkeypatch,
):
git_path = git_dir(tempdir_factory)
monkeypatch.chdir(git_path)
add_config_to_repo(git_path, config_before)
write_config(git_path, config_before, C.CONFIG_FILE)
if str(config_before) != str(config_after):
write_config(git_path, config_after, C.CONFIG_FILE)
full_config_path = os.path.join(git_path, C.CONFIG_FILE)
assert retval == _has_unstaged_config(full_config_path)
@pytest.mark.parametrize(
('config_before', 'config_after', 'retval'),
(
({'config with change': 1}, {'config with change': 0}, True),
({'config without change': 1}, {'config without change': 1}, False),
),
)
def test_has_unstaged_config_symlink(
config_before,
config_after,
retval,
tempdir_factory,
monkeypatch,
):
git_path = git_dir(tempdir_factory)
real_config_path = C.CONFIG_FILE.lstrip('.')
monkeypatch.chdir(git_path)
add_config_to_repo(git_path, config_before, real_config_path)
write_config(git_path, config_before, real_config_path)
os.symlink(real_config_path, C.CONFIG_FILE)
cmd_output('git', 'add', '-A')
git_commit()
if str(config_before) != str(config_after):
write_config(git_path, config_after, real_config_path)
full_config_path = os.path.join(git_path, C.CONFIG_FILE)
assert retval == _has_unstaged_config(full_config_path)
def test_has_unstaged_config_symlink_outside(tempdir_factory, monkeypatch):
config_before = {'config with change': 1}
config_after = {'config with change': 0}
with tempfile.NamedTemporaryFile() as tf:
git_path = git_dir(tempdir_factory)
real_config_path = tf.name
monkeypatch.chdir(git_path)
with open(real_config_path, 'w') as f:
f.write(str(config_before))
os.symlink(real_config_path, C.CONFIG_FILE)
cmd_output('git', 'add', C.CONFIG_FILE)
git_commit()
with open(real_config_path, 'w') as f:
f.write(str(config_after))
full_config_path = os.path.join(git_path, C.CONFIG_FILE)
assert not _has_unstaged_config(full_config_path)