mirror of
https://github.com/pre-commit/pre-commit.git
synced 2026-02-20 01:24:42 +04:00
Merge pull request #2569 from m-rsha/cmd-retcode-to-check
Change `cmd_output_b`s `retcode` arg to a boolean `check`
This commit is contained in:
commit
0827de1864
17 changed files with 33 additions and 37 deletions
|
|
@ -263,7 +263,7 @@ def _all_filenames(args: argparse.Namespace) -> Collection[str]:
|
||||||
|
|
||||||
def _get_diff() -> bytes:
|
def _get_diff() -> bytes:
|
||||||
_, out, _ = cmd_output_b(
|
_, out, _ = cmd_output_b(
|
||||||
'git', 'diff', '--no-ext-diff', '--ignore-submodules', retcode=None,
|
'git', 'diff', '--no-ext-diff', '--ignore-submodules', check=False,
|
||||||
)
|
)
|
||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
@ -318,7 +318,7 @@ 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, _, _ = cmd_output_b(
|
||||||
'git', 'diff', '--no-ext-diff', '--exit-code', config_file,
|
'git', 'diff', '--no-ext-diff', '--exit-code', config_file,
|
||||||
retcode=None,
|
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
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ def _log_and_exit(
|
||||||
error_msg = f'{msg}: {type(exc).__name__}: '.encode() + force_bytes(exc)
|
error_msg = f'{msg}: {type(exc).__name__}: '.encode() + force_bytes(exc)
|
||||||
output.write_line_b(error_msg)
|
output.write_line_b(error_msg)
|
||||||
|
|
||||||
_, git_version_b, _ = cmd_output_b('git', '--version', retcode=None)
|
_, git_version_b, _ = cmd_output_b('git', '--version', check=False)
|
||||||
git_version = git_version_b.decode(errors='backslashreplace').rstrip()
|
git_version = git_version_b.decode(errors='backslashreplace').rstrip()
|
||||||
|
|
||||||
storedir = Store().directory
|
storedir = Store().directory
|
||||||
|
|
|
||||||
|
|
@ -187,11 +187,11 @@ def head_rev(remote: str) -> str:
|
||||||
|
|
||||||
def has_diff(*args: str, repo: str = '.') -> bool:
|
def has_diff(*args: str, repo: str = '.') -> bool:
|
||||||
cmd = ('git', 'diff', '--quiet', '--no-ext-diff', *args)
|
cmd = ('git', 'diff', '--quiet', '--no-ext-diff', *args)
|
||||||
return cmd_output_b(*cmd, cwd=repo, retcode=None)[0] == 1
|
return cmd_output_b(*cmd, cwd=repo, check=False)[0] == 1
|
||||||
|
|
||||||
|
|
||||||
def has_core_hookpaths_set() -> bool:
|
def has_core_hookpaths_set() -> bool:
|
||||||
_, out, _ = cmd_output_b('git', 'config', 'core.hooksPath', retcode=None)
|
_, out, _ = cmd_output_b('git', 'config', 'core.hooksPath', check=False)
|
||||||
return bool(out.strip())
|
return bool(out.strip())
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ def in_env(
|
||||||
|
|
||||||
def health_check(prefix: Prefix, language_version: str) -> str | None:
|
def health_check(prefix: Prefix, language_version: str) -> str | None:
|
||||||
with in_env(prefix, language_version):
|
with in_env(prefix, language_version):
|
||||||
retcode, _, _ = cmd_output_b('node', '--version', retcode=None)
|
retcode, _, _ = cmd_output_b('node', '--version', check=False)
|
||||||
if retcode != 0: # pragma: win32 no cover
|
if retcode != 0: # pragma: win32 no cover
|
||||||
return f'`node --version` returned {retcode}'
|
return f'`node --version` returned {retcode}'
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ def get_default_version() -> str:
|
||||||
# Just detecting the executable does not suffice, because if rustup is
|
# Just detecting the executable does not suffice, because if rustup is
|
||||||
# installed but no toolchain is available, then `cargo` exists but
|
# installed but no toolchain is available, then `cargo` exists but
|
||||||
# cannot be used without installing a toolchain first.
|
# cannot be used without installing a toolchain first.
|
||||||
if cmd_output_b('cargo', '--version', retcode=None)[0] == 0:
|
if cmd_output_b('cargo', '--version', check=False)[0] == 0:
|
||||||
return 'system'
|
return 'system'
|
||||||
else:
|
else:
|
||||||
return C.DEFAULT
|
return C.DEFAULT
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ def _unstaged_changes_cleared(patch_dir: str) -> Generator[None, None, None]:
|
||||||
retcode, diff_stdout_binary, _ = cmd_output_b(
|
retcode, diff_stdout_binary, _ = cmd_output_b(
|
||||||
'git', 'diff-index', '--ignore-submodules', '--binary',
|
'git', 'diff-index', '--ignore-submodules', '--binary',
|
||||||
'--exit-code', '--no-color', '--no-ext-diff', tree, '--',
|
'--exit-code', '--no-color', '--no-ext-diff', tree, '--',
|
||||||
retcode=None,
|
check=False,
|
||||||
)
|
)
|
||||||
if retcode and diff_stdout_binary.strip():
|
if retcode and diff_stdout_binary.strip():
|
||||||
patch_filename = f'patch{int(time.time())}-{os.getpid()}'
|
patch_filename = f'patch{int(time.time())}-{os.getpid()}'
|
||||||
|
|
|
||||||
|
|
@ -83,14 +83,12 @@ class CalledProcessError(RuntimeError):
|
||||||
self,
|
self,
|
||||||
returncode: int,
|
returncode: int,
|
||||||
cmd: tuple[str, ...],
|
cmd: tuple[str, ...],
|
||||||
expected_returncode: int,
|
|
||||||
stdout: bytes,
|
stdout: bytes,
|
||||||
stderr: bytes | None,
|
stderr: bytes | None,
|
||||||
) -> None:
|
) -> None:
|
||||||
super().__init__(returncode, cmd, expected_returncode, stdout, stderr)
|
super().__init__(returncode, cmd, stdout, stderr)
|
||||||
self.returncode = returncode
|
self.returncode = returncode
|
||||||
self.cmd = cmd
|
self.cmd = cmd
|
||||||
self.expected_returncode = expected_returncode
|
|
||||||
self.stdout = stdout
|
self.stdout = stdout
|
||||||
self.stderr = stderr
|
self.stderr = stderr
|
||||||
|
|
||||||
|
|
@ -104,7 +102,6 @@ class CalledProcessError(RuntimeError):
|
||||||
return b''.join((
|
return b''.join((
|
||||||
f'command: {self.cmd!r}\n'.encode(),
|
f'command: {self.cmd!r}\n'.encode(),
|
||||||
f'return code: {self.returncode}\n'.encode(),
|
f'return code: {self.returncode}\n'.encode(),
|
||||||
f'expected return code: {self.expected_returncode}\n'.encode(),
|
|
||||||
b'stdout:', _indent_or_none(self.stdout), b'\n',
|
b'stdout:', _indent_or_none(self.stdout), b'\n',
|
||||||
b'stderr:', _indent_or_none(self.stderr),
|
b'stderr:', _indent_or_none(self.stderr),
|
||||||
))
|
))
|
||||||
|
|
@ -124,7 +121,7 @@ def _oserror_to_output(e: OSError) -> tuple[int, bytes, None]:
|
||||||
|
|
||||||
def cmd_output_b(
|
def cmd_output_b(
|
||||||
*cmd: str,
|
*cmd: str,
|
||||||
retcode: int | None = 0,
|
check: bool = True,
|
||||||
**kwargs: Any,
|
**kwargs: Any,
|
||||||
) -> tuple[int, bytes, bytes | None]:
|
) -> tuple[int, bytes, bytes | None]:
|
||||||
_setdefault_kwargs(kwargs)
|
_setdefault_kwargs(kwargs)
|
||||||
|
|
@ -142,8 +139,8 @@ def cmd_output_b(
|
||||||
stdout_b, stderr_b = proc.communicate()
|
stdout_b, stderr_b = proc.communicate()
|
||||||
returncode = proc.returncode
|
returncode = proc.returncode
|
||||||
|
|
||||||
if retcode is not None and retcode != returncode:
|
if check and returncode:
|
||||||
raise CalledProcessError(returncode, cmd, retcode, stdout_b, stderr_b)
|
raise CalledProcessError(returncode, cmd, stdout_b, stderr_b)
|
||||||
|
|
||||||
return returncode, stdout_b, stderr_b
|
return returncode, stdout_b, stderr_b
|
||||||
|
|
||||||
|
|
@ -196,10 +193,10 @@ if os.name != 'nt': # pragma: win32 no cover
|
||||||
|
|
||||||
def cmd_output_p(
|
def cmd_output_p(
|
||||||
*cmd: str,
|
*cmd: str,
|
||||||
retcode: int | None = 0,
|
check: bool = True,
|
||||||
**kwargs: Any,
|
**kwargs: Any,
|
||||||
) -> tuple[int, bytes, bytes | None]:
|
) -> tuple[int, bytes, bytes | None]:
|
||||||
assert retcode is None
|
assert check is False
|
||||||
assert kwargs['stderr'] == subprocess.STDOUT, kwargs['stderr']
|
assert kwargs['stderr'] == subprocess.STDOUT, kwargs['stderr']
|
||||||
_setdefault_kwargs(kwargs)
|
_setdefault_kwargs(kwargs)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,7 @@ def xargs(
|
||||||
run_cmd: tuple[str, ...],
|
run_cmd: tuple[str, ...],
|
||||||
) -> tuple[int, bytes, bytes | None]:
|
) -> tuple[int, bytes, bytes | None]:
|
||||||
return cmd_fn(
|
return cmd_fn(
|
||||||
*run_cmd, retcode=None, stderr=subprocess.STDOUT, **kwargs,
|
*run_cmd, check=False, stderr=subprocess.STDOUT, **kwargs,
|
||||||
)
|
)
|
||||||
|
|
||||||
threads = min(len(partitions), target_concurrency)
|
threads = min(len(partitions), target_concurrency)
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,7 @@ def test_init_templatedir_skip_on_missing_config(
|
||||||
retcode, output = git_commit(
|
retcode, output = git_commit(
|
||||||
fn=cmd_output_mocked_pre_commit_home,
|
fn=cmd_output_mocked_pre_commit_home,
|
||||||
tempdir_factory=tempdir_factory,
|
tempdir_factory=tempdir_factory,
|
||||||
retcode=None,
|
check=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
assert retcode == commit_retcode
|
assert retcode == commit_retcode
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,7 @@ def _get_commit_output(tempdir_factory, touch_file='foo', **kwargs):
|
||||||
cmd_output('git', 'add', touch_file)
|
cmd_output('git', 'add', touch_file)
|
||||||
return git_commit(
|
return git_commit(
|
||||||
fn=cmd_output_mocked_pre_commit_home,
|
fn=cmd_output_mocked_pre_commit_home,
|
||||||
retcode=None,
|
check=False,
|
||||||
tempdir_factory=tempdir_factory,
|
tempdir_factory=tempdir_factory,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
)
|
)
|
||||||
|
|
@ -286,7 +286,7 @@ def test_environment_not_sourced(tempdir_factory, store):
|
||||||
'GIT_AUTHOR_EMAIL': os.environ['GIT_AUTHOR_EMAIL'],
|
'GIT_AUTHOR_EMAIL': os.environ['GIT_AUTHOR_EMAIL'],
|
||||||
'GIT_COMMITTER_EMAIL': os.environ['GIT_COMMITTER_EMAIL'],
|
'GIT_COMMITTER_EMAIL': os.environ['GIT_COMMITTER_EMAIL'],
|
||||||
},
|
},
|
||||||
retcode=None,
|
check=False,
|
||||||
)
|
)
|
||||||
assert ret == 1
|
assert ret == 1
|
||||||
assert out == (
|
assert out == (
|
||||||
|
|
@ -551,7 +551,7 @@ def _get_push_output(tempdir_factory, remote='origin', opts=()):
|
||||||
return cmd_output_mocked_pre_commit_home(
|
return cmd_output_mocked_pre_commit_home(
|
||||||
'git', 'push', remote, 'HEAD:new_branch', *opts,
|
'git', 'push', remote, 'HEAD:new_branch', *opts,
|
||||||
tempdir_factory=tempdir_factory,
|
tempdir_factory=tempdir_factory,
|
||||||
retcode=None,
|
check=False,
|
||||||
)[:2]
|
)[:2]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -718,7 +718,7 @@ def test_non_ascii_hook_id(repo_with_passing_hook, tempdir_factory):
|
||||||
with cwd(repo_with_passing_hook):
|
with cwd(repo_with_passing_hook):
|
||||||
_, stdout, _ = cmd_output_mocked_pre_commit_home(
|
_, stdout, _ = cmd_output_mocked_pre_commit_home(
|
||||||
sys.executable, '-m', 'pre_commit.main', 'run', '☃',
|
sys.executable, '-m', 'pre_commit.main', 'run', '☃',
|
||||||
retcode=None, tempdir_factory=tempdir_factory,
|
check=False, tempdir_factory=tempdir_factory,
|
||||||
)
|
)
|
||||||
assert 'UnicodeDecodeError' not in stdout
|
assert 'UnicodeDecodeError' not in stdout
|
||||||
# Doesn't actually happen, but a reasonable assertion
|
# Doesn't actually happen, but a reasonable assertion
|
||||||
|
|
@ -737,7 +737,7 @@ def test_stdout_write_bug_py26(repo_with_failing_hook, store, tempdir_factory):
|
||||||
_, out = git_commit(
|
_, out = git_commit(
|
||||||
fn=cmd_output_mocked_pre_commit_home,
|
fn=cmd_output_mocked_pre_commit_home,
|
||||||
tempdir_factory=tempdir_factory,
|
tempdir_factory=tempdir_factory,
|
||||||
retcode=None,
|
check=False,
|
||||||
)
|
)
|
||||||
assert 'UnicodeEncodeError' not in out
|
assert 'UnicodeEncodeError' not in out
|
||||||
# Doesn't actually happen, but a reasonable assertion
|
# Doesn't actually happen, but a reasonable assertion
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ def _make_conflict():
|
||||||
bar_only_file.write('bar')
|
bar_only_file.write('bar')
|
||||||
cmd_output('git', 'add', 'bar_only_file')
|
cmd_output('git', 'add', 'bar_only_file')
|
||||||
git_commit(msg=_make_conflict.__name__)
|
git_commit(msg=_make_conflict.__name__)
|
||||||
cmd_output('git', 'merge', 'foo', retcode=None)
|
cmd_output('git', 'merge', 'foo', check=False)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
|
|
|
||||||
|
|
@ -162,7 +162,7 @@ def test_error_handler_non_ascii_exception(mock_store_dir):
|
||||||
def test_error_handler_non_utf8_exception(mock_store_dir):
|
def test_error_handler_non_utf8_exception(mock_store_dir):
|
||||||
with pytest.raises(SystemExit):
|
with pytest.raises(SystemExit):
|
||||||
with error_handler.error_handler():
|
with error_handler.error_handler():
|
||||||
raise CalledProcessError(1, ('exe',), 0, b'error: \xa0\xe1', b'')
|
raise CalledProcessError(1, ('exe',), b'error: \xa0\xe1', b'')
|
||||||
|
|
||||||
|
|
||||||
def test_error_handler_non_stringable_exception(mock_store_dir):
|
def test_error_handler_non_stringable_exception(mock_store_dir):
|
||||||
|
|
@ -183,10 +183,11 @@ def test_error_handler_no_tty(tempdir_factory):
|
||||||
'from pre_commit.error_handler import error_handler\n'
|
'from pre_commit.error_handler import error_handler\n'
|
||||||
'with error_handler():\n'
|
'with error_handler():\n'
|
||||||
' raise ValueError("\\u2603")\n',
|
' raise ValueError("\\u2603")\n',
|
||||||
retcode=3,
|
check=False,
|
||||||
tempdir_factory=tempdir_factory,
|
tempdir_factory=tempdir_factory,
|
||||||
pre_commit_home=pre_commit_home,
|
pre_commit_home=pre_commit_home,
|
||||||
)
|
)
|
||||||
|
assert ret == 3
|
||||||
log_file = os.path.join(pre_commit_home, 'pre-commit.log')
|
log_file = os.path.join(pre_commit_home, 'pre-commit.log')
|
||||||
out_lines = out.splitlines()
|
out_lines = out.splitlines()
|
||||||
assert out_lines[-2] == 'An unexpected error has occurred: ValueError: ☃'
|
assert out_lines[-2] == 'An unexpected error has occurred: ValueError: ☃'
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,7 @@ def test_is_in_merge_conflict_submodule(in_conflicting_submodule):
|
||||||
def test_cherry_pick_conflict(in_merge_conflict):
|
def test_cherry_pick_conflict(in_merge_conflict):
|
||||||
cmd_output('git', 'merge', '--abort')
|
cmd_output('git', 'merge', '--abort')
|
||||||
foo_ref = cmd_output('git', 'rev-parse', 'foo')[1].strip()
|
foo_ref = cmd_output('git', 'rev-parse', 'foo')[1].strip()
|
||||||
cmd_output('git', 'cherry-pick', foo_ref, retcode=None)
|
cmd_output('git', 'cherry-pick', foo_ref, check=False)
|
||||||
assert git.is_in_merge_conflict() is False
|
assert git.is_in_merge_conflict() is False
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -178,6 +178,6 @@ def test_get_docker_path_in_docker_windows(in_docker):
|
||||||
|
|
||||||
def test_get_docker_path_in_docker_docker_in_docker(in_docker):
|
def test_get_docker_path_in_docker_docker_in_docker(in_docker):
|
||||||
# won't be able to discover "self" container in true docker-in-docker
|
# won't be able to discover "self" container in true docker-in-docker
|
||||||
err = CalledProcessError(1, (), 0, b'', b'')
|
err = CalledProcessError(1, (), b'', b'')
|
||||||
with mock.patch.object(docker, 'cmd_output_b', side_effect=err):
|
with mock.patch.object(docker, 'cmd_output_b', side_effect=err):
|
||||||
assert docker._get_docker_path('/project') == '/project'
|
assert docker._get_docker_path('/project') == '/project'
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ def test_clone_shallow_failure_fallback_to_complete(
|
||||||
|
|
||||||
# Force shallow clone failure
|
# Force shallow clone failure
|
||||||
def fake_shallow_clone(self, *args, **kwargs):
|
def fake_shallow_clone(self, *args, **kwargs):
|
||||||
raise CalledProcessError(1, (), 0, b'', None)
|
raise CalledProcessError(1, (), b'', None)
|
||||||
store._shallow_clone = fake_shallow_clone
|
store._shallow_clone = fake_shallow_clone
|
||||||
|
|
||||||
ret = store.clone(path, rev)
|
ret = store.clone(path, rev)
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,10 @@ from pre_commit.util import tmpdir
|
||||||
|
|
||||||
|
|
||||||
def test_CalledProcessError_str():
|
def test_CalledProcessError_str():
|
||||||
error = CalledProcessError(1, ('exe',), 0, b'output', b'errors')
|
error = CalledProcessError(1, ('exe',), b'output', b'errors')
|
||||||
assert str(error) == (
|
assert str(error) == (
|
||||||
"command: ('exe',)\n"
|
"command: ('exe',)\n"
|
||||||
'return code: 1\n'
|
'return code: 1\n'
|
||||||
'expected return code: 0\n'
|
|
||||||
'stdout:\n'
|
'stdout:\n'
|
||||||
' output\n'
|
' output\n'
|
||||||
'stderr:\n'
|
'stderr:\n'
|
||||||
|
|
@ -31,11 +30,10 @@ def test_CalledProcessError_str():
|
||||||
|
|
||||||
|
|
||||||
def test_CalledProcessError_str_nooutput():
|
def test_CalledProcessError_str_nooutput():
|
||||||
error = CalledProcessError(1, ('exe',), 0, b'', b'')
|
error = CalledProcessError(1, ('exe',), b'', b'')
|
||||||
assert str(error) == (
|
assert str(error) == (
|
||||||
"command: ('exe',)\n"
|
"command: ('exe',)\n"
|
||||||
'return code: 1\n'
|
'return code: 1\n'
|
||||||
'expected return code: 0\n'
|
|
||||||
'stdout: (none)\n'
|
'stdout: (none)\n'
|
||||||
'stderr: (none)'
|
'stderr: (none)'
|
||||||
)
|
)
|
||||||
|
|
@ -83,14 +81,14 @@ def test_tmpdir():
|
||||||
|
|
||||||
|
|
||||||
def test_cmd_output_exe_not_found():
|
def test_cmd_output_exe_not_found():
|
||||||
ret, out, _ = cmd_output('dne', retcode=None)
|
ret, out, _ = cmd_output('dne', check=False)
|
||||||
assert ret == 1
|
assert ret == 1
|
||||||
assert out == 'Executable `dne` not found'
|
assert out == 'Executable `dne` not found'
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('fn', (cmd_output_b, cmd_output_p))
|
@pytest.mark.parametrize('fn', (cmd_output_b, cmd_output_p))
|
||||||
def test_cmd_output_exe_not_found_bytes(fn):
|
def test_cmd_output_exe_not_found_bytes(fn):
|
||||||
ret, out, _ = fn('dne', retcode=None, stderr=subprocess.STDOUT)
|
ret, out, _ = fn('dne', check=False, stderr=subprocess.STDOUT)
|
||||||
assert ret == 1
|
assert ret == 1
|
||||||
assert out == b'Executable `dne` not found'
|
assert out == b'Executable `dne` not found'
|
||||||
|
|
||||||
|
|
@ -101,7 +99,7 @@ def test_cmd_output_no_shebang(tmpdir, fn):
|
||||||
make_executable(f)
|
make_executable(f)
|
||||||
|
|
||||||
# previously this raised `OSError` -- the output is platform specific
|
# previously this raised `OSError` -- the output is platform specific
|
||||||
ret, out, _ = fn(str(f), retcode=None, stderr=subprocess.STDOUT)
|
ret, out, _ = fn(str(f), check=False, stderr=subprocess.STDOUT)
|
||||||
assert ret == 1
|
assert ret == 1
|
||||||
assert isinstance(out, bytes)
|
assert isinstance(out, bytes)
|
||||||
assert out.endswith(b'\n')
|
assert out.endswith(b'\n')
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue