diff --git a/.github/actions/pre-test/action.yml b/.github/actions/pre-test/action.yml index f5272c847..58a4ae67d 100644 --- a/.github/actions/pre-test/action.yml +++ b/.github/actions/pre-test/action.yml @@ -6,4 +6,4 @@ runs: using: composite steps: - uses: asottile/workflows/.github/actions/latest-git@v1.4.0 - if: inputs.env == 'py310' && runner.os == 'Linux' + if: inputs.env == 'py311' && runner.os == 'Linux' diff --git a/.github/workflows/languages.yaml b/.github/workflows/languages.yaml index be8963bac..92e0e24fa 100644 --- a/.github/workflows/languages.yaml +++ b/.github/workflows/languages.yaml @@ -21,7 +21,7 @@ jobs: fetch-depth: 0 - uses: actions/setup-python@v4 with: - python-version: '3.10' + python-version: '3.11' - name: install deps run: python -mpip install -e . -r requirements-dev.txt - name: vars @@ -39,7 +39,7 @@ jobs: - uses: asottile/workflows/.github/actions/fast-checkout@v1.8.1 - uses: actions/setup-python@v4 with: - python-version: '3.10' + python-version: '3.11' - run: echo "$CONDA\Scripts" >> "$GITHUB_PATH" shell: bash @@ -63,7 +63,7 @@ jobs: echo 'C:\Strawberry\c\bin' >> "$GITHUB_PATH" shell: bash if: matrix.os == 'windows-latest' && matrix.language == 'perl' - - uses: haskell/actions/setup@v2 + - uses: haskell-actions/setup@v2 if: matrix.language == 'haskell' - uses: r-lib/actions/setup-r@v2 if: matrix.os == 'ubuntu-latest' && matrix.language == 'r' diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 02b11ae28..bf12183c6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -12,12 +12,12 @@ concurrency: jobs: main-windows: - uses: asottile/workflows/.github/workflows/tox.yml@v1.8.1 + uses: asottile/workflows/.github/workflows/tox.yml@v1.11.1 with: - env: '["py310"]' + env: '["py311"]' os: windows-latest main-linux: - uses: asottile/workflows/.github/workflows/tox.yml@v1.8.1 + uses: asottile/workflows/.github/workflows/tox.yml@v1.11.1 with: - env: '["py310", "py311", "py312", "py313"]' + env: '["py311", "py312", "py313", "py314"]' os: ubuntu-latest diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 04a0b822f..0aa1867c9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,34 +10,34 @@ repos: - id: name-tests-test - id: requirements-txt-fixer - repo: https://github.com/asottile/setup-cfg-fmt - rev: v3.2.0 + rev: v3.3.0 hooks: - id: setup-cfg-fmt - repo: https://github.com/asottile/reorder-python-imports - rev: v3.17.0 + rev: v3.18.0 hooks: - id: reorder-python-imports exclude: ^pre_commit/resources/ - args: [--py310-plus, --add-import, 'from __future__ import annotations'] + args: [--py311-plus, --add-import, 'from __future__ import annotations'] - repo: https://github.com/asottile/add-trailing-comma rev: v4.0.0 hooks: - id: add-trailing-comma - repo: https://github.com/asottile/pyupgrade - rev: v3.21.2 + rev: v3.22.0 hooks: - id: pyupgrade - args: [--py310-plus] + args: [--py311-plus] - repo: https://github.com/hhatto/autopep8 rev: v2.3.2 hooks: - id: autopep8 - repo: https://github.com/PyCQA/flake8 - rev: 7.3.0 + rev: 7.4.1 hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v2.3.1 + rev: v2.4.0 hooks: - id: mypy additional_dependencies: [types-pyyaml] diff --git a/CHANGELOG.md b/CHANGELOG.md index dfd8a1e24..6f8c2942c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +4.7.0 - 2026-10-12 +================== + +### Fixes +- Fix `language: node` hooks during commit with `-a` or inside a submodule. + - Regressed in 4.6.1. + - #3773 issue by @cbirkhold. + - #3774 PR by @cbirkhold. + 4.6.2 - 2026-08-10 ================== diff --git a/pre_commit/languages/node.py b/pre_commit/languages/node.py index 17b7393ab..3ab6e2b8b 100644 --- a/pre_commit/languages/node.py +++ b/pre_commit/languages/node.py @@ -13,6 +13,7 @@ from pre_commit.envcontext import PatchesT from pre_commit.envcontext import UNSET from pre_commit.envcontext import Var +from pre_commit.git import no_git_env from pre_commit.languages.python import bin_dir from pre_commit.prefix import Prefix from pre_commit.util import cmd_output @@ -103,4 +104,4 @@ def install_environment( 'npm', 'install', '--allow-git=root', '--install-links', '-g', *pkgs, ) - lang_base.setup_cmd(prefix, install) + lang_base.setup_cmd(prefix, install, env=no_git_env()) diff --git a/setup.cfg b/setup.cfg index 6113e6973..3e4a84970 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 4.6.2 +version = 4.7.0 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown @@ -23,7 +23,7 @@ install_requires = nodeenv>=0.11.1 pyyaml>=5.1 virtualenv>=20.10.0 -python_requires = >=3.10 +python_requires = >=3.11 [options.packages.find] exclude = diff --git a/testing/util.py b/testing/util.py index 1646ccd2a..894cebd6b 100644 --- a/testing/util.py +++ b/testing/util.py @@ -1,6 +1,5 @@ from __future__ import annotations -import contextlib import os.path import subprocess import sys @@ -86,16 +85,6 @@ def run_opts( ) -@contextlib.contextmanager -def cwd(path): - original_cwd = os.getcwd() - os.chdir(path) - try: - yield - finally: - os.chdir(original_cwd) - - def git_commit(*args, fn=cmd_output, msg='commit!', all_files=True, **kwargs): kwargs.setdefault('stderr', subprocess.STDOUT) diff --git a/testing/zipapp/Dockerfile b/testing/zipapp/Dockerfile index ea967e383..119c0ba46 100644 --- a/testing/zipapp/Dockerfile +++ b/testing/zipapp/Dockerfile @@ -1,9 +1,7 @@ -FROM ubuntu:jammy +FROM ubuntu:noble RUN : \ && apt-get update \ && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ - python3 \ - python3-distutils \ python3-venv \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* diff --git a/testing/zipapp/make b/testing/zipapp/make index 43bb4373f..20d6d35a8 100755 --- a/testing/zipapp/make +++ b/testing/zipapp/make @@ -44,7 +44,7 @@ def _add_shim(dest: str) -> None: with tempfile.TemporaryDirectory() as tmpdir: _exit_if_retv( 'podman', 'run', '--rm', '--volume', f'{tmpdir}:/out:rw', IMG, - 'cp', '/venv/lib/python3.10/site-packages/distlib/t32.exe', '/out', + 'cp', '/venv/lib/python3.12/site-packages/distlib/t32.exe', '/out', ) with open(os.path.join(dest, 'python.exe'), 'wb') as f: diff --git a/tests/color_test.py b/tests/color_test.py index 89b4fd3eb..e8da98abc 100644 --- a/tests/color_test.py +++ b/tests/color_test.py @@ -36,24 +36,30 @@ def test_use_color_no_tty(): def test_use_color_tty_with_color_support(): - with mock.patch.object(sys.stderr, 'isatty', return_value=True): - with mock.patch('pre_commit.color.terminal_supports_color', True): - with envcontext.envcontext((('TERM', envcontext.UNSET),)): - assert use_color('auto') is True + with ( + mock.patch.object(sys.stderr, 'isatty', return_value=True), + mock.patch('pre_commit.color.terminal_supports_color', True), + envcontext.envcontext((('TERM', envcontext.UNSET),)), + ): + assert use_color('auto') is True def test_use_color_tty_without_color_support(): - with mock.patch.object(sys.stderr, 'isatty', return_value=True): - with mock.patch('pre_commit.color.terminal_supports_color', False): - with envcontext.envcontext((('TERM', envcontext.UNSET),)): - assert use_color('auto') is False + with ( + mock.patch.object(sys.stderr, 'isatty', return_value=True), + mock.patch('pre_commit.color.terminal_supports_color', False), + envcontext.envcontext((('TERM', envcontext.UNSET),)), + ): + assert use_color('auto') is False def test_use_color_dumb_term(): - with mock.patch.object(sys.stderr, 'isatty', return_value=True): - with mock.patch('pre_commit.color.terminal_supports_color', True): - with envcontext.envcontext((('TERM', 'dumb'),)): - assert use_color('auto') is False + with ( + mock.patch.object(sys.stderr, 'isatty', return_value=True), + mock.patch('pre_commit.color.terminal_supports_color', True), + envcontext.envcontext((('TERM', 'dumb'),)), + ): + assert use_color('auto') is False def test_use_color_raises_if_given_shenanigans(): diff --git a/tests/commands/hazmat_test.py b/tests/commands/hazmat_test.py index df957e36e..b5533c76b 100644 --- a/tests/commands/hazmat_test.py +++ b/tests/commands/hazmat_test.py @@ -1,12 +1,12 @@ from __future__ import annotations +import contextlib import sys import pytest from pre_commit.commands.hazmat import _cmd_filenames from pre_commit.commands.hazmat import main -from testing.util import cwd def test_cmd_filenames_no_dash_dash(): @@ -51,7 +51,7 @@ def test_cd(tmp_path, capfd): subdir.joinpath('a').write_text('a') subdir.joinpath('b').write_text('b') - with cwd(tmp_path): + with contextlib.chdir(tmp_path): ret = main(( 'cd', 'subdir', sys.executable, '-c', diff --git a/tests/commands/hook_impl_test.py b/tests/commands/hook_impl_test.py index 9aa93af53..0c8529343 100644 --- a/tests/commands/hook_impl_test.py +++ b/tests/commands/hook_impl_test.py @@ -1,5 +1,6 @@ from __future__ import annotations +import contextlib import subprocess import sys from unittest import mock @@ -15,7 +16,6 @@ from testing.fixtures import git_dir from testing.fixtures import sample_local_config from testing.fixtures import write_config -from testing.util import cwd from testing.util import git_commit @@ -269,7 +269,7 @@ def push_example(tempdir_factory): def test_run_ns_pre_push_updating_branch(push_example): src, src_head, clone, clone_head = push_example - with cwd(clone): + with contextlib.chdir(clone): args = ('origin', src) stdin = f'HEAD {clone_head} refs/heads/b {src_head}\n'.encode() ns = hook_impl._run_ns('pre-push', False, args, stdin) @@ -287,7 +287,7 @@ def test_run_ns_pre_push_updating_branch(push_example): def test_run_ns_pre_push_new_branch(push_example): src, src_head, clone, clone_head = push_example - with cwd(clone): + with contextlib.chdir(clone): args = ('origin', src) stdin = f'HEAD {clone_head} refs/heads/b {hook_impl.Z40}\n'.encode() ns = hook_impl._run_ns('pre-push', False, args, stdin) @@ -300,7 +300,7 @@ def test_run_ns_pre_push_new_branch(push_example): def test_run_ns_pre_push_new_branch_existing_rev(push_example): src, src_head, clone, _ = push_example - with cwd(clone): + with contextlib.chdir(clone): args = ('origin', src) stdin = f'HEAD {src_head} refs/heads/b2 {hook_impl.Z40}\n'.encode() ns = hook_impl._run_ns('pre-push', False, args, stdin) @@ -311,7 +311,7 @@ def test_run_ns_pre_push_new_branch_existing_rev(push_example): def test_run_ns_pre_push_ref_with_whitespace(push_example): src, src_head, clone, _ = push_example - with cwd(clone): + with contextlib.chdir(clone): args = ('origin', src) line = f'HEAD^{{/ }} {src_head} refs/heads/b2 {hook_impl.Z40}\n' stdin = line.encode() @@ -327,7 +327,7 @@ def test_pushing_orphan_branch(push_example): git_commit(cwd=clone, msg='something else to get unique hash') clone_rev = git.head_rev(clone) - with cwd(clone): + with contextlib.chdir(clone): args = ('origin', src) stdin = f'HEAD {clone_rev} refs/heads/b2 {hook_impl.Z40}\n'.encode() ns = hook_impl._run_ns('pre-push', False, args, stdin) @@ -339,7 +339,7 @@ def test_pushing_orphan_branch(push_example): def test_run_ns_pre_push_deleting_branch(push_example): src, src_head, clone, _ = push_example - with cwd(clone): + with contextlib.chdir(clone): args = ('origin', src) stdin = f'(delete) {hook_impl.Z40} refs/heads/b {src_head}'.encode() ns = hook_impl._run_ns('pre-push', False, args, stdin) @@ -352,7 +352,7 @@ def test_hook_impl_main_noop_pre_push(cap_out, store, push_example): stdin = f'(delete) {hook_impl.Z40} refs/heads/b {src_head}'.encode() with mock.patch.object(sys.stdin.buffer, 'read', return_value=stdin): - with cwd(clone): + with contextlib.chdir(clone): write_config('.', sample_local_config()) ret = hook_impl.hook_impl( store, @@ -368,7 +368,7 @@ def test_hook_impl_main_noop_pre_push(cap_out, store, push_example): def test_hook_impl_main_runs_hooks(cap_out, tempdir_factory, store): - with cwd(git_dir(tempdir_factory)): + with contextlib.chdir(git_dir(tempdir_factory)): write_config('.', sample_local_config()) ret = hook_impl.hook_impl( store, diff --git a/tests/commands/init_templatedir_test.py b/tests/commands/init_templatedir_test.py index 28f29b77c..d72301593 100644 --- a/tests/commands/init_templatedir_test.py +++ b/tests/commands/init_templatedir_test.py @@ -1,5 +1,6 @@ from __future__ import annotations +import contextlib import os.path from unittest import mock @@ -12,7 +13,6 @@ from testing.fixtures import git_dir from testing.fixtures import make_consuming_repo from testing.util import cmd_output_mocked_pre_commit_home -from testing.util import cwd from testing.util import git_commit @@ -31,7 +31,7 @@ def test_init_templatedir(tmpdir, tempdir_factory, store, cap_out): with envcontext((('GIT_TEMPLATE_DIR', target),)): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') - with cwd(path): + with contextlib.chdir(path): retcode, output = git_commit( fn=cmd_output_mocked_pre_commit_home, tempdir_factory=tempdir_factory, @@ -43,7 +43,7 @@ def test_init_templatedir(tmpdir, tempdir_factory, store, cap_out): def test_init_templatedir_already_set(tmpdir, tempdir_factory, store, cap_out): target = str(tmpdir.join('tmpl')) tmp_git_dir = git_dir(tempdir_factory) - with cwd(tmp_git_dir): + with contextlib.chdir(tmp_git_dir): cmd_output('git', 'config', 'init.templateDir', target) init_templatedir( C.CONFIG_FILE, store, target, hook_types=['pre-commit'], @@ -73,7 +73,7 @@ def test_init_templatedir_not_set(tmpdir, store, cap_out): def test_init_templatedir_expanduser(tmpdir, tempdir_factory, store, cap_out): target = str(tmpdir.join('tmpl')) tmp_git_dir = git_dir(tempdir_factory) - with cwd(tmp_git_dir): + with contextlib.chdir(tmp_git_dir): cmd_output('git', 'config', 'init.templateDir', '~/templatedir') with mock.patch.object(os.path, 'expanduser', return_value=target): init_templatedir( @@ -88,7 +88,7 @@ def test_init_templatedir_expanduser(tmpdir, tempdir_factory, store, cap_out): def test_init_templatedir_hookspath_set(tmpdir, tempdir_factory, store): target = tmpdir.join('tmpl') tmp_git_dir = git_dir(tempdir_factory) - with cwd(tmp_git_dir): + with contextlib.chdir(tmp_git_dir): cmd_output('git', 'config', '--local', 'core.hooksPath', 'hooks') init_templatedir( C.CONFIG_FILE, store, target, hook_types=['pre-commit'], @@ -114,7 +114,7 @@ def test_init_templatedir_skip_on_missing_config( ): target = str(tmpdir.join('tmpl')) init_git_dir = git_dir(tempdir_factory) - with cwd(init_git_dir): + with contextlib.chdir(init_git_dir): cmd_output('git', 'config', 'init.templateDir', target) init_templatedir( C.CONFIG_FILE, @@ -131,7 +131,7 @@ def test_init_templatedir_skip_on_missing_config( with envcontext((('GIT_TEMPLATE_DIR', target),)): verify_git_dir = git_dir(tempdir_factory) - with cwd(verify_git_dir): + with contextlib.chdir(verify_git_dir): retcode, output = git_commit( fn=cmd_output_mocked_pre_commit_home, tempdir_factory=tempdir_factory, diff --git a/tests/commands/install_uninstall_test.py b/tests/commands/install_uninstall_test.py index 9eb0e741a..3f886b2c6 100644 --- a/tests/commands/install_uninstall_test.py +++ b/tests/commands/install_uninstall_test.py @@ -1,5 +1,6 @@ from __future__ import annotations +import contextlib import os.path import re @@ -24,7 +25,6 @@ from testing.fixtures import remove_config_from_repo from testing.fixtures import write_config from testing.util import cmd_output_mocked_pre_commit_home -from testing.util import cwd from testing.util import git_commit @@ -153,7 +153,7 @@ def _get_commit_output(tempdir_factory, touch_file='foo', **kwargs): def test_install_pre_commit_and_run(tempdir_factory, store): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') - with cwd(path): + with contextlib.chdir(path): assert install(C.CONFIG_FILE, store, hook_types=['pre-commit']) == 0 ret, output = _get_commit_output(tempdir_factory) @@ -163,7 +163,7 @@ def test_install_pre_commit_and_run(tempdir_factory, store): def test_install_pre_commit_and_run_custom_path(tempdir_factory, store): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') - with cwd(path): + with contextlib.chdir(path): cmd_output('git', 'mv', C.CONFIG_FILE, 'custom.yaml') git_commit(cwd=path) assert install('custom.yaml', store, hook_types=['pre-commit']) == 0 @@ -180,7 +180,7 @@ def test_install_in_submodule_and_run(tempdir_factory, store): git_commit(cwd=parent_path) sub_pth = os.path.join(parent_path, 'sub') - with cwd(sub_pth): + with contextlib.chdir(sub_pth): assert install(C.CONFIG_FILE, store, hook_types=['pre-commit']) == 0 ret, output = _get_commit_output(tempdir_factory) assert ret == 0 @@ -193,7 +193,7 @@ def test_install_in_worktree_and_run(tempdir_factory, store): cmd_output('git', '-C', src_path, 'branch', '-m', 'notmaster') cmd_output('git', '-C', src_path, 'worktree', 'add', path, '-b', 'master') - with cwd(path): + with contextlib.chdir(path): assert install(C.CONFIG_FILE, store, hook_types=['pre-commit']) == 0 ret, output = _get_commit_output(tempdir_factory) assert ret == 0 @@ -203,7 +203,7 @@ def test_install_in_worktree_and_run(tempdir_factory, store): def test_commit_am(tempdir_factory, store): """Regression test for #322.""" path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') - with cwd(path): + with contextlib.chdir(path): # Make an unstaged change open('unstaged', 'w').close() cmd_output('git', 'add', '.') @@ -219,7 +219,7 @@ def test_commit_am(tempdir_factory, store): def test_unicode_merge_commit_message(tempdir_factory, store): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') - with cwd(path): + with contextlib.chdir(path): assert install(C.CONFIG_FILE, store, hook_types=['pre-commit']) == 0 cmd_output('git', 'checkout', 'master', '-b', 'foo') git_commit('-n', cwd=path) @@ -236,7 +236,7 @@ def test_unicode_merge_commit_message(tempdir_factory, store): def test_install_idempotent(tempdir_factory, store): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') - with cwd(path): + with contextlib.chdir(path): assert install(C.CONFIG_FILE, store, hook_types=['pre-commit']) == 0 assert install(C.CONFIG_FILE, store, hook_types=['pre-commit']) == 0 @@ -264,7 +264,7 @@ def _path_without_us(): def test_environment_not_sourced(tempdir_factory, store): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') - with cwd(path): + with contextlib.chdir(path): assert not install(C.CONFIG_FILE, store, hook_types=['pre-commit']) # simulate deleting the virtualenv by rewriting the exe hook = os.path.join(path, '.git/hooks/pre-commit') @@ -310,7 +310,7 @@ def test_environment_not_sourced(tempdir_factory, store): def test_failing_hooks_returns_nonzero(tempdir_factory, store): path = make_consuming_repo(tempdir_factory, 'failing_hook_repo') - with cwd(path): + with contextlib.chdir(path): assert install(C.CONFIG_FILE, store, hook_types=['pre-commit']) == 0 ret, output = _get_commit_output(tempdir_factory) @@ -335,7 +335,7 @@ def _write_legacy_hook(path): def test_install_existing_hooks_no_overwrite(tempdir_factory, store): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') - with cwd(path): + with contextlib.chdir(path): _write_legacy_hook(path) # Make sure we installed the "old" hook correctly @@ -356,7 +356,7 @@ def test_install_existing_hooks_no_overwrite(tempdir_factory, store): def test_legacy_overwriting_legacy_hook(tempdir_factory, store): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') - with cwd(path): + with contextlib.chdir(path): _write_legacy_hook(path) assert install(C.CONFIG_FILE, store, hook_types=['pre-commit']) == 0 _write_legacy_hook(path) @@ -366,7 +366,7 @@ def test_legacy_overwriting_legacy_hook(tempdir_factory, store): def test_install_existing_hook_no_overwrite_idempotent(tempdir_factory, store): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') - with cwd(path): + with contextlib.chdir(path): _write_legacy_hook(path) # Install twice @@ -403,7 +403,7 @@ def test_install_with_existing_non_utf8_script(tmpdir, store): def test_failing_existing_hook_returns_1(tempdir_factory, store): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') - with cwd(path): + with contextlib.chdir(path): # Write out a failing "old" hook os.makedirs(os.path.join(path, '.git/hooks'), exist_ok=True) with open(os.path.join(path, '.git/hooks/pre-commit'), 'w') as f: @@ -420,7 +420,7 @@ def test_failing_existing_hook_returns_1(tempdir_factory, store): def test_install_overwrite_no_existing_hooks(tempdir_factory, store): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') - with cwd(path): + with contextlib.chdir(path): assert not install( C.CONFIG_FILE, store, hook_types=['pre-commit'], overwrite=True, ) @@ -432,7 +432,7 @@ def test_install_overwrite_no_existing_hooks(tempdir_factory, store): def test_install_overwrite(tempdir_factory, store): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') - with cwd(path): + with contextlib.chdir(path): _write_legacy_hook(path) assert not install( C.CONFIG_FILE, store, hook_types=['pre-commit'], overwrite=True, @@ -445,7 +445,7 @@ def test_install_overwrite(tempdir_factory, store): def test_uninstall_restores_legacy_hooks(tempdir_factory, store): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') - with cwd(path): + with contextlib.chdir(path): _write_legacy_hook(path) # Now install and uninstall pre-commit @@ -460,7 +460,7 @@ def test_uninstall_restores_legacy_hooks(tempdir_factory, store): def test_replace_old_commit_script(tempdir_factory, store): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') - with cwd(path): + with contextlib.chdir(path): # Install a script that looks like our old script pre_commit_contents = resource_text('hook-tmpl') new_contents = pre_commit_contents.replace( @@ -500,7 +500,7 @@ def test_uninstall_doesnt_remove_not_our_hooks(in_git_dir): def test_installs_hooks_with_hooks_True(tempdir_factory, store): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') - with cwd(path): + with contextlib.chdir(path): install(C.CONFIG_FILE, store, hook_types=['pre-commit'], hooks=True) ret, output = _get_commit_output( tempdir_factory, pre_commit_home=store.directory, @@ -512,7 +512,7 @@ def test_installs_hooks_with_hooks_True(tempdir_factory, store): def test_install_hooks_command(tempdir_factory, store): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') - with cwd(path): + with contextlib.chdir(path): install(C.CONFIG_FILE, store, hook_types=['pre-commit']) install_hooks(C.CONFIG_FILE, store) ret, output = _get_commit_output( @@ -525,7 +525,7 @@ def test_install_hooks_command(tempdir_factory, store): def test_installed_from_venv(tempdir_factory, store): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') - with cwd(path): + with contextlib.chdir(path): install(C.CONFIG_FILE, store, hook_types=['pre-commit']) # No environment so pre-commit is not on the path when running! # Should still pick up the python from when we installed @@ -562,7 +562,7 @@ def test_pre_push_integration_failing(tempdir_factory, store): upstream = make_consuming_repo(tempdir_factory, 'failing_hook_repo') path = tempdir_factory.get() cmd_output('git', 'clone', upstream, path) - with cwd(path): + with contextlib.chdir(path): install(C.CONFIG_FILE, store, hook_types=['pre-push']) # commit succeeds because pre-commit is only installed for pre-push assert _get_commit_output(tempdir_factory)[0] == 0 @@ -580,7 +580,7 @@ def test_pre_push_integration_accepted(tempdir_factory, store): upstream = make_consuming_repo(tempdir_factory, 'script_hooks_repo') path = tempdir_factory.get() cmd_output('git', 'clone', upstream, path) - with cwd(path): + with contextlib.chdir(path): install(C.CONFIG_FILE, store, hook_types=['pre-push']) assert _get_commit_output(tempdir_factory)[0] == 0 @@ -596,11 +596,11 @@ def test_pre_push_force_push_without_fetch(tempdir_factory, store): path2 = tempdir_factory.get() cmd_output('git', 'clone', upstream, path1) cmd_output('git', 'clone', upstream, path2) - with cwd(path1): + with contextlib.chdir(path1): assert _get_commit_output(tempdir_factory)[0] == 0 assert _get_push_output(tempdir_factory)[0] == 0 - with cwd(path2): + with contextlib.chdir(path2): install(C.CONFIG_FILE, store, hook_types=['pre-push']) assert _get_commit_output(tempdir_factory, msg='force!')[0] == 0 @@ -615,7 +615,7 @@ def test_pre_push_new_upstream(tempdir_factory, store): upstream2 = git_dir(tempdir_factory) path = tempdir_factory.get() cmd_output('git', 'clone', upstream, path) - with cwd(path): + with contextlib.chdir(path): install(C.CONFIG_FILE, store, hook_types=['pre-push']) assert _get_commit_output(tempdir_factory)[0] == 0 @@ -645,7 +645,7 @@ def test_pre_push_environment_variables(tempdir_factory, store): clone = tempdir_factory.get() cmd_output('git', 'clone', upstream, clone) add_config_to_repo(clone, config) - with cwd(clone): + with contextlib.chdir(clone): install(C.CONFIG_FILE, store, hook_types=['pre-push']) cmd_output('git', 'remote', 'rename', 'origin', 'origin2') @@ -658,7 +658,7 @@ def test_pre_push_integration_empty_push(tempdir_factory, store): upstream = make_consuming_repo(tempdir_factory, 'script_hooks_repo') path = tempdir_factory.get() cmd_output('git', 'clone', upstream, path) - with cwd(path): + with contextlib.chdir(path): install(C.CONFIG_FILE, store, hook_types=['pre-push']) _get_push_output(tempdir_factory) retc, output = _get_push_output(tempdir_factory) @@ -670,7 +670,7 @@ def test_pre_push_legacy(tempdir_factory, store): upstream = make_consuming_repo(tempdir_factory, 'script_hooks_repo') path = tempdir_factory.get() cmd_output('git', 'clone', upstream, path) - with cwd(path): + with contextlib.chdir(path): os.makedirs(os.path.join(path, '.git/hooks'), exist_ok=True) with open(os.path.join(path, '.git/hooks/pre-push'), 'w') as f: f.write( @@ -759,7 +759,7 @@ def test_post_commit_integration(tempdir_factory, store): ], } write_config(path, config) - with cwd(path): + with contextlib.chdir(path): _get_commit_output(tempdir_factory) assert not os.path.exists('post-commit.tmp') @@ -787,7 +787,7 @@ def test_post_merge_integration(tempdir_factory, store): ], } write_config(path, config) - with cwd(path): + with contextlib.chdir(path): # create a simple diamond of commits for a non-trivial merge open('init', 'a').close() cmd_output('git', 'add', '.') @@ -831,7 +831,7 @@ def test_pre_rebase_integration(tempdir_factory, store): ], } write_config(path, config) - with cwd(path): + with contextlib.chdir(path): install(C.CONFIG_FILE, store, hook_types=['pre-rebase']) open('foo', 'a').close() cmd_output('git', 'add', '.') @@ -871,7 +871,7 @@ def test_post_rewrite_integration(tempdir_factory, store): ], } write_config(path, config) - with cwd(path): + with contextlib.chdir(path): open('init', 'a').close() cmd_output('git', 'add', '.') install(C.CONFIG_FILE, store, hook_types=['post-rewrite']) @@ -903,7 +903,7 @@ def test_post_checkout_integration(tempdir_factory, store): ], } write_config(path, config) - with cwd(path): + with contextlib.chdir(path): cmd_output('git', 'add', '.') git_commit() @@ -936,7 +936,7 @@ def test_skips_post_checkout_unstaged_changes(tempdir_factory, store): }], } write_config(path, config) - with cwd(path): + with contextlib.chdir(path): cmd_output('git', 'add', '.') _get_commit_output(tempdir_factory) @@ -1023,7 +1023,7 @@ def test_pre_merge_commit_integration(tempdir_factory, store): ) path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') - with cwd(path): + with contextlib.chdir(path): ret = install(C.CONFIG_FILE, store, hook_types=['pre-merge-commit']) assert ret == 0 @@ -1040,7 +1040,7 @@ def test_pre_merge_commit_integration(tempdir_factory, store): def test_install_disallow_missing_config(tempdir_factory, store): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') - with cwd(path): + with contextlib.chdir(path): remove_config_from_repo(path) ret = install( C.CONFIG_FILE, store, hook_types=['pre-commit'], @@ -1054,7 +1054,7 @@ def test_install_disallow_missing_config(tempdir_factory, store): def test_install_allow_missing_config(tempdir_factory, store): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') - with cwd(path): + with contextlib.chdir(path): remove_config_from_repo(path) ret = install( C.CONFIG_FILE, store, hook_types=['pre-commit'], @@ -1073,7 +1073,7 @@ def test_install_allow_missing_config(tempdir_factory, store): def test_install_temporarily_allow_mising_config(tempdir_factory, store): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') - with cwd(path): + with contextlib.chdir(path): remove_config_from_repo(path) ret = install( C.CONFIG_FILE, store, hook_types=['pre-commit'], diff --git a/tests/commands/run_test.py b/tests/commands/run_test.py index e4af1e162..1c7172a6d 100644 --- a/tests/commands/run_test.py +++ b/tests/commands/run_test.py @@ -1,5 +1,6 @@ from __future__ import annotations +import contextlib import os.path import shlex import sys @@ -31,7 +32,6 @@ from testing.fixtures import sample_meta_config from testing.fixtures import write_config from testing.util import cmd_output_mocked_pre_commit_home -from testing.util import cwd from testing.util import git_commit from testing.util import run_opts @@ -107,21 +107,21 @@ def test_full_msg_postfix_not_colored(): @pytest.fixture def repo_with_passing_hook(tempdir_factory): git_path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') - with cwd(git_path): + with contextlib.chdir(git_path): yield git_path @pytest.fixture def repo_with_failing_hook(tempdir_factory): git_path = make_consuming_repo(tempdir_factory, 'failing_hook_repo') - with cwd(git_path): + with contextlib.chdir(git_path): yield git_path @pytest.fixture def aliased_repo(tempdir_factory): git_path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') - with cwd(git_path): + with contextlib.chdir(git_path): with modify_config() as config: config['repos'][0]['hooks'].append( {'id': 'bash_hook', 'alias': 'foo_bash'}, @@ -136,7 +136,7 @@ def stage_a_file(filename='foo.py'): def _do_run(cap_out, store, repo, args, environ={}, config_file=C.CONFIG_FILE): - with cwd(repo): # replicates `main._adjust_args_and_chdir` behaviour + with contextlib.chdir(repo): # replicates `main._adjust_args_and_chdir` ret = run(config_file, store, args, environ=environ) printed = cap_out.get_bytes() return ret, printed @@ -175,7 +175,7 @@ def test_run_all_hooks_failing(cap_out, store, repo_with_failing_hook): def test_arbitrary_bytes_hook(cap_out, store, tempdir_factory): git_path = make_consuming_repo(tempdir_factory, 'arbitrary_bytes_repo') - with cwd(git_path): + with contextlib.chdir(git_path): _test_run( cap_out, store, git_path, {}, (b'\xe2\x98\x83\xb2\n',), 1, True, ) @@ -185,7 +185,7 @@ def test_hook_that_modifies_but_returns_zero(cap_out, store, tempdir_factory): git_path = make_consuming_repo( tempdir_factory, 'modified_file_returns_zero_repo', ) - with cwd(git_path): + with contextlib.chdir(git_path): stage_a_file('bar.py') _test_run( cap_out, @@ -212,7 +212,7 @@ def test_hook_that_modifies_but_returns_zero(cap_out, store, tempdir_factory): def test_types_hook_repository(cap_out, store, tempdir_factory): git_path = make_consuming_repo(tempdir_factory, 'types_repo') - with cwd(git_path): + with contextlib.chdir(git_path): stage_a_file('bar.py') stage_a_file('bar.notpy') ret, printed = _do_run(cap_out, store, git_path, run_opts()) @@ -223,7 +223,7 @@ def test_types_hook_repository(cap_out, store, tempdir_factory): def test_types_or_hook_repository(cap_out, store, tempdir_factory): git_path = make_consuming_repo(tempdir_factory, 'types_or_repo') - with cwd(git_path): + with contextlib.chdir(git_path): stage_a_file('bar.notpy') stage_a_file('bar.pxd') stage_a_file('bar.py') @@ -236,7 +236,7 @@ def test_types_or_hook_repository(cap_out, store, tempdir_factory): def test_exclude_types_hook_repository(cap_out, store, tempdir_factory): git_path = make_consuming_repo(tempdir_factory, 'exclude_types_repo') - with cwd(git_path): + with contextlib.chdir(git_path): with open('exe', 'w') as exe: exe.write('#!/usr/bin/env python3\n') make_executable('exe') @@ -335,7 +335,7 @@ def test_show_diff_on_failure( git_path = make_consuming_repo( tempdir_factory, 'modified_file_returns_zero_repo', ) - with cwd(git_path): + with contextlib.chdir(git_path): stage_a_file('bar.py') _test_run( cap_out, store, git_path, args, @@ -406,7 +406,7 @@ def test_run_output_logfile(cap_out, store, tempdir_factory): ) git_path = make_consuming_repo(tempdir_factory, 'logfile_repo') - with cwd(git_path): + with contextlib.chdir(git_path): _test_run( cap_out, store, @@ -695,7 +695,7 @@ def test_hook_id_in_verbose_output(cap_out, store, repo_with_passing_hook): def test_multiple_hooks_same_id(cap_out, store, repo_with_passing_hook): - with cwd(repo_with_passing_hook): + with contextlib.chdir(repo_with_passing_hook): # Add bash hook on there again with modify_config() as config: config['repos'][0]['hooks'].append({'id': 'bash_hook'}) @@ -725,7 +725,7 @@ def test_aliased_hook_run(cap_out, store, aliased_repo): def test_non_ascii_hook_id(repo_with_passing_hook, tempdir_factory): - with cwd(repo_with_passing_hook): + with contextlib.chdir(repo_with_passing_hook): _, stdout, _ = cmd_output_mocked_pre_commit_home( sys.executable, '-m', 'pre_commit.main', 'run', '☃', check=False, tempdir_factory=tempdir_factory, @@ -736,7 +736,7 @@ def test_non_ascii_hook_id(repo_with_passing_hook, tempdir_factory): def test_stdout_write_bug_py26(repo_with_failing_hook, store, tempdir_factory): - with cwd(repo_with_failing_hook): + with contextlib.chdir(repo_with_failing_hook): with modify_config() as config: config['repos'][0]['hooks'][0]['args'] = ['☃'] stage_a_file() @@ -758,7 +758,7 @@ def test_lots_of_files(store, tempdir_factory): # windows xargs seems to have a bug, here's a regression test for # our workaround git_path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') - with cwd(git_path): + with contextlib.chdir(git_path): # Override files so we run against them with modify_config() as config: config['repos'][0]['hooks'][0]['files'] = '' @@ -873,7 +873,7 @@ def test_post_checkout_hook(cap_out, store, tempdir_factory): } add_config_to_repo(path, config) - with cwd(path): + with contextlib.chdir(path): _test_run( cap_out, store, @@ -1024,12 +1024,12 @@ def test_no_unstaged_error_with_all_files_or_files( def test_files_running_subdir(repo_with_passing_hook, tempdir_factory): - with cwd(repo_with_passing_hook): + with contextlib.chdir(repo_with_passing_hook): os.mkdir('subdir') open('subdir/foo.py', 'w').close() cmd_output('git', 'add', 'subdir/foo.py') - with cwd('subdir'): + with contextlib.chdir('subdir'): # Use subprocess to demonstrate behaviour in main _, stdout, _ = cmd_output_mocked_pre_commit_home( sys.executable, '-m', 'pre_commit.main', 'run', '-v', @@ -1123,20 +1123,24 @@ def test_classifier_removes_dne(): def test_classifier_normalizes_filenames_on_windows_to_forward_slashes(tmpdir): - with tmpdir.as_cwd(): - tmpdir.join('a/b/c').ensure() - with mock.patch.object(os, 'altsep', '/'): - with mock.patch.object(os, 'sep', '\\'): - classifier = Classifier.from_config((r'a\b\c',), '', '^$') - assert classifier.filenames == ['a/b/c'] + tmpdir.join('a/b/c').ensure() + with ( + tmpdir.as_cwd(), + mock.patch.object(os, 'altsep', '/'), + mock.patch.object(os, 'sep', '\\'), + ): + classifier = Classifier.from_config((r'a\b\c',), '', '^$') + assert classifier.filenames == ['a/b/c'] def test_classifier_does_not_normalize_backslashes_non_windows(tmpdir): - with mock.patch.object(os.path, 'lexists', return_value=True): - with mock.patch.object(os, 'altsep', None): - with mock.patch.object(os, 'sep', '/'): - classifier = Classifier.from_config((r'a/b\c',), '', '^$') - assert classifier.filenames == [r'a/b\c'] + with ( + mock.patch.object(os.path, 'lexists', return_value=True), + mock.patch.object(os, 'altsep', None), + mock.patch.object(os, 'sep', '/'), + ): + classifier = Classifier.from_config((r'a/b\c',), '', '^$') + assert classifier.filenames == [r'a/b\c'] def test_classifier_empty_types_or(tmpdir): diff --git a/tests/commands/try_repo_test.py b/tests/commands/try_repo_test.py index c5f891ea7..c03830780 100644 --- a/tests/commands/try_repo_test.py +++ b/tests/commands/try_repo_test.py @@ -1,5 +1,6 @@ from __future__ import annotations +import contextlib import os.path import re import time @@ -14,7 +15,6 @@ from testing.fixtures import git_dir from testing.fixtures import make_repo from testing.fixtures import modify_manifest -from testing.util import cwd from testing.util import git_commit from testing.util import run_opts @@ -37,7 +37,7 @@ def _add_test_file(): def _run_try_repo(tempdir_factory, **kwargs): repo = make_repo(tempdir_factory, 'modified_file_returns_zero_repo') - with cwd(git_dir(tempdir_factory)): + with contextlib.chdir(git_dir(tempdir_factory)): _add_test_file() assert not try_repo(try_repo_opts(repo, **kwargs)) @@ -91,7 +91,7 @@ def test_try_repo_with_specific_hook(cap_out, tempdir_factory): def test_try_repo_relative_path(cap_out, tempdir_factory): repo = make_repo(tempdir_factory, 'modified_file_returns_zero_repo') - with cwd(git_dir(tempdir_factory)): + with contextlib.chdir(git_dir(tempdir_factory)): _add_test_file() relative_repo = os.path.relpath(repo, '.') # previously crashed on cloning a relative path @@ -100,7 +100,7 @@ def test_try_repo_relative_path(cap_out, tempdir_factory): def test_try_repo_bare_repo(cap_out, tempdir_factory): repo = make_repo(tempdir_factory, 'modified_file_returns_zero_repo') - with cwd(git_dir(tempdir_factory)): + with contextlib.chdir(git_dir(tempdir_factory)): _add_test_file() bare_repo = os.path.join(repo, '.git') # previously crashed attempting modification changes @@ -111,7 +111,7 @@ def test_try_repo_specific_revision(cap_out, tempdir_factory): repo = make_repo(tempdir_factory, 'script_hooks_repo') ref = git.head_rev(repo) git_commit(cwd=repo) - with cwd(git_dir(tempdir_factory)): + with contextlib.chdir(git_dir(tempdir_factory)): _add_test_file() assert not try_repo(try_repo_opts(repo, ref=ref)) @@ -125,7 +125,7 @@ def test_try_repo_uncommitted_changes(cap_out, tempdir_factory): with modify_manifest(repo, commit=False) as manifest: manifest[0]['name'] = 'modified name!' - with cwd(git_dir(tempdir_factory)): + with contextlib.chdir(git_dir(tempdir_factory)): open('test-fie', 'a').close() cmd_output('git', 'add', '.') assert not try_repo(try_repo_opts(repo)) @@ -146,10 +146,10 @@ def test_try_repo_uncommitted_changes(cap_out, tempdir_factory): def test_try_repo_staged_changes(tempdir_factory): repo = make_repo(tempdir_factory, 'modified_file_returns_zero_repo') - with cwd(repo): + with contextlib.chdir(repo): open('staged-file', 'a').close() open('second-staged-file', 'a').close() cmd_output('git', 'add', '.') - with cwd(git_dir(tempdir_factory)): + with contextlib.chdir(git_dir(tempdir_factory)): assert not try_repo(try_repo_opts(repo, hook='bash_hook')) diff --git a/tests/conftest.py b/tests/conftest.py index 8c9cd14db..7bf720ffe 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,5 +1,6 @@ from __future__ import annotations +import contextlib import functools import io import os.path @@ -16,7 +17,6 @@ from testing.fixtures import git_dir from testing.fixtures import make_consuming_repo from testing.fixtures import write_config -from testing.util import cwd from testing.util import git_commit @@ -38,7 +38,7 @@ def get(self): @pytest.fixture def in_tmpdir(tempdir_factory): path = tempdir_factory.get() - with cwd(path): + with contextlib.chdir(path): yield path @@ -79,7 +79,7 @@ def in_merge_conflict(tempdir_factory): conflict_path = tempdir_factory.get() cmd_output('git', 'clone', path, conflict_path) - with cwd(conflict_path): + with contextlib.chdir(conflict_path): _make_conflict() yield os.path.join(conflict_path) @@ -90,7 +90,7 @@ def in_conflicting_submodule(tempdir_factory): git_dir_2 = git_dir(tempdir_factory) git_commit(msg=in_conflicting_submodule.__name__, cwd=git_dir_2) cmd_output('git', 'submodule', 'add', git_dir_2, 'sub', cwd=git_dir_1) - with cwd(os.path.join(git_dir_1, 'sub')): + with contextlib.chdir(os.path.join(git_dir_1, 'sub')): _make_conflict() yield @@ -109,7 +109,7 @@ def commit_msg_repo(tempdir_factory): }], } write_config(path, config) - with cwd(path): + with contextlib.chdir(path): cmd_output('git', 'add', '.') git_commit(msg=commit_msg_repo.__name__) yield path @@ -130,7 +130,7 @@ def prepare_commit_msg_repo(tempdir_factory): }], } write_config(path, config) - with cwd(path): + with contextlib.chdir(path): with open(script_name, 'w') as script_file: script_file.write( '#!/usr/bin/env bash\n' @@ -157,7 +157,7 @@ def failing_prepare_commit_msg_repo(tempdir_factory): }], } write_config(path, config) - with cwd(path): + with contextlib.chdir(path): cmd_output('git', 'add', '.') git_commit(msg=failing_prepare_commit_msg_repo.__name__) yield path diff --git a/tests/languages/golang_test.py b/tests/languages/golang_test.py index 7fb6ab18b..3a1c83ae1 100644 --- a/tests/languages/golang_test.py +++ b/tests/languages/golang_test.py @@ -1,5 +1,6 @@ from __future__ import annotations +import contextlib from unittest import mock import pytest @@ -17,7 +18,6 @@ from testing.fixtures import make_config_from_repo from testing.language_helpers import run_language from testing.util import cmd_output_mocked_pre_commit_home -from testing.util import cwd from testing.util import git_commit @@ -223,7 +223,7 @@ def test_automatic_toolchain_switching_go_fmt(tmp_path, monkeypatch): main_file = test_dir.joinpath('main.go') main_file.write_text(main_go) - with cwd(test_dir): + with contextlib.chdir(test_dir): ret, out = run_language( path=hook_dir, language=golang, diff --git a/tests/languages/julia_test.py b/tests/languages/julia_test.py index aa7098cfb..cf9dba447 100644 --- a/tests/languages/julia_test.py +++ b/tests/languages/julia_test.py @@ -1,5 +1,6 @@ from __future__ import annotations +import contextlib import os from unittest import mock @@ -7,7 +8,6 @@ from pre_commit.languages import julia from pre_commit.prefix import Prefix from testing.language_helpers import run_language -from testing.util import cwd def _make_hook(tmp_path, julia_code): @@ -117,7 +117,7 @@ def test_julia_repo_local(tmp_path): local_dir.joinpath('local.jl').write_text( 'using TOML; foreach(println, ARGS)', ) - with cwd(local_dir): + with contextlib.chdir(local_dir): deps = ('TOML=fa267f1f-6049-4f14-aa54-33bafae1ed76',) expected = (0, b'--local-arg1\n--local-arg2\n') assert run_language( diff --git a/tests/languages/node_test.py b/tests/languages/node_test.py index 778501a69..b2df9f6a3 100644 --- a/tests/languages/node_test.py +++ b/tests/languages/node_test.py @@ -144,6 +144,29 @@ def test_node_hook_system(tmp_path): assert ret == (0, b'Hello World\n') +def test_node_hook_install_does_not_write_callers_index(tmp_path): + # git sets GIT_DIR / GIT_INDEX_FILE to absolute paths when running hooks + # in a submodule, `npm install git+file://...` must not inherit them + hook_repo = tmp_path.joinpath('hook') + hook_repo.mkdir() + _make_hello_world(hook_repo) + + user_repo = tmp_path.joinpath('user') + cmd_output_b('git', 'init', user_repo) + user_repo.joinpath('f').touch() + cmd_output_b('git', 'add', 'f', cwd=user_repo) + + git_dir = user_repo.joinpath('.git') + with envcontext.envcontext(( + ('GIT_DIR', str(git_dir)), + ('GIT_INDEX_FILE', str(git_dir.joinpath('index'))), + )): + ret = run_language(hook_repo, node, 'node-hello') + assert ret == (0, b'Hello World\n') + + assert cmd_output('git', 'ls-files', cwd=user_repo)[1] == 'f\n' + + def test_node_with_user_config_set(tmp_path): cfg = tmp_path.joinpath('cfg') cfg.write_text('cache=/dne\n') diff --git a/tests/languages/ruby_test.py b/tests/languages/ruby_test.py index 5d767b25d..c030a9af6 100644 --- a/tests/languages/ruby_test.py +++ b/tests/languages/ruby_test.py @@ -1,5 +1,6 @@ from __future__ import annotations +import contextlib import tarfile from unittest import mock @@ -12,7 +13,6 @@ from pre_commit.languages.ruby import _resource_bytesio from pre_commit.store import _make_local_repo from testing.language_helpers import run_language -from testing.util import cwd from testing.util import xfailif_windows @@ -134,6 +134,6 @@ def test_ruby_with_bundle_disable_shared_gems(tmp_path): 'BUNDLE_PATH: vendor/gem\n', ) - with cwd(workdir): + with contextlib.chdir(workdir): # `3.2.0` has new enough `gem` reading `.bundle` test_ruby_hook_language_version(tmp_path) diff --git a/tests/languages/rust_test.py b/tests/languages/rust_test.py index 52e356134..241f7a61a 100644 --- a/tests/languages/rust_test.py +++ b/tests/languages/rust_test.py @@ -1,5 +1,6 @@ from __future__ import annotations +import contextlib from unittest import mock import pytest @@ -9,7 +10,6 @@ from pre_commit.languages import rust from pre_commit.store import _make_local_repo from testing.language_helpers import run_language -from testing.util import cwd ACTUAL_GET_DEFAULT_VERSION = rust.get_default_version.__wrapped__ @@ -34,7 +34,7 @@ def test_selects_system_even_if_rust_toolchain_toml(tmp_path): toolchain_toml = '[toolchain]\nchannel = "wtf"\n' tmp_path.joinpath('rust-toolchain.toml').write_text(toolchain_toml) - with cwd(tmp_path): + with contextlib.chdir(tmp_path): assert ACTUAL_GET_DEFAULT_VERSION() == 'system' diff --git a/tests/main_test.py b/tests/main_test.py index 5194e9ea8..973c6e830 100644 --- a/tests/main_test.py +++ b/tests/main_test.py @@ -13,7 +13,6 @@ from pre_commit.errors import FatalError from pre_commit.util import cmd_output from testing.auto_namedtuple import auto_namedtuple -from testing.util import cwd def _args(**kwargs): @@ -64,7 +63,7 @@ def test_install_on_subst(in_git_dir, store): # pragma: posix no cover assert not os.path.exists('Z:') cmd_output('subst', 'Z:', str(in_git_dir)) try: - with cwd('Z:'): + with contextlib.chdir('Z:'): test_adjust_args_and_chdir_noop('Z:\\') finally: cmd_output('subst', '/d', 'Z:') diff --git a/tests/repository_test.py b/tests/repository_test.py index 5d71c3e4c..4295340e9 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -1,5 +1,6 @@ from __future__ import annotations +import contextlib import os.path import shlex import shutil @@ -27,7 +28,6 @@ from testing.fixtures import make_config_from_repo from testing.fixtures import make_repo from testing.language_helpers import run_language -from testing.util import cwd from testing.util import get_resource_path @@ -239,14 +239,16 @@ class MyKeyboardInterrupt(KeyboardInterrupt): # To simulate a killed install, we'll make PythonEnv.run raise ^C # and then to simulate a second ^C during cleanup, we'll make shutil.rmtree # raise as well. - with pytest.raises(MyKeyboardInterrupt): - with mock.patch.object( - lang_base, 'setup_cmd', side_effect=MyKeyboardInterrupt, - ): - with mock.patch.object( + with ( + pytest.raises(MyKeyboardInterrupt), + mock.patch.object( + lang_base, 'setup_cmd', side_effect=MyKeyboardInterrupt, + ), + mock.patch.object( shutil, 'rmtree', side_effect=MyKeyboardInterrupt, - ): - install_hook_envs(hooks, store) + ), + ): + install_hook_envs(hooks, store) # Should have made an environment, however this environment is broken! hook, = hooks @@ -298,7 +300,7 @@ def test_really_long_file_paths(tempdir_factory, store): path = make_repo(tempdir_factory, 'python_hooks_repo') config = make_config_from_repo(path) - with cwd(really_long_path): + with contextlib.chdir(really_long_path): _get_hook(config, store, 'foo') diff --git a/tests/staged_files_only_test.py b/tests/staged_files_only_test.py index cd2f63870..215cd8b9c 100644 --- a/tests/staged_files_only_test.py +++ b/tests/staged_files_only_test.py @@ -14,7 +14,6 @@ from pre_commit.util import cmd_output from testing.auto_namedtuple import auto_namedtuple from testing.fixtures import git_dir -from testing.util import cwd from testing.util import get_resource_path from testing.util import git_commit from testing.util import xfailif_windows @@ -189,7 +188,7 @@ def test_img_conflict(img_staged, patch_dir): @pytest.fixture def repo_with_commits(tempdir_factory): path = git_dir(tempdir_factory) - with cwd(path): + with contextlib.chdir(path): open('foo', 'a+').close() cmd_output('git', 'add', 'foo') git_commit() @@ -206,7 +205,7 @@ def checkout_submodule(rev): @pytest.fixture def sub_staged(repo_with_commits, tempdir_factory): path = git_dir(tempdir_factory) - with cwd(path): + with contextlib.chdir(path): open('bar', 'a+').close() cmd_output('git', 'add', 'bar') git_commit() @@ -224,7 +223,7 @@ def sub_staged(repo_with_commits, tempdir_factory): def _test_sub_state(path, rev='rev1', status='A'): assert os.path.exists(path.sub_path) - with cwd(path.sub_path): + with contextlib.chdir(path.sub_path): actual_rev = cmd_output('git', 'rev-parse', 'HEAD')[1].strip() assert actual_rev == getattr(path.submodule, rev) actual_status = get_short_git_status()['sub'] diff --git a/tests/store_test.py b/tests/store_test.py index 13f198ea2..65c2f917b 100644 --- a/tests/store_test.py +++ b/tests/store_test.py @@ -1,5 +1,6 @@ from __future__ import annotations +import contextlib import logging import os.path import shlex @@ -17,7 +18,6 @@ from pre_commit.util import CalledProcessError from pre_commit.util import cmd_output from testing.fixtures import git_dir -from testing.util import cwd from testing.util import git_commit from testing.util import xfailif_windows @@ -81,7 +81,7 @@ def test_store_init(store): def test_clone(store, tempdir_factory, caplog): path = git_dir(tempdir_factory) - with cwd(path): + with contextlib.chdir(path): git_commit() rev = git.head_rev(path) git_commit() @@ -201,7 +201,7 @@ def test_clone_shallow_failure_fallback_to_complete( caplog, ): path = git_dir(tempdir_factory) - with cwd(path): + with contextlib.chdir(path): git_commit() rev = git.head_rev(path) git_commit() @@ -233,7 +233,7 @@ def fake_shallow_clone(self, *args, **kwargs): def test_clone_tag_not_on_mainline(store, tempdir_factory): path = git_dir(tempdir_factory) - with cwd(path): + with contextlib.chdir(path): git_commit() cmd_output('git', 'checkout', 'master', '-b', 'branch') git_commit()