summaryrefslogtreecommitdiffstats
path: root/testing
diff options
context:
space:
mode:
Diffstat (limited to 'testing')
-rw-r--r--testing/__init__.py0
-rw-r--r--testing/auto_namedtuple.py11
-rw-r--r--testing/fixtures.py146
-rwxr-xr-xtesting/gen-languages-all28
-rwxr-xr-xtesting/get-swift.sh27
-rw-r--r--testing/resources/arbitrary_bytes_repo/.pre-commit-hooks.yaml5
-rwxr-xr-xtesting/resources/arbitrary_bytes_repo/hook.sh7
-rw-r--r--testing/resources/arg_per_line_hooks_repo/.pre-commit-hooks.yaml6
-rwxr-xr-xtesting/resources/arg_per_line_hooks_repo/bin/hook.sh5
-rw-r--r--testing/resources/conda_hooks_repo/.pre-commit-hooks.yaml10
-rw-r--r--testing/resources/conda_hooks_repo/environment.yml6
-rw-r--r--testing/resources/docker_hooks_repo/.pre-commit-hooks.yaml17
-rw-r--r--testing/resources/docker_hooks_repo/Dockerfile3
-rw-r--r--testing/resources/docker_image_hooks_repo/.pre-commit-hooks.yaml8
-rw-r--r--testing/resources/exclude_types_repo/.pre-commit-hooks.yaml6
-rwxr-xr-xtesting/resources/exclude_types_repo/bin/hook.sh3
-rw-r--r--testing/resources/failing_hook_repo/.pre-commit-hooks.yaml5
-rwxr-xr-xtesting/resources/failing_hook_repo/bin/hook.sh4
-rw-r--r--testing/resources/golang_hooks_repo/.pre-commit-hooks.yaml5
-rw-r--r--testing/resources/golang_hooks_repo/golang-hello-world/main.go17
-rw-r--r--testing/resources/img1.jpgbin0 -> 843 bytes
-rw-r--r--testing/resources/img2.jpgbin0 -> 891 bytes
-rw-r--r--testing/resources/img3.jpgbin0 -> 859 bytes
-rw-r--r--testing/resources/logfile_repo/.pre-commit-hooks.yaml6
-rwxr-xr-xtesting/resources/logfile_repo/bin/hook.sh5
-rw-r--r--testing/resources/modified_file_returns_zero_repo/.pre-commit-hooks.yaml15
-rwxr-xr-xtesting/resources/modified_file_returns_zero_repo/bin/hook.sh7
-rwxr-xr-xtesting/resources/modified_file_returns_zero_repo/bin/hook2.sh2
-rwxr-xr-xtesting/resources/modified_file_returns_zero_repo/bin/hook3.sh6
-rw-r--r--testing/resources/node_hooks_repo/.pre-commit-hooks.yaml5
-rw-r--r--testing/resources/node_hooks_repo/bin/main.js3
-rw-r--r--testing/resources/node_hooks_repo/package.json5
-rw-r--r--testing/resources/node_versioned_hooks_repo/.pre-commit-hooks.yaml6
-rw-r--r--testing/resources/node_versioned_hooks_repo/bin/main.js4
-rw-r--r--testing/resources/node_versioned_hooks_repo/package.json5
-rw-r--r--testing/resources/not_found_exe/.pre-commit-hooks.yaml5
-rw-r--r--testing/resources/perl_hooks_repo/.gitignore7
-rw-r--r--testing/resources/perl_hooks_repo/.pre-commit-hooks.yaml5
-rw-r--r--testing/resources/perl_hooks_repo/MANIFEST4
-rw-r--r--testing/resources/perl_hooks_repo/Makefile.PL10
-rwxr-xr-xtesting/resources/perl_hooks_repo/bin/pre-commit-perl-hello7
-rw-r--r--testing/resources/perl_hooks_repo/lib/PreCommitHello.pm12
-rw-r--r--testing/resources/prints_cwd_repo/.pre-commit-hooks.yaml5
-rw-r--r--testing/resources/python3_hooks_repo/.pre-commit-hooks.yaml6
-rw-r--r--testing/resources/python3_hooks_repo/py3_hook.py8
-rw-r--r--testing/resources/python3_hooks_repo/setup.py8
-rw-r--r--testing/resources/python_hooks_repo/.pre-commit-hooks.yaml5
-rw-r--r--testing/resources/python_hooks_repo/foo.py7
-rw-r--r--testing/resources/python_hooks_repo/setup.py8
-rw-r--r--testing/resources/python_venv_hooks_repo/.pre-commit-hooks.yaml5
-rw-r--r--testing/resources/python_venv_hooks_repo/foo.py7
-rw-r--r--testing/resources/python_venv_hooks_repo/setup.py8
-rw-r--r--testing/resources/ruby_hooks_repo/.gitignore1
-rw-r--r--testing/resources/ruby_hooks_repo/.pre-commit-hooks.yaml5
-rwxr-xr-xtesting/resources/ruby_hooks_repo/bin/ruby_hook3
-rw-r--r--testing/resources/ruby_hooks_repo/lib/.gitignore0
-rw-r--r--testing/resources/ruby_hooks_repo/ruby_hook.gemspec9
-rw-r--r--testing/resources/ruby_versioned_hooks_repo/.gitignore1
-rw-r--r--testing/resources/ruby_versioned_hooks_repo/.pre-commit-hooks.yaml6
-rwxr-xr-xtesting/resources/ruby_versioned_hooks_repo/bin/ruby_hook4
-rw-r--r--testing/resources/ruby_versioned_hooks_repo/lib/.gitignore0
-rw-r--r--testing/resources/ruby_versioned_hooks_repo/ruby_hook.gemspec9
-rw-r--r--testing/resources/rust_hooks_repo/.pre-commit-hooks.yaml5
-rw-r--r--testing/resources/rust_hooks_repo/Cargo.lock3
-rw-r--r--testing/resources/rust_hooks_repo/Cargo.toml3
-rw-r--r--testing/resources/rust_hooks_repo/src/main.rs3
-rw-r--r--testing/resources/script_hooks_repo/.pre-commit-hooks.yaml5
-rwxr-xr-xtesting/resources/script_hooks_repo/bin/hook.sh4
-rw-r--r--testing/resources/stdout_stderr_repo/.pre-commit-hooks.yaml8
-rwxr-xr-xtesting/resources/stdout_stderr_repo/stdout-stderr-entry7
-rwxr-xr-xtesting/resources/stdout_stderr_repo/tty-check-entry11
-rw-r--r--testing/resources/swift_hooks_repo/.gitignore4
-rw-r--r--testing/resources/swift_hooks_repo/.pre-commit-hooks.yaml6
-rw-r--r--testing/resources/swift_hooks_repo/Package.swift7
-rw-r--r--testing/resources/swift_hooks_repo/Sources/swift_hooks_repo/main.swift1
-rw-r--r--testing/resources/system_hook_with_spaces_repo/.pre-commit-hooks.yaml5
-rw-r--r--testing/resources/types_repo/.pre-commit-hooks.yaml5
-rwxr-xr-xtesting/resources/types_repo/bin/hook.sh3
-rw-r--r--testing/util.py113
79 files changed, 736 insertions, 0 deletions
diff --git a/testing/__init__.py b/testing/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/testing/__init__.py
diff --git a/testing/auto_namedtuple.py b/testing/auto_namedtuple.py
new file mode 100644
index 0000000..0841094
--- /dev/null
+++ b/testing/auto_namedtuple.py
@@ -0,0 +1,11 @@
+import collections
+
+
+def auto_namedtuple(classname='auto_namedtuple', **kwargs):
+ """Returns an automatic namedtuple object.
+
+ Args:
+ classname - The class name for the returned object.
+ **kwargs - Properties to give the returned object.
+ """
+ return (collections.namedtuple(classname, kwargs.keys())(**kwargs))
diff --git a/testing/fixtures.py b/testing/fixtures.py
new file mode 100644
index 0000000..f7def08
--- /dev/null
+++ b/testing/fixtures.py
@@ -0,0 +1,146 @@
+import contextlib
+import os.path
+import shutil
+
+from cfgv import apply_defaults
+from cfgv import validate
+
+import pre_commit.constants as C
+from pre_commit import git
+from pre_commit.clientlib import CONFIG_SCHEMA
+from pre_commit.clientlib import load_manifest
+from pre_commit.util import cmd_output
+from pre_commit.util import yaml_dump
+from pre_commit.util import yaml_load
+from testing.util import get_resource_path
+from testing.util import git_commit
+
+
+def copy_tree_to_path(src_dir, dest_dir):
+ """Copies all of the things inside src_dir to an already existing dest_dir.
+
+ This looks eerily similar to shutil.copytree, but copytree has no option
+ for not creating dest_dir.
+ """
+ names = os.listdir(src_dir)
+
+ for name in names:
+ srcname = os.path.join(src_dir, name)
+ destname = os.path.join(dest_dir, name)
+
+ if os.path.isdir(srcname):
+ shutil.copytree(srcname, destname)
+ else:
+ shutil.copy(srcname, destname)
+
+
+def git_dir(tempdir_factory):
+ path = tempdir_factory.get()
+ cmd_output('git', 'init', path)
+ return path
+
+
+def make_repo(tempdir_factory, repo_source):
+ path = git_dir(tempdir_factory)
+ copy_tree_to_path(get_resource_path(repo_source), path)
+ cmd_output('git', 'add', '.', cwd=path)
+ git_commit(msg=make_repo.__name__, cwd=path)
+ return path
+
+
+@contextlib.contextmanager
+def modify_manifest(path, commit=True):
+ """Modify the manifest yielded by this context to write to
+ .pre-commit-hooks.yaml.
+ """
+ manifest_path = os.path.join(path, C.MANIFEST_FILE)
+ with open(manifest_path) as f:
+ manifest = yaml_load(f.read())
+ yield manifest
+ with open(manifest_path, 'w') as manifest_file:
+ manifest_file.write(yaml_dump(manifest))
+ if commit:
+ git_commit(msg=modify_manifest.__name__, cwd=path)
+
+
+@contextlib.contextmanager
+def modify_config(path='.', commit=True):
+ """Modify the config yielded by this context to write to
+ .pre-commit-config.yaml
+ """
+ config_path = os.path.join(path, C.CONFIG_FILE)
+ with open(config_path) as f:
+ config = yaml_load(f.read())
+ yield config
+ with open(config_path, 'w', encoding='UTF-8') as config_file:
+ config_file.write(yaml_dump(config))
+ if commit:
+ git_commit(msg=modify_config.__name__, cwd=path)
+
+
+def sample_local_config():
+ return {
+ 'repo': 'local',
+ 'hooks': [{
+ 'id': 'do_not_commit',
+ 'name': 'Block if "DO NOT COMMIT" is found',
+ 'entry': 'DO NOT COMMIT',
+ 'language': 'pygrep',
+ }],
+ }
+
+
+def sample_meta_config():
+ return {'repo': 'meta', 'hooks': [{'id': 'check-useless-excludes'}]}
+
+
+def make_config_from_repo(repo_path, rev=None, hooks=None, check=True):
+ manifest = load_manifest(os.path.join(repo_path, C.MANIFEST_FILE))
+ config = {
+ 'repo': f'file://{repo_path}',
+ 'rev': rev or git.head_rev(repo_path),
+ 'hooks': hooks or [{'id': hook['id']} for hook in manifest],
+ }
+
+ if check:
+ wrapped = validate({'repos': [config]}, CONFIG_SCHEMA)
+ wrapped = apply_defaults(wrapped, CONFIG_SCHEMA)
+ config, = wrapped['repos']
+ return config
+ else:
+ return config
+
+
+def read_config(directory, config_file=C.CONFIG_FILE):
+ config_path = os.path.join(directory, config_file)
+ with open(config_path) as f:
+ config = yaml_load(f.read())
+ return config
+
+
+def write_config(directory, config, config_file=C.CONFIG_FILE):
+ if type(config) is not list and 'repos' not in config:
+ assert isinstance(config, dict), config
+ config = {'repos': [config]}
+ with open(os.path.join(directory, config_file), 'w') as outfile:
+ outfile.write(yaml_dump(config))
+
+
+def add_config_to_repo(git_path, config, config_file=C.CONFIG_FILE):
+ write_config(git_path, config, config_file=config_file)
+ cmd_output('git', 'add', config_file, cwd=git_path)
+ git_commit(msg=add_config_to_repo.__name__, cwd=git_path)
+ return git_path
+
+
+def remove_config_from_repo(git_path, config_file=C.CONFIG_FILE):
+ cmd_output('git', 'rm', config_file, cwd=git_path)
+ git_commit(msg=remove_config_from_repo.__name__, cwd=git_path)
+ return git_path
+
+
+def make_consuming_repo(tempdir_factory, repo_source):
+ path = make_repo(tempdir_factory, repo_source)
+ config = make_config_from_repo(path)
+ git_path = git_dir(tempdir_factory)
+ return add_config_to_repo(git_path, config)
diff --git a/testing/gen-languages-all b/testing/gen-languages-all
new file mode 100755
index 0000000..6d0b26f
--- /dev/null
+++ b/testing/gen-languages-all
@@ -0,0 +1,28 @@
+#!/usr/bin/env python3
+import sys
+
+LANGUAGES = [
+ 'conda', 'docker', 'docker_image', 'fail', 'golang', 'node', 'perl',
+ 'pygrep', 'python', 'python_venv', 'ruby', 'rust', 'script', 'swift',
+ 'system',
+]
+FIELDS = [
+ 'ENVIRONMENT_DIR', 'get_default_version', 'healthy', 'install_environment',
+ 'run_hook',
+]
+
+
+def main() -> int:
+ print(f' # BEGIN GENERATED ({sys.argv[0]})')
+ for lang in LANGUAGES:
+ parts = [f' {lang!r}: Language(name={lang!r}']
+ for k in FIELDS:
+ parts.append(f', {k}={lang}.{k}')
+ parts.append('), # noqa: E501')
+ print(''.join(parts))
+ print(' # END GENERATED')
+ return 0
+
+
+if __name__ == '__main__':
+ exit(main())
diff --git a/testing/get-swift.sh b/testing/get-swift.sh
new file mode 100755
index 0000000..e205d44
--- /dev/null
+++ b/testing/get-swift.sh
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+# This is a script used in CI to install swift
+set -euxo pipefail
+
+. /etc/lsb-release
+if [ "$DISTRIB_CODENAME" = "bionic" ]; then
+ SWIFT_URL='https://swift.org/builds/swift-5.1.3-release/ubuntu1804/swift-5.1.3-RELEASE/swift-5.1.3-RELEASE-ubuntu18.04.tar.gz'
+ SWIFT_HASH='ac82ccd773fe3d586fc340814e31e120da1ff695c6a712f6634e9cc720769610'
+else
+ echo "unknown dist: ${DISTRIB_CODENAME}" 1>&2
+ exit 1
+fi
+
+check() {
+ echo "$SWIFT_HASH $TGZ" | sha256sum --check
+}
+
+TGZ="$HOME/.swift/swift.tar.gz"
+mkdir -p "$(dirname "$TGZ")"
+if ! check >& /dev/null; then
+ rm -f "$TGZ"
+ curl --location --silent --output "$TGZ" "$SWIFT_URL"
+ check
+fi
+
+mkdir -p /tmp/swift
+tar -xf "$TGZ" --strip 1 --directory /tmp/swift
diff --git a/testing/resources/arbitrary_bytes_repo/.pre-commit-hooks.yaml b/testing/resources/arbitrary_bytes_repo/.pre-commit-hooks.yaml
new file mode 100644
index 0000000..c2aec9b
--- /dev/null
+++ b/testing/resources/arbitrary_bytes_repo/.pre-commit-hooks.yaml
@@ -0,0 +1,5 @@
+- id: hook
+ name: hook
+ entry: ./hook.sh
+ language: script
+ files: \.py$
diff --git a/testing/resources/arbitrary_bytes_repo/hook.sh b/testing/resources/arbitrary_bytes_repo/hook.sh
new file mode 100755
index 0000000..9df0c5a
--- /dev/null
+++ b/testing/resources/arbitrary_bytes_repo/hook.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+# Intentionally write mixed encoding to the output. This should not crash
+# pre-commit and should write bytes to the output.
+# '☃'.encode() + '²'.encode('latin1')
+echo -e '\xe2\x98\x83\xb2'
+# exit 1 to trigger printing
+exit 1
diff --git a/testing/resources/arg_per_line_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/arg_per_line_hooks_repo/.pre-commit-hooks.yaml
new file mode 100644
index 0000000..4c101db
--- /dev/null
+++ b/testing/resources/arg_per_line_hooks_repo/.pre-commit-hooks.yaml
@@ -0,0 +1,6 @@
+- id: arg-per-line
+ name: Args per line hook
+ entry: bin/hook.sh
+ language: script
+ files: ''
+ args: [hello, world]
diff --git a/testing/resources/arg_per_line_hooks_repo/bin/hook.sh b/testing/resources/arg_per_line_hooks_repo/bin/hook.sh
new file mode 100755
index 0000000..47fd21d
--- /dev/null
+++ b/testing/resources/arg_per_line_hooks_repo/bin/hook.sh
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+
+for i in "$@"; do
+ echo "arg: $i"
+done
diff --git a/testing/resources/conda_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/conda_hooks_repo/.pre-commit-hooks.yaml
new file mode 100644
index 0000000..a0d274c
--- /dev/null
+++ b/testing/resources/conda_hooks_repo/.pre-commit-hooks.yaml
@@ -0,0 +1,10 @@
+- id: sys-exec
+ name: sys-exec
+ entry: python -c 'import os; import sys; print(sys.executable.split(os.path.sep)[-2]) if os.name == "nt" else print(sys.executable.split(os.path.sep)[-3])'
+ language: conda
+ files: \.py$
+- id: additional-deps
+ name: additional-deps
+ entry: python
+ language: conda
+ files: \.py$
diff --git a/testing/resources/conda_hooks_repo/environment.yml b/testing/resources/conda_hooks_repo/environment.yml
new file mode 100644
index 0000000..e23c079
--- /dev/null
+++ b/testing/resources/conda_hooks_repo/environment.yml
@@ -0,0 +1,6 @@
+channels:
+ - conda-forge
+ - defaults
+dependencies:
+ - python
+ - pip
diff --git a/testing/resources/docker_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/docker_hooks_repo/.pre-commit-hooks.yaml
new file mode 100644
index 0000000..5295739
--- /dev/null
+++ b/testing/resources/docker_hooks_repo/.pre-commit-hooks.yaml
@@ -0,0 +1,17 @@
+- id: docker-hook
+ name: Docker test hook
+ entry: echo
+ language: docker
+ files: \.txt$
+
+- id: docker-hook-arg
+ name: Docker test hook
+ entry: echo -n
+ language: docker
+ files: \.txt$
+
+- id: docker-hook-failing
+ name: Docker test hook with nonzero exit code
+ entry: bork
+ language: docker
+ files: \.txt$
diff --git a/testing/resources/docker_hooks_repo/Dockerfile b/testing/resources/docker_hooks_repo/Dockerfile
new file mode 100644
index 0000000..841b151
--- /dev/null
+++ b/testing/resources/docker_hooks_repo/Dockerfile
@@ -0,0 +1,3 @@
+FROM cogniteev/echo
+
+CMD ["echo", "This is overwritten by the .pre-commit-hooks.yaml 'entry'"]
diff --git a/testing/resources/docker_image_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/docker_image_hooks_repo/.pre-commit-hooks.yaml
new file mode 100644
index 0000000..1b385aa
--- /dev/null
+++ b/testing/resources/docker_image_hooks_repo/.pre-commit-hooks.yaml
@@ -0,0 +1,8 @@
+- id: echo-entrypoint
+ name: echo (via --entrypoint)
+ language: docker_image
+ entry: --entrypoint echo cogniteev/echo
+- id: echo-cmd
+ name: echo (via cmd)
+ language: docker_image
+ entry: cogniteev/echo echo
diff --git a/testing/resources/exclude_types_repo/.pre-commit-hooks.yaml b/testing/resources/exclude_types_repo/.pre-commit-hooks.yaml
new file mode 100644
index 0000000..ed8794f
--- /dev/null
+++ b/testing/resources/exclude_types_repo/.pre-commit-hooks.yaml
@@ -0,0 +1,6 @@
+- id: python-files
+ name: Python files
+ entry: bin/hook.sh
+ language: script
+ types: [python]
+ exclude_types: [python3]
diff --git a/testing/resources/exclude_types_repo/bin/hook.sh b/testing/resources/exclude_types_repo/bin/hook.sh
new file mode 100755
index 0000000..bdade51
--- /dev/null
+++ b/testing/resources/exclude_types_repo/bin/hook.sh
@@ -0,0 +1,3 @@
+#!/usr/bin/env bash
+echo $@
+exit 1
diff --git a/testing/resources/failing_hook_repo/.pre-commit-hooks.yaml b/testing/resources/failing_hook_repo/.pre-commit-hooks.yaml
new file mode 100644
index 0000000..118cc8b
--- /dev/null
+++ b/testing/resources/failing_hook_repo/.pre-commit-hooks.yaml
@@ -0,0 +1,5 @@
+- id: failing_hook
+ name: Failing hook
+ entry: bin/hook.sh
+ language: script
+ files: .
diff --git a/testing/resources/failing_hook_repo/bin/hook.sh b/testing/resources/failing_hook_repo/bin/hook.sh
new file mode 100755
index 0000000..229ccaf
--- /dev/null
+++ b/testing/resources/failing_hook_repo/bin/hook.sh
@@ -0,0 +1,4 @@
+#!/usr/bin/env bash
+echo 'Fail'
+echo $@
+exit 1
diff --git a/testing/resources/golang_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/golang_hooks_repo/.pre-commit-hooks.yaml
new file mode 100644
index 0000000..206733b
--- /dev/null
+++ b/testing/resources/golang_hooks_repo/.pre-commit-hooks.yaml
@@ -0,0 +1,5 @@
+- id: golang-hook
+ name: golang example hook
+ entry: golang-hello-world
+ language: golang
+ files: ''
diff --git a/testing/resources/golang_hooks_repo/golang-hello-world/main.go b/testing/resources/golang_hooks_repo/golang-hello-world/main.go
new file mode 100644
index 0000000..1e3c591
--- /dev/null
+++ b/testing/resources/golang_hooks_repo/golang-hello-world/main.go
@@ -0,0 +1,17 @@
+package main
+
+
+import (
+ "fmt"
+ "github.com/BurntSushi/toml"
+)
+
+type Config struct {
+ What string
+}
+
+func main() {
+ var conf Config
+ toml.Decode("What = 'world'\n", &conf)
+ fmt.Printf("hello %v\n", conf.What)
+}
diff --git a/testing/resources/img1.jpg b/testing/resources/img1.jpg
new file mode 100644
index 0000000..dea4262
--- /dev/null
+++ b/testing/resources/img1.jpg
Binary files differ
diff --git a/testing/resources/img2.jpg b/testing/resources/img2.jpg
new file mode 100644
index 0000000..68568e5
--- /dev/null
+++ b/testing/resources/img2.jpg
Binary files differ
diff --git a/testing/resources/img3.jpg b/testing/resources/img3.jpg
new file mode 100644
index 0000000..392d2cf
--- /dev/null
+++ b/testing/resources/img3.jpg
Binary files differ
diff --git a/testing/resources/logfile_repo/.pre-commit-hooks.yaml b/testing/resources/logfile_repo/.pre-commit-hooks.yaml
new file mode 100644
index 0000000..dcaba2e
--- /dev/null
+++ b/testing/resources/logfile_repo/.pre-commit-hooks.yaml
@@ -0,0 +1,6 @@
+- id: logfile test hook
+ name: Logfile test hook
+ entry: bin/hook.sh
+ language: script
+ files: .
+ log_file: test.log
diff --git a/testing/resources/logfile_repo/bin/hook.sh b/testing/resources/logfile_repo/bin/hook.sh
new file mode 100755
index 0000000..890d941
--- /dev/null
+++ b/testing/resources/logfile_repo/bin/hook.sh
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+echo "This is STDOUT output"
+echo "This is STDERR output" 1>&2
+
+exit 1
diff --git a/testing/resources/modified_file_returns_zero_repo/.pre-commit-hooks.yaml b/testing/resources/modified_file_returns_zero_repo/.pre-commit-hooks.yaml
new file mode 100644
index 0000000..8d79ef3
--- /dev/null
+++ b/testing/resources/modified_file_returns_zero_repo/.pre-commit-hooks.yaml
@@ -0,0 +1,15 @@
+- id: bash_hook
+ name: Bash hook
+ entry: bin/hook.sh
+ language: script
+ files: 'foo.py'
+- id: bash_hook2
+ name: Bash hook
+ entry: bin/hook2.sh
+ language: script
+ files: ''
+- id: bash_hook3
+ name: Bash hook
+ entry: bin/hook3.sh
+ language: script
+ files: 'bar.py'
diff --git a/testing/resources/modified_file_returns_zero_repo/bin/hook.sh b/testing/resources/modified_file_returns_zero_repo/bin/hook.sh
new file mode 100755
index 0000000..98b05f9
--- /dev/null
+++ b/testing/resources/modified_file_returns_zero_repo/bin/hook.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+for f in $@; do
+ # Non UTF-8 bytes
+ echo -e '\x01\x97' > "$f"
+ echo "Modified: $f!"
+done
diff --git a/testing/resources/modified_file_returns_zero_repo/bin/hook2.sh b/testing/resources/modified_file_returns_zero_repo/bin/hook2.sh
new file mode 100755
index 0000000..5af177a
--- /dev/null
+++ b/testing/resources/modified_file_returns_zero_repo/bin/hook2.sh
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+echo $@
diff --git a/testing/resources/modified_file_returns_zero_repo/bin/hook3.sh b/testing/resources/modified_file_returns_zero_repo/bin/hook3.sh
new file mode 100755
index 0000000..3180eb3
--- /dev/null
+++ b/testing/resources/modified_file_returns_zero_repo/bin/hook3.sh
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash
+
+for f in $@; do
+ # Non UTF-8 bytes
+ echo -e '\x01\x97' > "$f"
+done
diff --git a/testing/resources/node_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/node_hooks_repo/.pre-commit-hooks.yaml
new file mode 100644
index 0000000..257698a
--- /dev/null
+++ b/testing/resources/node_hooks_repo/.pre-commit-hooks.yaml
@@ -0,0 +1,5 @@
+- id: foo
+ name: Foo
+ entry: foo
+ language: node
+ files: \.js$
diff --git a/testing/resources/node_hooks_repo/bin/main.js b/testing/resources/node_hooks_repo/bin/main.js
new file mode 100644
index 0000000..8e0f025
--- /dev/null
+++ b/testing/resources/node_hooks_repo/bin/main.js
@@ -0,0 +1,3 @@
+#!/usr/bin/env node
+
+console.log('Hello World');
diff --git a/testing/resources/node_hooks_repo/package.json b/testing/resources/node_hooks_repo/package.json
new file mode 100644
index 0000000..050b630
--- /dev/null
+++ b/testing/resources/node_hooks_repo/package.json
@@ -0,0 +1,5 @@
+{
+ "name": "foo",
+ "version": "0.0.1",
+ "bin": {"foo": "./bin/main.js"}
+}
diff --git a/testing/resources/node_versioned_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/node_versioned_hooks_repo/.pre-commit-hooks.yaml
new file mode 100644
index 0000000..e7ad5ea
--- /dev/null
+++ b/testing/resources/node_versioned_hooks_repo/.pre-commit-hooks.yaml
@@ -0,0 +1,6 @@
+- id: versioned-node-hook
+ name: Versioned node hook
+ entry: versioned-node-hook
+ language: node
+ language_version: 9.3.0
+ files: \.js$
diff --git a/testing/resources/node_versioned_hooks_repo/bin/main.js b/testing/resources/node_versioned_hooks_repo/bin/main.js
new file mode 100644
index 0000000..df12cbe
--- /dev/null
+++ b/testing/resources/node_versioned_hooks_repo/bin/main.js
@@ -0,0 +1,4 @@
+#!/usr/bin/env node
+
+console.log(process.version);
+console.log('Hello World');
diff --git a/testing/resources/node_versioned_hooks_repo/package.json b/testing/resources/node_versioned_hooks_repo/package.json
new file mode 100644
index 0000000..18c7787
--- /dev/null
+++ b/testing/resources/node_versioned_hooks_repo/package.json
@@ -0,0 +1,5 @@
+{
+ "name": "versioned-node-hook",
+ "version": "0.0.1",
+ "bin": {"versioned-node-hook": "./bin/main.js"}
+}
diff --git a/testing/resources/not_found_exe/.pre-commit-hooks.yaml b/testing/resources/not_found_exe/.pre-commit-hooks.yaml
new file mode 100644
index 0000000..566f3c1
--- /dev/null
+++ b/testing/resources/not_found_exe/.pre-commit-hooks.yaml
@@ -0,0 +1,5 @@
+- id: not-found-exe
+ name: Not found exe
+ entry: i-dont-exist-lol
+ language: system
+ files: ''
diff --git a/testing/resources/perl_hooks_repo/.gitignore b/testing/resources/perl_hooks_repo/.gitignore
new file mode 100644
index 0000000..7af9940
--- /dev/null
+++ b/testing/resources/perl_hooks_repo/.gitignore
@@ -0,0 +1,7 @@
+/MYMETA.json
+/MYMETA.yml
+/Makefile
+/PreCommitHello-*.tar.*
+/PreCommitHello-*/
+/blib/
+/pm_to_blib
diff --git a/testing/resources/perl_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/perl_hooks_repo/.pre-commit-hooks.yaml
new file mode 100644
index 0000000..11e6f6c
--- /dev/null
+++ b/testing/resources/perl_hooks_repo/.pre-commit-hooks.yaml
@@ -0,0 +1,5 @@
+- id: perl-hook
+ name: perl example hook
+ entry: pre-commit-perl-hello
+ language: perl
+ files: ''
diff --git a/testing/resources/perl_hooks_repo/MANIFEST b/testing/resources/perl_hooks_repo/MANIFEST
new file mode 100644
index 0000000..4a20084
--- /dev/null
+++ b/testing/resources/perl_hooks_repo/MANIFEST
@@ -0,0 +1,4 @@
+MANIFEST
+Makefile.PL
+bin/pre-commit-perl-hello
+lib/PreCommitHello.pm
diff --git a/testing/resources/perl_hooks_repo/Makefile.PL b/testing/resources/perl_hooks_repo/Makefile.PL
new file mode 100644
index 0000000..6c70e10
--- /dev/null
+++ b/testing/resources/perl_hooks_repo/Makefile.PL
@@ -0,0 +1,10 @@
+use strict;
+use warnings;
+
+use ExtUtils::MakeMaker;
+
+WriteMakefile(
+ NAME => "PreCommitHello",
+ VERSION_FROM => "lib/PreCommitHello.pm",
+ EXE_FILES => [qw(bin/pre-commit-perl-hello)],
+);
diff --git a/testing/resources/perl_hooks_repo/bin/pre-commit-perl-hello b/testing/resources/perl_hooks_repo/bin/pre-commit-perl-hello
new file mode 100755
index 0000000..9474009
--- /dev/null
+++ b/testing/resources/perl_hooks_repo/bin/pre-commit-perl-hello
@@ -0,0 +1,7 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+use PreCommitHello;
+
+PreCommitHello::hello();
diff --git a/testing/resources/perl_hooks_repo/lib/PreCommitHello.pm b/testing/resources/perl_hooks_repo/lib/PreCommitHello.pm
new file mode 100644
index 0000000..c76521c
--- /dev/null
+++ b/testing/resources/perl_hooks_repo/lib/PreCommitHello.pm
@@ -0,0 +1,12 @@
+package PreCommitHello;
+
+use strict;
+use warnings;
+
+our $VERSION = "0.1.0";
+
+sub hello {
+ print "Hello from perl-commit Perl!\n";
+}
+
+1;
diff --git a/testing/resources/prints_cwd_repo/.pre-commit-hooks.yaml b/testing/resources/prints_cwd_repo/.pre-commit-hooks.yaml
new file mode 100644
index 0000000..7092379
--- /dev/null
+++ b/testing/resources/prints_cwd_repo/.pre-commit-hooks.yaml
@@ -0,0 +1,5 @@
+- id: prints_cwd
+ name: Prints Cwd
+ entry: pwd
+ language: system
+ files: \.sh$
diff --git a/testing/resources/python3_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/python3_hooks_repo/.pre-commit-hooks.yaml
new file mode 100644
index 0000000..2c23700
--- /dev/null
+++ b/testing/resources/python3_hooks_repo/.pre-commit-hooks.yaml
@@ -0,0 +1,6 @@
+- id: python3-hook
+ name: Python 3 Hook
+ entry: python3-hook
+ language: python
+ language_version: python3
+ files: \.py$
diff --git a/testing/resources/python3_hooks_repo/py3_hook.py b/testing/resources/python3_hooks_repo/py3_hook.py
new file mode 100644
index 0000000..8c9cda4
--- /dev/null
+++ b/testing/resources/python3_hooks_repo/py3_hook.py
@@ -0,0 +1,8 @@
+import sys
+
+
+def main():
+ print(sys.version_info[0])
+ print(repr(sys.argv[1:]))
+ print('Hello World')
+ return 0
diff --git a/testing/resources/python3_hooks_repo/setup.py b/testing/resources/python3_hooks_repo/setup.py
new file mode 100644
index 0000000..9125dc1
--- /dev/null
+++ b/testing/resources/python3_hooks_repo/setup.py
@@ -0,0 +1,8 @@
+from setuptools import setup
+
+setup(
+ name='python3_hook',
+ version='0.0.0',
+ py_modules=['py3_hook'],
+ entry_points={'console_scripts': ['python3-hook = py3_hook:main']},
+)
diff --git a/testing/resources/python_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/python_hooks_repo/.pre-commit-hooks.yaml
new file mode 100644
index 0000000..e10ad50
--- /dev/null
+++ b/testing/resources/python_hooks_repo/.pre-commit-hooks.yaml
@@ -0,0 +1,5 @@
+- id: foo
+ name: Foo
+ entry: foo
+ language: python
+ files: \.py$
diff --git a/testing/resources/python_hooks_repo/foo.py b/testing/resources/python_hooks_repo/foo.py
new file mode 100644
index 0000000..9c4368e
--- /dev/null
+++ b/testing/resources/python_hooks_repo/foo.py
@@ -0,0 +1,7 @@
+import sys
+
+
+def main():
+ print(repr(sys.argv[1:]))
+ print('Hello World')
+ return 0
diff --git a/testing/resources/python_hooks_repo/setup.py b/testing/resources/python_hooks_repo/setup.py
new file mode 100644
index 0000000..0559271
--- /dev/null
+++ b/testing/resources/python_hooks_repo/setup.py
@@ -0,0 +1,8 @@
+from setuptools import setup
+
+setup(
+ name='foo',
+ version='0.0.0',
+ py_modules=['foo'],
+ entry_points={'console_scripts': ['foo = foo:main']},
+)
diff --git a/testing/resources/python_venv_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/python_venv_hooks_repo/.pre-commit-hooks.yaml
new file mode 100644
index 0000000..a666ed8
--- /dev/null
+++ b/testing/resources/python_venv_hooks_repo/.pre-commit-hooks.yaml
@@ -0,0 +1,5 @@
+- id: foo
+ name: Foo
+ entry: foo
+ language: python_venv
+ files: \.py$
diff --git a/testing/resources/python_venv_hooks_repo/foo.py b/testing/resources/python_venv_hooks_repo/foo.py
new file mode 100644
index 0000000..9c4368e
--- /dev/null
+++ b/testing/resources/python_venv_hooks_repo/foo.py
@@ -0,0 +1,7 @@
+import sys
+
+
+def main():
+ print(repr(sys.argv[1:]))
+ print('Hello World')
+ return 0
diff --git a/testing/resources/python_venv_hooks_repo/setup.py b/testing/resources/python_venv_hooks_repo/setup.py
new file mode 100644
index 0000000..0559271
--- /dev/null
+++ b/testing/resources/python_venv_hooks_repo/setup.py
@@ -0,0 +1,8 @@
+from setuptools import setup
+
+setup(
+ name='foo',
+ version='0.0.0',
+ py_modules=['foo'],
+ entry_points={'console_scripts': ['foo = foo:main']},
+)
diff --git a/testing/resources/ruby_hooks_repo/.gitignore b/testing/resources/ruby_hooks_repo/.gitignore
new file mode 100644
index 0000000..c111b33
--- /dev/null
+++ b/testing/resources/ruby_hooks_repo/.gitignore
@@ -0,0 +1 @@
+*.gem
diff --git a/testing/resources/ruby_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/ruby_hooks_repo/.pre-commit-hooks.yaml
new file mode 100644
index 0000000..aa15872
--- /dev/null
+++ b/testing/resources/ruby_hooks_repo/.pre-commit-hooks.yaml
@@ -0,0 +1,5 @@
+- id: ruby_hook
+ name: Ruby Hook
+ entry: ruby_hook
+ language: ruby
+ files: \.rb$
diff --git a/testing/resources/ruby_hooks_repo/bin/ruby_hook b/testing/resources/ruby_hooks_repo/bin/ruby_hook
new file mode 100755
index 0000000..5a7e5ed
--- /dev/null
+++ b/testing/resources/ruby_hooks_repo/bin/ruby_hook
@@ -0,0 +1,3 @@
+#!/usr/bin/env ruby
+
+puts 'Hello world from a ruby hook'
diff --git a/testing/resources/ruby_hooks_repo/lib/.gitignore b/testing/resources/ruby_hooks_repo/lib/.gitignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/testing/resources/ruby_hooks_repo/lib/.gitignore
diff --git a/testing/resources/ruby_hooks_repo/ruby_hook.gemspec b/testing/resources/ruby_hooks_repo/ruby_hook.gemspec
new file mode 100644
index 0000000..75f4e8f
--- /dev/null
+++ b/testing/resources/ruby_hooks_repo/ruby_hook.gemspec
@@ -0,0 +1,9 @@
+Gem::Specification.new do |s|
+ s.name = 'ruby_hook'
+ s.version = '0.1.0'
+ s.authors = ['Anthony Sottile']
+ s.summary = 'A ruby hook!'
+ s.description = 'A ruby hook!'
+ s.files = ['bin/ruby_hook']
+ s.executables = ['ruby_hook']
+end
diff --git a/testing/resources/ruby_versioned_hooks_repo/.gitignore b/testing/resources/ruby_versioned_hooks_repo/.gitignore
new file mode 100644
index 0000000..c111b33
--- /dev/null
+++ b/testing/resources/ruby_versioned_hooks_repo/.gitignore
@@ -0,0 +1 @@
+*.gem
diff --git a/testing/resources/ruby_versioned_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/ruby_versioned_hooks_repo/.pre-commit-hooks.yaml
new file mode 100644
index 0000000..63e1dd4
--- /dev/null
+++ b/testing/resources/ruby_versioned_hooks_repo/.pre-commit-hooks.yaml
@@ -0,0 +1,6 @@
+- id: ruby_hook
+ name: Ruby Hook
+ entry: ruby_hook
+ language: ruby
+ language_version: 2.5.1
+ files: \.rb$
diff --git a/testing/resources/ruby_versioned_hooks_repo/bin/ruby_hook b/testing/resources/ruby_versioned_hooks_repo/bin/ruby_hook
new file mode 100755
index 0000000..2406f04
--- /dev/null
+++ b/testing/resources/ruby_versioned_hooks_repo/bin/ruby_hook
@@ -0,0 +1,4 @@
+#!/usr/bin/env ruby
+
+puts RUBY_VERSION
+puts 'Hello world from a ruby hook'
diff --git a/testing/resources/ruby_versioned_hooks_repo/lib/.gitignore b/testing/resources/ruby_versioned_hooks_repo/lib/.gitignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/testing/resources/ruby_versioned_hooks_repo/lib/.gitignore
diff --git a/testing/resources/ruby_versioned_hooks_repo/ruby_hook.gemspec b/testing/resources/ruby_versioned_hooks_repo/ruby_hook.gemspec
new file mode 100644
index 0000000..75f4e8f
--- /dev/null
+++ b/testing/resources/ruby_versioned_hooks_repo/ruby_hook.gemspec
@@ -0,0 +1,9 @@
+Gem::Specification.new do |s|
+ s.name = 'ruby_hook'
+ s.version = '0.1.0'
+ s.authors = ['Anthony Sottile']
+ s.summary = 'A ruby hook!'
+ s.description = 'A ruby hook!'
+ s.files = ['bin/ruby_hook']
+ s.executables = ['ruby_hook']
+end
diff --git a/testing/resources/rust_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/rust_hooks_repo/.pre-commit-hooks.yaml
new file mode 100644
index 0000000..df1269f
--- /dev/null
+++ b/testing/resources/rust_hooks_repo/.pre-commit-hooks.yaml
@@ -0,0 +1,5 @@
+- id: rust-hook
+ name: rust example hook
+ entry: rust-hello-world
+ language: rust
+ files: ''
diff --git a/testing/resources/rust_hooks_repo/Cargo.lock b/testing/resources/rust_hooks_repo/Cargo.lock
new file mode 100644
index 0000000..36fbfda
--- /dev/null
+++ b/testing/resources/rust_hooks_repo/Cargo.lock
@@ -0,0 +1,3 @@
+[[package]]
+name = "rust-hello-world"
+version = "0.1.0"
diff --git a/testing/resources/rust_hooks_repo/Cargo.toml b/testing/resources/rust_hooks_repo/Cargo.toml
new file mode 100644
index 0000000..cd83b43
--- /dev/null
+++ b/testing/resources/rust_hooks_repo/Cargo.toml
@@ -0,0 +1,3 @@
+[package]
+name = "rust-hello-world"
+version = "0.1.0"
diff --git a/testing/resources/rust_hooks_repo/src/main.rs b/testing/resources/rust_hooks_repo/src/main.rs
new file mode 100644
index 0000000..ad379d6
--- /dev/null
+++ b/testing/resources/rust_hooks_repo/src/main.rs
@@ -0,0 +1,3 @@
+fn main() {
+ println!("hello world");
+}
diff --git a/testing/resources/script_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/script_hooks_repo/.pre-commit-hooks.yaml
new file mode 100644
index 0000000..21cad4a
--- /dev/null
+++ b/testing/resources/script_hooks_repo/.pre-commit-hooks.yaml
@@ -0,0 +1,5 @@
+- id: bash_hook
+ name: Bash hook
+ entry: bin/hook.sh
+ language: script
+ files: ''
diff --git a/testing/resources/script_hooks_repo/bin/hook.sh b/testing/resources/script_hooks_repo/bin/hook.sh
new file mode 100755
index 0000000..6565ee4
--- /dev/null
+++ b/testing/resources/script_hooks_repo/bin/hook.sh
@@ -0,0 +1,4 @@
+#!/usr/bin/env bash
+
+echo $@
+echo 'Hello World'
diff --git a/testing/resources/stdout_stderr_repo/.pre-commit-hooks.yaml b/testing/resources/stdout_stderr_repo/.pre-commit-hooks.yaml
new file mode 100644
index 0000000..6800d25
--- /dev/null
+++ b/testing/resources/stdout_stderr_repo/.pre-commit-hooks.yaml
@@ -0,0 +1,8 @@
+- id: stdout-stderr
+ name: stdout-stderr
+ language: script
+ entry: ./stdout-stderr-entry
+- id: tty-check
+ name: tty-check
+ language: script
+ entry: ./tty-check-entry
diff --git a/testing/resources/stdout_stderr_repo/stdout-stderr-entry b/testing/resources/stdout_stderr_repo/stdout-stderr-entry
new file mode 100755
index 0000000..7563df5
--- /dev/null
+++ b/testing/resources/stdout_stderr_repo/stdout-stderr-entry
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+echo 0
+echo 1 1>&2
+echo 2
+echo 3 1>&2
+echo 4
+echo 5 1>&2
diff --git a/testing/resources/stdout_stderr_repo/tty-check-entry b/testing/resources/stdout_stderr_repo/tty-check-entry
new file mode 100755
index 0000000..01a9d38
--- /dev/null
+++ b/testing/resources/stdout_stderr_repo/tty-check-entry
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+t() {
+ if [ -t "$1" ]; then
+ echo "$2: True"
+ else
+ echo "$2: False"
+ fi
+}
+t 0 stdin
+t 1 stdout
+t 2 stderr
diff --git a/testing/resources/swift_hooks_repo/.gitignore b/testing/resources/swift_hooks_repo/.gitignore
new file mode 100644
index 0000000..02c0875
--- /dev/null
+++ b/testing/resources/swift_hooks_repo/.gitignore
@@ -0,0 +1,4 @@
+.DS_Store
+/.build
+/Packages
+/*.xcodeproj
diff --git a/testing/resources/swift_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/swift_hooks_repo/.pre-commit-hooks.yaml
new file mode 100644
index 0000000..c08df87
--- /dev/null
+++ b/testing/resources/swift_hooks_repo/.pre-commit-hooks.yaml
@@ -0,0 +1,6 @@
+- id: swift-hooks-repo
+ name: Swift hooks repo example
+ description: Runs the hello world app generated by swift package init --type executable (binary called swift_hooks_repo here)
+ entry: swift_hooks_repo
+ language: swift
+ files: \.(swift)$
diff --git a/testing/resources/swift_hooks_repo/Package.swift b/testing/resources/swift_hooks_repo/Package.swift
new file mode 100644
index 0000000..04976d3
--- /dev/null
+++ b/testing/resources/swift_hooks_repo/Package.swift
@@ -0,0 +1,7 @@
+// swift-tools-version:5.0
+import PackageDescription
+
+let package = Package(
+ name: "swift_hooks_repo",
+ targets: [.target(name: "swift_hooks_repo")]
+)
diff --git a/testing/resources/swift_hooks_repo/Sources/swift_hooks_repo/main.swift b/testing/resources/swift_hooks_repo/Sources/swift_hooks_repo/main.swift
new file mode 100644
index 0000000..f7cf60e
--- /dev/null
+++ b/testing/resources/swift_hooks_repo/Sources/swift_hooks_repo/main.swift
@@ -0,0 +1 @@
+print("Hello, world!")
diff --git a/testing/resources/system_hook_with_spaces_repo/.pre-commit-hooks.yaml b/testing/resources/system_hook_with_spaces_repo/.pre-commit-hooks.yaml
new file mode 100644
index 0000000..b2c347c
--- /dev/null
+++ b/testing/resources/system_hook_with_spaces_repo/.pre-commit-hooks.yaml
@@ -0,0 +1,5 @@
+- id: system-hook-with-spaces
+ name: System hook with spaces
+ entry: bash -c 'echo "Hello World"'
+ language: system
+ files: \.sh$
diff --git a/testing/resources/types_repo/.pre-commit-hooks.yaml b/testing/resources/types_repo/.pre-commit-hooks.yaml
new file mode 100644
index 0000000..2e5e4a6
--- /dev/null
+++ b/testing/resources/types_repo/.pre-commit-hooks.yaml
@@ -0,0 +1,5 @@
+- id: python-files
+ name: Python files
+ entry: bin/hook.sh
+ language: script
+ types: [python]
diff --git a/testing/resources/types_repo/bin/hook.sh b/testing/resources/types_repo/bin/hook.sh
new file mode 100755
index 0000000..bdade51
--- /dev/null
+++ b/testing/resources/types_repo/bin/hook.sh
@@ -0,0 +1,3 @@
+#!/usr/bin/env bash
+echo $@
+exit 1
diff --git a/testing/util.py b/testing/util.py
new file mode 100644
index 0000000..439bee7
--- /dev/null
+++ b/testing/util.py
@@ -0,0 +1,113 @@
+import contextlib
+import os.path
+import subprocess
+
+import pytest
+
+from pre_commit import parse_shebang
+from pre_commit.languages.docker import docker_is_running
+from pre_commit.util import cmd_output
+from testing.auto_namedtuple import auto_namedtuple
+
+
+TESTING_DIR = os.path.abspath(os.path.dirname(__file__))
+
+
+def get_resource_path(path):
+ return os.path.join(TESTING_DIR, 'resources', path)
+
+
+def cmd_output_mocked_pre_commit_home(
+ *args, tempdir_factory, pre_commit_home=None, env=None, **kwargs,
+):
+ if pre_commit_home is None:
+ pre_commit_home = tempdir_factory.get()
+ env = env if env is not None else os.environ
+ kwargs.setdefault('stderr', subprocess.STDOUT)
+ # Don't want to write to the home directory
+ env = dict(env, PRE_COMMIT_HOME=pre_commit_home)
+ ret, out, _ = cmd_output(*args, env=env, **kwargs)
+ return ret, out.replace('\r\n', '\n'), None
+
+
+skipif_cant_run_docker = pytest.mark.skipif(
+ os.name == 'nt' or not docker_is_running(),
+ reason="Docker isn't running or can't be accessed",
+)
+skipif_cant_run_swift = pytest.mark.skipif(
+ parse_shebang.find_executable('swift') is None,
+ reason="swift isn't installed or can't be found",
+)
+xfailif_windows_no_ruby = pytest.mark.xfail(
+ os.name == 'nt',
+ reason='Ruby support not yet implemented on windows.',
+)
+xfailif_windows = pytest.mark.xfail(os.name == 'nt', reason='windows')
+
+
+def supports_venv(): # pragma: no cover (platform specific)
+ try:
+ __import__('ensurepip')
+ __import__('venv')
+ return True
+ except ImportError:
+ return False
+
+
+xfailif_no_venv = pytest.mark.xfail(
+ not supports_venv(), reason='Does not support venv module',
+)
+
+
+def run_opts(
+ all_files=False,
+ files=(),
+ color=False,
+ verbose=False,
+ hook=None,
+ from_ref='',
+ to_ref='',
+ remote_name='',
+ remote_url='',
+ hook_stage='commit',
+ show_diff_on_failure=False,
+ commit_msg_filename='',
+ checkout_type='',
+):
+ # These are mutually exclusive
+ assert not (all_files and files)
+ return auto_namedtuple(
+ all_files=all_files,
+ files=files,
+ color=color,
+ verbose=verbose,
+ hook=hook,
+ from_ref=from_ref,
+ to_ref=to_ref,
+ remote_name=remote_name,
+ remote_url=remote_url,
+ hook_stage=hook_stage,
+ show_diff_on_failure=show_diff_on_failure,
+ commit_msg_filename=commit_msg_filename,
+ checkout_type=checkout_type,
+ )
+
+
+@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!', **kwargs):
+ kwargs.setdefault('stderr', subprocess.STDOUT)
+
+ cmd = ('git', 'commit', '--allow-empty', '--no-gpg-sign', '-a') + args
+ if msg is not None: # allow skipping `-m` with `msg=None`
+ cmd += ('-m', msg)
+ ret, out, _ = fn(*cmd, **kwargs)
+ return ret, out.replace('\r\n', '\n')