anon-iclr-submission/benchname-bug-localization huggingface dataset:
Repository: zulko/moviepy
Issue: Issue with nesting context managers

When we nest context managers which subclip, moviepy has an issue, as the innermost context manager will close the call to ffmpeg, but the outer objects assume it's there.
__Case 1:__
```
with VideoFileClip(video_file) as v:
    with v.subclip(1,2) as s:
        pass
    v.subclip(0,2).iter_frames().next()
```
Works as the reader is reinitialized here:
https://github.com/Zulko/moviepy/blob/master/moviepy/video/io/ffmpeg_reader.py#L172


__Case 2:__
```
with VideoFileClip(video_file) as v:
    with v.subclip(1,2) as s:
        pass
    for f in v.subclip(1,2).iter_frames():
        pass
```
Returns `AttributeError: FFMPEG_VideoReader instance has no attribute 'lastread'` as it tries reading the `lastread` frame, which got deleted.

__Case 3:__
```
with VideoFileClip(video_file) as v:
    with v.subclip(1,2) as s:
        pass
    for f in v.subclip(2,3).iter_frames():
        pass
```
Returns `AttributeError: 'NoneType' object has no attribute 'stdout'` as it tries reusing the reader by skipping forward through the unneeded frame here:
https://github.com/Zulko/moviepy/blob/master/moviepy/video/io/ffmpeg_reader.py#L176

__Correct behavior in my opinion:__
Verify with an open call to ffmpeg exists and recreate it if not


Changed files:
tests/test_issues.py, moviepy/video/io/ffmpeg_reader.py

diff --git a/moviepy/video/io/ffmpeg_reader.py b/moviepy/video/io/ffmpeg_reader.py
index 82e5cb1..0a26a88 100644
--- a/moviepy/video/io/ffmpeg_reader.py
+++ b/moviepy/video/io/ffmpeg_reader.py
@@ -166,10 +166,16 @@ class FFMPEG_VideoReader:
 
         pos = int(self.fps*t + 0.00001)+1
 
+        # Initialize proc if it is not open
+        if not self.proc:
+            self.initialize(t)
+            self.pos = pos
+            self.lastread = self.read_frame()
+
         if pos == self.pos:
             return self.lastread
         else:
-            if(pos < self.pos) or (pos > self.pos+100):
+            if (pos < self.pos) or (pos > self.pos + 100):
                 self.initialize(t)
                 self.pos = pos
             else:
diff --git a/tests/test_issues.py b/tests/test_issues.py
index 7296917..ebfb91e 100644
--- a/tests/test_issues.py
+++ b/tests/test_issues.py
@@ -285,7 +285,18 @@ def test_issue_636():
    with VideoFileClip("media/big_buck_bunny_0_30.webm").subclip(0,11) as video:
        with video.subclip(0,1) as subclip:
            pass
-      
+
+def test_issue_655():
+    video_file = 'media/fire2.mp4'
+    for subclip in [(0,2),(1,2),(2,3)]:
+        with VideoFileClip(video_file) as v:
+            with v.subclip(1,2) as s:
+                pass
+            next(v.subclip(*subclip).iter_frames())
+    assert True
+
+
+
 if __name__ == '__main__':
    pytest.main()
Repository: zulko/moviepy
Issue: read_chunk() breaks in numpy 1.12.0

In `audio.io.readers.FFMPEG_AudioReader`, the `read_chunk()` method breaks as of numpy 1.12.0 (released a few days ago). Numpy no longer accepts floats as index values, so the `result.reshape((len(result)/self.nchannels, self.nchannels))` call raises an exception. In practice, this means working with audio files is basically impossible with the latest numpy. Patch is trivial; PR coming in a moment.

Changed files:
moviepy/audio/io/readers.py

diff --git a/moviepy/audio/io/readers.py b/moviepy/audio/io/readers.py
index 86084c9..378c3c8 100644
--- a/moviepy/audio/io/readers.py
+++ b/moviepy/audio/io/readers.py
@@ -119,7 +119,7 @@ class FFMPEG_AudioReader:
         dt = {1: 'int8',2:'int16',4:'int32'}[self.nbytes]
         result = np.fromstring(s, dtype=dt)
         result = (1.0*result / 2**(8*self.nbytes-1)).\\
-                                 reshape((len(result)/self.nchannels,
+                                 reshape((int(len(result)/self.nchannels),
                                           self.nchannels))
         #self.proc.stdout.flush()
         self.pos = self.pos+chunksize
Repository: zulko/moviepy
Issue: Zombie processes after reader.close()

Hi,

When MoviePy finishes rendering I'm still left with a lot of zombie ffmpeg processes. (http://cl.ly/image/1X2h0o0J103K)

These don't use any resources, but there is a maximum nr of processes ofcourse. 
Is this bad? Can this be overcome?


Changed files:
moviepy/video/io/ffmpeg_reader.py

diff --git a/moviepy/video/io/ffmpeg_reader.py b/moviepy/video/io/ffmpeg_reader.py
index 70b098d..420eed1 100644
--- a/moviepy/video/io/ffmpeg_reader.py
+++ b/moviepy/video/io/ffmpeg_reader.py
@@ -169,6 +169,7 @@ class FFMPEG_VideoReader:
             self.proc.terminate()
             self.proc.stdout.close()
             self.proc.stderr.close()
+            self.proc.wait()
             del self.proc
 
     def __del__(self):
Repository: pre-commit/pre-commit
Issue: Windows: Large number of files causes `xargs: ... Bad file number`

Originally here: https://github.com/pre-commit/pre-commit-hooks/issues/41


Changed files:
tests/commands/run_test.py, pre_commit/languages/helpers.py

diff --git a/pre_commit/languages/helpers.py b/pre_commit/languages/helpers.py
index e854d18..ff46acc 100644
--- a/pre_commit/languages/helpers.py
+++ b/pre_commit/languages/helpers.py
@@ -10,7 +10,9 @@ def file_args_to_stdin(file_args):
 def run_hook(env, hook, file_args):
     quoted_args = [pipes.quote(arg) for arg in hook['args']]
     return env.run(
-        ' '.join(['xargs', '-0', hook['entry']] + quoted_args),
+        # Use -s 4000 (slightly less than posix mandated minimum)
+        # This is to prevent "xargs: ... Bad file number" on windows
+        ' '.join(['xargs', '-0', '-s4000', hook['entry']] + quoted_args),
         stdin=file_args_to_stdin(file_args),
         retcode=None,
     )
diff --git a/tests/commands/run_test.py b/tests/commands/run_test.py
index a245dfb..9cca610 100644
--- a/tests/commands/run_test.py
+++ b/tests/commands/run_test.py
@@ -305,3 +305,32 @@ def test_get_changed_files():
         '3387edbb1288a580b37fe25225aa0b856b18ad1a',
     )
     assert files == ['CHANGELOG.md', 'setup.py']
+
+
+def test_lots_of_files(mock_out_store_directory, tmpdir_factory):
+    # windows xargs seems to have a bug, here's a regression test for
+    # our workaround
+    git_path = make_consuming_repo(tmpdir_factory, 'python_hooks_repo')
+    with cwd(git_path):
+        # Override files so we run against them
+        with io.open(
+            '.pre-commit-config.yaml', 'a+',
+        ) as config_file:
+            config_file.write('        files: ""\\n')
+
+        # Write a crap ton of files
+        for i in range(400):
+            filename = '{0}{1}'.format('a' * 100, i)
+            open(filename, 'w').close()
+
+        cmd_output('bash', '-c', 'git add .')
+        install(Runner(git_path))
+
+        # Don't want to write to home directory
+        env = dict(os.environ, **{'PRE_COMMIT_HOME': tmpdir_factory.get()})
+        cmd_output(
+            'git', 'commit', '-m', 'Commit!',
+            # git commit puts pre-commit to stderr
+            stderr=subprocess.STDOUT,
+            env=env,
+        )
Repository: pre-commit/pre-commit
Issue: Cannot install ruby hooks on OS X

I can install pre-commit fine, but when it comes to running it for the first time, I get this error:

```
[INFO] Installing environment for git@***/pre-commit/mirrors-scss-lint.
[INFO] Once installed this environment will be reused.
[INFO] This may take a few minutes...
An unexpected error has occurred: CalledProcessError: Command: ['bash', '-c', '. /Users/markl/.pre-commit/repoLPZw60/rbenv-1.9.3-p484/bin/activate && cd /Users/markl/.pre-commit/repoLPZw60/ && gem build *.gemspec && gem install --no-document *.gem']
Return code: 1
Expected return code: 0
Output:
      Successfully built RubyGem
      Name: __fake_gem
      Version: 0.0.0
      File: __fake_gem-0.0.0.gem

Errors:
    WARNING:  no email specified
    WARNING:  no homepage specified
    WARNING:  description and summary are identical
    ERROR:  While executing gem ... (OptionParser::InvalidOption)
        invalid option: --no-document


Check the log at ~/.pre-commit/pre-commit.log
```

Environment details:
OS X 10.10.5
`gem --version`: 2.4.8
`ruby --version`: ruby 2.0.0p481 (2014-05-08 revision 45883) [universal.x86_64-darwin14]


Changed files:
pre_commit/languages/ruby.py

diff --git a/pre_commit/languages/ruby.py b/pre_commit/languages/ruby.py
index 7b018c1..0931a58 100644
--- a/pre_commit/languages/ruby.py
+++ b/pre_commit/languages/ruby.py
@@ -89,7 +89,7 @@ def install_environment(repo_cmd_runner, version='default'):
                 _install_ruby(ruby_env, version)
             ruby_env.run(
                 'cd {prefix} && gem build *.gemspec'
-                ' && gem install --no-document *.gem',
+                ' && gem install --no-ri --no-rdoc *.gem',
             )
Repository: pre-commit/pre-commit
Issue: Hooks not installed in the right hooks directory for worktrees

When on a git worktree, the hooks are not installed on the right hook dir:
```
❯ pre-commit install
pre-commit installed at /home/vampas/projects/SaltStack/console/raas/.git/worktrees/revan1/hooks/pre-commit
```
The hook does not run.

The hook only runs when I moved the `pre-commit` script to `/home/vampas/projects/SaltStack/console/raas/.git/hooks/pre-commit`

```
❯ pre-commit --version
pre-commit 1.10.4
```

Changed files:
tests/commands/install_uninstall_test.py, pre_commit/git.py

diff --git a/pre_commit/git.py b/pre_commit/git.py
index 4fb2e65..d9e01f5 100644
--- a/pre_commit/git.py
+++ b/pre_commit/git.py
@@ -31,10 +31,16 @@ def get_root():
 
 
 def get_git_dir(git_root):
-    return os.path.normpath(os.path.join(
-        git_root,
-        cmd_output('git', 'rev-parse', '--git-dir', cwd=git_root)[1].strip(),
-    ))
+    def _git_dir(opt):
+        return os.path.normpath(os.path.join(
+            git_root,
+            cmd_output('git', 'rev-parse', opt, cwd=git_root)[1].strip(),
+        ))
+
+    try:
+        return _git_dir('--git-common-dir')
+    except CalledProcessError:  # pragma: no cover (git < 2.5)
+        return _git_dir('--git-dir')
 
 
 def get_remote_url(git_root):
diff --git a/tests/commands/install_uninstall_test.py b/tests/commands/install_uninstall_test.py
index 7345cfb..e6f0e41 100644
--- a/tests/commands/install_uninstall_test.py
+++ b/tests/commands/install_uninstall_test.py
@@ -172,6 +172,19 @@ def test_install_in_submodule_and_run(tempdir_factory, store):
         assert NORMAL_PRE_COMMIT_RUN.match(output)
 
 
+def test_install_in_worktree_and_run(tempdir_factory, store):
+    src_path = make_consuming_repo(tempdir_factory, 'script_hooks_repo')
+    path = tempdir_factory.get()
+    cmd_output('git', '-C', src_path, 'branch', '-m', 'notmaster')
+    cmd_output('git', '-C', src_path, 'worktree', 'add', path, '-b', 'master')
+
+    with cwd(path):
+        assert install(Runner(path, C.CONFIG_FILE), store) == 0
+        ret, output = _get_commit_output(tempdir_factory)
+        assert ret == 0
+        assert NORMAL_PRE_COMMIT_RUN.match(output)
+
+
 def test_commit_am(tempdir_factory, store):
     """Regression test for #322."""
     path = make_consuming_repo(tempdir_factory, 'script_hooks_repo')
Repository: pre-commit/pre-commit
Issue: rust hook requires `--path` attribute

Cargo has changed how packages get installed and requires an extra `--path <destination>` attribute.

Symptom:
```
[INFO] Initializing environment for https://github.com/nix-community/nixpkgs-fmt.
[INFO] Installing environment for https://github.com/nix-community/nixpkgs-fmt.
[INFO] Once installed this environment will be reused.
[INFO] This may take a few minutes...
An unexpected error has occurred: CalledProcessError: Command: ('/nix/store/fcc3x8zwq1c0667xjs7bkn6ay8j4fdpz-rust-1.38.0-nightly-2019-08-07-ad7c55e1f/bin/cargo', 'install', '--bins', '--root', '/home/zimbatm/.cache/pre-commit/repoeft6xm6t/rustenv-default')
Return code: 101
Expected return code: 0
Output: (none)
Errors: 
    error: Using `cargo install` to install the binaries for the package in current working directory is no longer supported, use `cargo install --path .` instead. Use `cargo build` if you want to simply build the package.
```

I guess the fix should be done where here: https://github.com/pre-commit/pre-commit/blob/9c6a1d80d6b94c86a1785a40a51389e83accac3e/pre_commit/languages/rust.py#L87

Do we want to make pre-commit compatible with multiple versions of cargo or just the latest one?

/cc @asottile @chriskuehl 

Changed files:
pre_commit/languages/rust.py

diff --git a/pre_commit/languages/rust.py b/pre_commit/languages/rust.py
index e09d007..4b25a9d 100644
--- a/pre_commit/languages/rust.py
+++ b/pre_commit/languages/rust.py
@@ -73,7 +73,7 @@ def install_environment(prefix, version, additional_dependencies):
         _add_dependencies(prefix.path('Cargo.toml'), lib_deps)
 
     with clean_path_on_failure(directory):
-        packages_to_install = {()}
+        packages_to_install = {('--path', '.')}
         for cli_dep in cli_deps:
             cli_dep = cli_dep[len('cli:'):]
             package, _, version = cli_dep.partition(':')
Repository: pre-commit/pre-commit
Issue: Some versions of git don't create .git/hooks directory

Noticed here: https://github.com/victorlin/bugbuzz-python/pull/1#issuecomment-104971132


Changed files:
tests/commands/install_uninstall_test.py, pre_commit/commands/install_uninstall.py

diff --git a/pre_commit/commands/install_uninstall.py b/pre_commit/commands/install_uninstall.py
index c84d29b..47c9484 100644
--- a/pre_commit/commands/install_uninstall.py
+++ b/pre_commit/commands/install_uninstall.py
@@ -48,6 +48,9 @@ def install(runner, overwrite=False, hooks=False, hook_type='pre-commit'):
     hook_path = runner.get_hook_path(hook_type)
     legacy_path = hook_path + '.legacy'
 
+    if not os.path.exists(os.path.dirname(hook_path)):
+        os.makedirs(os.path.dirname(hook_path))
+
     # If we have an existing hook, move it to pre-commit.legacy
     if (
         os.path.exists(hook_path) and
diff --git a/tests/commands/install_uninstall_test.py b/tests/commands/install_uninstall_test.py
index 9e1806e..ca82c06 100644
--- a/tests/commands/install_uninstall_test.py
+++ b/tests/commands/install_uninstall_test.py
@@ -5,6 +5,7 @@ import io
 import os
 import os.path
 import re
+import shutil
 import subprocess
 import sys
 
@@ -78,6 +79,15 @@ def test_install_pre_commit(tmpdir_factory):
     assert pre_push_contents == expected_contents
 
 
+def test_install_hooks_directory_not_present(tmpdir_factory):
+    path = git_dir(tmpdir_factory)
+    # Simulate some git clients which don't make .git/hooks #234
+    shutil.rmtree(os.path.join(path, '.git', 'hooks'))
+    runner = Runner(path)
+    install(runner)
+    assert os.path.exists(runner.pre_commit_path)
+
+
 def test_uninstall_does_not_blow_up_when_not_there(tmpdir_factory):
     path = git_dir(tmpdir_factory)
     runner = Runner(path)
Repository: pre-commit/pre-commit
Issue: npmrc causes npm to install to home directory instead of nodeenv

Here is what happened when I tried to get eslint installed: 

```
$ pre-commit run --all-files
eslint..............................................................................................................................................................................................................................................................................................................Failed
hookid: eslint

xargs: eslint: No such file or directory
```

Moving .npmrc to nope.npmrc fixed the issue.


Changed files:
setup.py

diff --git a/setup.py b/setup.py
index cff71eb..62ea211 100644
--- a/setup.py
+++ b/setup.py
@@ -41,7 +41,7 @@ setup(
         'aspy.yaml',
         'cached-property',
         'jsonschema',
-        'nodeenv>=0.9.4',
+        'nodeenv>=0.11.1',
         'ordereddict',
         'plumbum',
         'pyyaml',
Repository: pre-commit/pre-commit
Issue: FileExistsError : [WinError 183] Cannot create a file when that file already exists

version : 1.15.2
OS : Windows 10

```console
$ pre-commit install

An unexpected error has occurred: FileExistsError: [WinError 183] Cannot create a file when that file already exists: '.git\\\\hooks\\\\pre-commit' -> '.git\\\\hooks\\\\pre-commit.legacy'
```

when i tried second times this was the error.

Changed files:
tests/commands/install_uninstall_test.py, pre_commit/commands/install_uninstall.py

diff --git a/pre_commit/commands/install_uninstall.py b/pre_commit/commands/install_uninstall.py
index 5f9f5c3..701afcc 100644
--- a/pre_commit/commands/install_uninstall.py
+++ b/pre_commit/commands/install_uninstall.py
@@ -5,6 +5,7 @@ import io
 import itertools
 import logging
 import os.path
+import shutil
 import sys
 
 from pre_commit import git
@@ -84,7 +85,7 @@ def install(
 
     # If we have an existing hook, move it to pre-commit.legacy
     if os.path.lexists(hook_path) and not is_our_script(hook_path):
-        os.rename(hook_path, legacy_path)
+        shutil.move(hook_path, legacy_path)
 
     # If we specify overwrite, we simply delete the legacy file
     if overwrite and os.path.exists(legacy_path):
diff --git a/tests/commands/install_uninstall_test.py b/tests/commands/install_uninstall_test.py
index e253dd4..3bb0a3e 100644
--- a/tests/commands/install_uninstall_test.py
+++ b/tests/commands/install_uninstall_test.py
@@ -325,6 +325,16 @@ def test_install_existing_hooks_no_overwrite(tempdir_factory, store):
         assert NORMAL_PRE_COMMIT_RUN.match(output[len('legacy hook\\n'):])
 
 
+def test_legacy_overwriting_legacy_hook(tempdir_factory, store):
+    path = make_consuming_repo(tempdir_factory, 'script_hooks_repo')
+    with cwd(path):
+        _write_legacy_hook(path)
+        assert install(C.CONFIG_FILE, store) == 0
+        _write_legacy_hook(path)
+        # this previously crashed on windows.  See #1010
+        assert install(C.CONFIG_FILE, store) == 0
+
+
 def test_install_existing_hook_no_overwrite_idempotent(tempdir_factory, store):
     path = make_consuming_repo(tempdir_factory, 'script_hooks_repo')
     with cwd(path):
Repository: pre-commit/pre-commit
Issue: `check-useless-excludes` meta hook doesn't seem to work well with broken symlinks

Repro steps
1. Add a submodule
2. Add a symlink to somewhere inside this submodule
3. Use `check-symlinks`
4. Deinit submodule (to simulate the case when people clone without `--recursive`)
4. Notice that it now complains about the symlink created on 2
5. Add an exclude entry with the path to that symlink
6. Use `check-useless-excludes`
7. Notice that it complains that the added exclude entry doesn't apply.

For a working example, check out https://github.com/pkoch/test-check-useless-excludes (without `--recursive`, or run `git submodule deinit --all`) and run `pre-commit run --all`.

Changed files:
tests/meta_hooks/check_useless_excludes_test.py, pre_commit/meta_hooks/check_useless_excludes.py

diff --git a/pre_commit/meta_hooks/check_useless_excludes.py b/pre_commit/meta_hooks/check_useless_excludes.py
index 12be03f..6116597 100644
--- a/pre_commit/meta_hooks/check_useless_excludes.py
+++ b/pre_commit/meta_hooks/check_useless_excludes.py
@@ -43,6 +43,9 @@ def check_useless_excludes(config_file: str) -> int:
 
     for repo in config['repos']:
         for hook in repo['hooks']:
+            # the default of manifest hooks is `types: [file]` but we may
+            # be configuring a symlink hook while there's a broken symlink
+            hook.setdefault('types', [])
             # Not actually a manifest dict, but this more accurately reflects
             # the defaults applied during runtime
             hook = apply_defaults(hook, MANIFEST_HOOK_DICT)
diff --git a/tests/meta_hooks/check_useless_excludes_test.py b/tests/meta_hooks/check_useless_excludes_test.py
index d261e81..703bd25 100644
--- a/tests/meta_hooks/check_useless_excludes_test.py
+++ b/tests/meta_hooks/check_useless_excludes_test.py
@@ -1,5 +1,10 @@
+from pre_commit import git
 from pre_commit.meta_hooks import check_useless_excludes
+from pre_commit.util import cmd_output
 from testing.fixtures import add_config_to_repo
+from testing.fixtures import make_config_from_repo
+from testing.fixtures import make_repo
+from testing.util import xfailif_windows
 
 
 def test_useless_exclude_global(capsys, in_git_dir):
@@ -113,3 +118,20 @@ def test_valid_exclude(capsys, in_git_dir):
 
     out, _ = capsys.readouterr()
     assert out == ''
+
+
+@xfailif_windows  # pragma: win32 no cover
+def test_useless_excludes_broken_symlink(capsys, in_git_dir, tempdir_factory):
+    path = make_repo(tempdir_factory, 'script_hooks_repo')
+    config = make_config_from_repo(path)
+    config['hooks'][0]['exclude'] = 'broken-symlink'
+    add_config_to_repo(in_git_dir.strpath, config)
+
+    in_git_dir.join('broken-symlink').mksymlinkto('DNE')
+    cmd_output('git', 'add', 'broken-symlink')
+    git.commit()
+
+    assert check_useless_excludes.main(('.pre-commit-config.yaml',)) == 0
+
+    out, _ = capsys.readouterr()
+    assert out == ''
Repository: pre-commit/pre-commit
Issue: Remove / deprecate expected_return_code

Since we rely heavily on xargs, this feature doesn't really work as expected.


Changed files:
tests/commands/run_test.py, pre_commit/commands/run.py, pre_commit/clientlib/validate_manifest.py, tests/manifest_test.py, tests/clientlib/validate_manifest_test.py

diff --git a/pre_commit/clientlib/validate_manifest.py b/pre_commit/clientlib/validate_manifest.py
index e5a6e0e..c08ce0b 100644
--- a/pre_commit/clientlib/validate_manifest.py
+++ b/pre_commit/clientlib/validate_manifest.py
@@ -24,7 +24,6 @@ MANIFEST_JSON_SCHEMA = {
             'language': {'type': 'string'},
             'language_version': {'type': 'string', 'default': 'default'},
             'files': {'type': 'string'},
-            'expected_return_value': {'type': 'number', 'default': 0},
             'stages': {
                 'type': 'array',
                 'default': [],
diff --git a/pre_commit/commands/run.py b/pre_commit/commands/run.py
index 067fbc0..95a9f90 100644
--- a/pre_commit/commands/run.py
+++ b/pre_commit/commands/run.py
@@ -87,7 +87,7 @@ def _run_single_hook(hook, repo, args, write, skips=frozenset()):
 
     retcode, stdout, stderr = repo.run_hook(hook, filenames)
 
-    if retcode != hook['expected_return_value']:
+    if retcode:
         retcode = 1
         print_color = color.RED
         pass_fail = 'Failed'
diff --git a/tests/clientlib/validate_manifest_test.py b/tests/clientlib/validate_manifest_test.py
index d847cab..4e51ade 100644
--- a/tests/clientlib/validate_manifest_test.py
+++ b/tests/clientlib/validate_manifest_test.py
@@ -77,7 +77,6 @@ def test_additional_manifest_failing(obj):
                 'language': 'python',
                 'language_version': 'python3.3',
                 'files': r'\\.py$',
-                'expected_return_value': 0,
             }],
             True,
         ),
diff --git a/tests/commands/run_test.py b/tests/commands/run_test.py
index be9223e..6b0d4b6 100644
--- a/tests/commands/run_test.py
+++ b/tests/commands/run_test.py
@@ -476,8 +476,7 @@ def test_local_hook_fails(
         ('hooks', [OrderedDict((
             ('id', 'no-todo'),
             ('name', 'No TODO'),
-            ('entry', 'grep -iI todo'),
-            ('expected_return_value', 1),
+            ('entry', 'sh -c "! grep -iI todo $@" --'),
             ('language', 'system'),
             ('files', ''),
         ))])
diff --git a/tests/manifest_test.py b/tests/manifest_test.py
index 7e09f33..ce1beed 100644
--- a/tests/manifest_test.py
+++ b/tests/manifest_test.py
@@ -23,7 +23,6 @@ def test_manifest_contents(manifest):
         'description': '',
         'entry': 'bin/hook.sh',
         'exclude': '^$',
-        'expected_return_value': 0,
         'files': '',
         'id': 'bash_hook',
         'language': 'script',
@@ -39,7 +38,6 @@ def test_hooks(manifest):
         'description': '',
         'entry': 'bin/hook.sh',
         'exclude': '^$',
-        'expected_return_value': 0,
         'files': '',
         'id': 'bash_hook',
         'language': 'script',
Repository: pre-commit/pre-commit
Issue: Flask style test failing health check in CI

Flask's style test in GitHub actions runs `tox -e style`, which runs `pre-commit run --all-files --show-diff-on-failure`, which is failing with "An unexpected error has occurred: AssertionError: BUG: expected environment for python to be healthy() immediately after install, please open an issue describing your environment".

Note, this does not reproduce locally.

AFAIK, this first appeared in pallets/flask#3739.

We're trying to debug this over in pallets/flask#3740 where I've temporarily added a `cat .../pre-commit.log` command. Output here: https://github.com/pallets/flask/pull/3740/checks?check_run_id=1018335736#step:9:14

Neither the error message nor the log actually say what specifically about the environment is unhealthy.
 
Any ideas?

Thanks!

Changed files:
tests/languages/python_test.py, pre_commit/languages/python.py

diff --git a/pre_commit/languages/python.py b/pre_commit/languages/python.py
index 6f7c900..7a68580 100644
--- a/pre_commit/languages/python.py
+++ b/pre_commit/languages/python.py
@@ -191,7 +191,8 @@ def healthy(prefix: Prefix, language_version: str) -> bool:
 
     return (
         'version_info' in cfg and
-        _version_info(py_exe) == cfg['version_info'] and (
+        # always use uncached lookup here in case we replaced an unhealthy env
+        _version_info.__wrapped__(py_exe) == cfg['version_info'] and (
             'base-executable' not in cfg or
             _version_info(cfg['base-executable']) == cfg['version_info']
         )
diff --git a/tests/languages/python_test.py b/tests/languages/python_test.py
index c419ad6..29c5a9b 100644
--- a/tests/languages/python_test.py
+++ b/tests/languages/python_test.py
@@ -8,6 +8,7 @@ import pre_commit.constants as C
 from pre_commit.envcontext import envcontext
 from pre_commit.languages import python
 from pre_commit.prefix import Prefix
+from pre_commit.util import make_executable
 
 
 def test_read_pyvenv_cfg(tmpdir):
@@ -141,3 +142,26 @@ def test_unhealthy_old_virtualenv(python_dir):
     os.remove(prefix.path('py_env-default/pyvenv.cfg'))
 
     assert python.healthy(prefix, C.DEFAULT) is False
+
+
+def test_unhealthy_then_replaced(python_dir):
+    prefix, tmpdir = python_dir
+
+    python.install_environment(prefix, C.DEFAULT, ())
+
+    # simulate an exe which returns an old version
+    exe_name = 'python.exe' if sys.platform == 'win32' else 'python'
+    py_exe = prefix.path(python.bin_dir('py_env-default'), exe_name)
+    os.rename(py_exe, f'{py_exe}.tmp')
+
+    with open(py_exe, 'w') as f:
+        f.write('#!/usr/bin/env bash\\necho 1.2.3\\n')
+    make_executable(py_exe)
+
+    # should be unhealthy due to version mismatch
+    assert python.healthy(prefix, C.DEFAULT) is False
+
+    # now put the exe back and it should be healthy again
+    os.replace(f'{py_exe}.tmp', py_exe)
+
+    assert python.healthy(prefix, C.DEFAULT) is True
Repository: pre-commit/pre-commit
Issue: Rbenv default ruby issue on install

I am trying to install MDL v0.11.0

i get the following error during install 
```
pre-commit
[INFO] Installing environment for git://github.com/markdownlint/markdownlint.
[INFO] Once installed this environment will be reused.
[INFO] This may take a few minutes...
An unexpected error has occurred: CalledProcessError: command: ('/usr/local/bin/bash', '/Users/abuxton/.rbenv/shims/gem', 'build', 'mdl.gemspec')
return code: 1
expected return code: 0
stdout: (none)
stderr:
    rbenv: version `default' is not installed (set by RBENV_VERSION environment variable)
```

seems to be the same issue as https://github.com/pre-commit/pre-commit/issues/369 on a previous version of pre-commit
pre-commit.log https://gist.github.com/abuxton/d29e6265f3230f838a746d7a5defd5e3 

i have tried, ensuring local rbenv, I have tried pre-commit clean/uninstall and reinstall to no success, mdl will `brew install mdl` successfully and works fine. 


Changed files:
pre_commit/languages/ruby.py

diff --git a/pre_commit/languages/ruby.py b/pre_commit/languages/ruby.py
index 1a0f0c7..81bc954 100644
--- a/pre_commit/languages/ruby.py
+++ b/pre_commit/languages/ruby.py
@@ -52,7 +52,6 @@ def get_env_patch(
     else:  # pragma: win32 no cover
         patches += (
             ('RBENV_ROOT', venv),
-            ('RBENV_VERSION', language_version),
             (
                 'PATH', (
                     os.path.join(venv, 'gems', 'bin'), os.pathsep,
@@ -61,6 +60,9 @@ def get_env_patch(
                 ),
             ),
         )
+    if language_version not in {'system', 'default'}:  # pragma: win32 no cover
+        patches += (('RBENV_VERSION', language_version),)
+
     return patches
Repository: pre-commit/pre-commit
Issue: Ruby hooks failing with rbenv installed

Pre-commit has been failing for the past few weeks.

https://gist.github.com/ThatGerber/d6533155848076b25e5e0d5cb02e20eb

Seems to be an issue with the ruby (rbenv) environment.

Tried running `pre-commit clean && pre-commit` but it returns the same issue. Setting `rbenv global 2.2.4` and `rbenv shell 2.2.4` does help either.


Changed files:
pre_commit/languages/ruby.py

diff --git a/pre_commit/languages/ruby.py b/pre_commit/languages/ruby.py
index dc320b3..28ad377 100644
--- a/pre_commit/languages/ruby.py
+++ b/pre_commit/languages/ruby.py
@@ -19,16 +19,18 @@ ENVIRONMENT_DIR = 'rbenv'
 
 
 def get_env_patch(venv, language_version):
-    return (
+    patches = (
         ('GEM_HOME', os.path.join(venv, 'gems')),
         ('RBENV_ROOT', venv),
-        ('RBENV_VERSION', language_version),
         ('PATH', (
             os.path.join(venv, 'gems', 'bin'), os.pathsep,
             os.path.join(venv, 'shims'), os.pathsep,
             os.path.join(venv, 'bin'), os.pathsep, Var('PATH'),
         )),
     )
+    if language_version != 'default':
+        patches += (('RBENV_VERSION', language_version),)
+    return patches
 
 
 @contextlib.contextmanager
Repository: pre-commit/pre-commit
Issue: cspell hook install fails due pre-commit assumptions regarding npm packages

I am raising this bug here as cspell is still unusable as a pre-commit hook even after the author made additional changes and I am afraid that the root cause is no longer inside cspell package.

Mainly cspell is a typescript project that is published on npm and you cannot run it without building it first. Apparently pre-commit does not know about this concenpt (or I am not aware about it).'

More information can be found on https://github.com/Jason3S/cspell/issues/53#issuecomment-402562237

To enabled cspell hook it should be enough to add this:
```
  - repo: https://github.com/Jason3S/cspell.git
    rev: v3.2.2
    hooks:
      - id: cspell
```

Still, once you run pre-precommit you soon endup with something like:
```
cspell...................................................................Failed
hookid: cspell

internal/modules/cjs/loader.js:611
    throw err;
    ^

Error: Cannot find module './dist/app'
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:609:15)
    at Function.Module._load (internal/modules/cjs/loader.js:535:25)
    at Module.require (internal/modules/cjs/loader.js:663:17)
    at require (internal/modules/cjs/helpers.js:20:18)
    at Object.<anonymous> (/Users/ssbarnea/.cache/pre-commit/repolvipoC/bin.js:5:1)
    at Module._compile (internal/modules/cjs/loader.js:734:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:745:10)
    at Module.load (internal/modules/cjs/loader.js:626:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:566:12)
    at Function.Module._load (internal/modules/cjs/loader.js:558:3)
internal/modules/cjs/loader.js:611
    throw err;
    ^
```

The maintainer of cspell mentioned that the project was not designed to run from source, and the expected behavior is to install the npm package. I have to say that I kinda agree with his view.

How can we address this issue? 

Changed files:
pre_commit/languages/node.py

diff --git a/pre_commit/languages/node.py b/pre_commit/languages/node.py
index b313bf5..e7962cc 100644
--- a/pre_commit/languages/node.py
+++ b/pre_commit/languages/node.py
@@ -62,10 +62,11 @@ def install_environment(prefix, version, additional_dependencies):
             cmd.extend(['-n', version])
         cmd_output(*cmd)
 
+        dep = 'git+file:///{}'.format(prefix.prefix_dir)
         with in_env(prefix, version):
             helpers.run_setup_cmd(
                 prefix,
-                ('npm', 'install', '-g', '.') + additional_dependencies,
+                ('npm', 'install', '-g', dep) + additional_dependencies,
             )
Repository: pre-commit/pre-commit
Issue: Encode some sort of "version" for language-local repositories

Without this, they'll never get upgraded if fixes are made in the pre-commit empty template

Changed files:
pre_commit/constants.py, pre_commit/store.py

diff --git a/pre_commit/constants.py b/pre_commit/constants.py
index 387bcd6..3f81c80 100644
--- a/pre_commit/constants.py
+++ b/pre_commit/constants.py
@@ -17,6 +17,8 @@ YAML_DUMP_KWARGS = {
 
 # Bump when installation changes in a backwards / forwards incompatible way
 INSTALLED_STATE_VERSION = '1'
+# Bump when modifying `empty_template`
+LOCAL_REPO_VERSION = '1'
 
 VERSION = pkg_resources.get_distribution('pre-commit').version
 VERSION_PARSED = pkg_resources.parse_version(VERSION)
diff --git a/pre_commit/store.py b/pre_commit/store.py
index 3f24d0b..6756448 100644
--- a/pre_commit/store.py
+++ b/pre_commit/store.py
@@ -9,6 +9,7 @@ import tempfile
 
 from cached_property import cached_property
 
+import pre_commit.constants as C
 from pre_commit.prefixed_command_runner import PrefixedCommandRunner
 from pre_commit.util import clean_path_on_failure
 from pre_commit.util import cmd_output
@@ -129,7 +130,7 @@ class Store(object):
         def make_local_strategy(directory):
             copy_tree_to_path(resource_filename('empty_template'), directory)
         return self._new_repo(
-            'local:{}'.format(','.join(sorted(deps))), 'N/A',
+            'local:{}'.format(','.join(sorted(deps))), C.LOCAL_REPO_VERSION,
             make_local_strategy,
         )
Repository: pre-commit/pre-commit
Issue: always_run + no `files` still crashes on `KeyError: files`

I was under the impression `files` was completely ignored for `always_run`, I guess not!

Here's a small reproduction:

```yaml
-   repo: local
    hooks:
    -   id: foo
        name: foo
        always_run: true
        entry: bash -c 'echo hello && exit 1'
        language: system
```

```
$ ./venv-pre_commit/bin/pre-commit run foo
An unexpected error has occurred: KeyError: u'files'
Check the log at ~/.pre-commit/pre-commit.log
```

```
$ cat ~/.pre-commit/pre-commit.log 
An unexpected error has occurred: KeyError: u'files'
Traceback (most recent call last):
  File "/tmp/foo/pre-commit/pre_commit/error_handler.py", line 48, in error_handler
    yield
  File "/tmp/foo/pre-commit/pre_commit/main.py", line 226, in main
    return run(runner, args)
  File "/tmp/foo/pre-commit/pre_commit/commands/run.py", line 235, in run
    return _run_hooks(repo_hooks, args, environ)
  File "/tmp/foo/pre-commit/pre_commit/commands/run.py", line 155, in _run_hooks
    retval |= _run_single_hook(hook, repo, args, skips, cols)
  File "/tmp/foo/pre-commit/pre_commit/commands/run.py", line 60, in _run_single_hook
    filenames = get_filenames(args, hook['files'], hook['exclude'])
KeyError: u'files'
```


Changed files:
pre_commit/commands/run.py

diff --git a/pre_commit/commands/run.py b/pre_commit/commands/run.py
index 3039b66..9ce71d8 100644
--- a/pre_commit/commands/run.py
+++ b/pre_commit/commands/run.py
@@ -57,7 +57,7 @@ NO_FILES = '(no files to check)'
 
 
 def _run_single_hook(hook, repo, args, skips, cols):
-    filenames = get_filenames(args, hook['files'], hook['exclude'])
+    filenames = get_filenames(args, hook.get('files', ''), hook['exclude'])
     if hook['id'] in skips:
         output.write(get_hook_message(
             _hook_msg_start(hook, args.verbose),
Repository: pre-commit/pre-commit
Issue: nodeenv try to download non existing tar.gz prebuilt under Cygwin

Hi,

Strange issue: I suspect a recent change broke this as it used to work last week, on another Windows computer with Cygwin.

Bug reproduction: `pre-commit run` using e.g. https://github.com/Lucas-C/pre-commit-hooks-html v1.1.0

`pre-commit` execute the following command under the hood, a command that also fails if I execute it manually:
```
nodeenv --prebuilt /cygdrive/c/Users/admin/.pre-commit/repoYHJ85q/node_env-default
```
The error is the following:
```
urllib2.HTTPError: HTTP Error 404: Not Found
```
The `tar.gz` it tries to install is https://nodejs.org/dist/v7.2.1/node-v7.2.1-cygwin_nt-6.1-x64.tar.gz, which does not exist. My guess is that `nodeenv` should use the Windows prebuilts instead: https://nodejs.org/dist/v7.2.1/node-v7.2.1-win-x64.zip This is because `platform.system()` is used: https://github.com/ekalinin/nodeenv/blob/master/nodeenv.py#L503

I'm going to ask for help on the https://github.com/ekalinin/nodeenv project, but do you have any hint at what the root cause could be here ?

Changed files:
pre_commit/languages/node.py

diff --git a/pre_commit/languages/node.py b/pre_commit/languages/node.py
index 69378b0..5892267 100644
--- a/pre_commit/languages/node.py
+++ b/pre_commit/languages/node.py
@@ -17,10 +17,11 @@ healthy = helpers.basic_healthy
 
 
 def get_env_patch(venv):  # pragma: windows no cover
+    config = os.path.join(venv, 'bin') if sys.platform == 'cygwin' else venv
     return (
         ('NODE_VIRTUAL_ENV', venv),
-        ('NPM_CONFIG_PREFIX', venv),
-        ('npm_config_prefix', venv),
+        ('NPM_CONFIG_PREFIX', config),
+        ('npm_config_prefix', config),
         ('NODE_PATH', os.path.join(venv, 'lib', 'node_modules')),
         ('PATH', (os.path.join(venv, 'bin'), os.pathsep, Var('PATH'))),
     )
Repository: pre-commit/pre-commit
Issue: commit-msg stage does not work

Everything works as expected when running just `pre-commit install`, then hooks work.
But when running `pre-commit install -t commit-msg` `IOError` happens, since template could not be found.

Here's the detailed information.

## Env

- `python2.7`
- `pipenv 7.3.7`
- `pre-commit 1.1.1`

Actually tested with both `python2` and `python3`.

## Configuration

```yaml
- repo: local
  hooks:
    - id: gitlint
      name: gitlint
      entry: "bash -c 'gitlint lint'"
      language: system
      stages: [commit-msg]

    - id: pytest
      name: pytest
      entry: "bash -c 'python manage.py test'"
      language: system

    - id: safety
      name: safety
      entry: "bash -c 'safety check'"
      language: system
```

## Output

```
» pre-commit install -t commit-msg
Running in migration mode with existing hooks at /Users/sobolev/Desktop/test/.git/hooks/commit-msg.legacy
Use -f to use only pre-commit.
An unexpected error has occurred: IOError: [Errno 2] No such file or directory: '/Users/sobolev/.virtualenvs/test-p4WySO70/lib/python2.7/site-packages/pre_commit/resources/commit-msg-tmpl'
Check the log at /Users/sobolev/.cache/pre-commit/pre-commit.log
```

When I do `ls /Users/sobolev/.virtualenvs/test-p4WySO70/lib/python2.7/site-packages/pre_commit/resources/commit-msg-tmpl`  that's what is see:

```
(test-p4WySO70) ~/Desktop/test  master ✗                                  ✚ 2 ⚡
» ls /Users/sobolev/.virtualenvs/test-p4WySO70/lib/python2.7/site-packages/pre_commit/resources                
empty_template  pre-push-tmpl  ruby-build.tar.gz
hook-tmpl       rbenv.tar.gz   ruby-download.tar.gz
```

Changed files:
setup.py

diff --git a/setup.py b/setup.py
index a2cd138..55116ca 100644
--- a/setup.py
+++ b/setup.py
@@ -29,11 +29,7 @@ setup(
     packages=find_packages(exclude=('tests*', 'testing*')),
     package_data={
         'pre_commit': [
-            'resources/hook-tmpl',
-            'resources/pre-push-tmpl',
-            'resources/rbenv.tar.gz',
-            'resources/ruby-build.tar.gz',
-            'resources/ruby-download.tar.gz',
+            'resources/*',
             'resources/empty_template/*',
             'resources/empty_template/.npmignore',
         ],
Repository: pre-commit/pre-commit
Issue: Running `pre-commit` 1.20.0 on Guix gives server certificate verification failed. CAfile: none CRLfile: none

Running `pre-commit` 1.20.0 on Guix gives

```
An unexpected error has occurred: CalledProcessError: Command: ('/home/igankevich/.guix-profile/bin/git', 'fetch', 'origin', '--tags')
Return code: 128
Expected return code: 0
Output: (none)
Errors:
    fatal: unable to access 'https://github.com/pre-commit/pre-commit-hooks/': server certificate verification failed. CAfile: none CRLfile: none

Traceback (most recent call last):
  File "/gnu/store/35ppc0zpffbzc6zsw9xnks1hxmr7wh19-python-pre-commit-1.20.0/lib/python3.7/site-packages/pre_commit/store.py", line 168, in clone_strategy
    self._shallow_clone(ref, _git_cmd)
  File "/gnu/store/35ppc0zpffbzc6zsw9xnks1hxmr7wh19-python-pre-commit-1.20.0/lib/python3.7/site-packages/pre_commit/store.py", line 150, in _shallow_clone
    git_cmd('-c', git_config, 'fetch', 'origin', ref, '--depth=1')
  File "/gnu/store/35ppc0zpffbzc6zsw9xnks1hxmr7wh19-python-pre-commit-1.20.0/lib/python3.7/site-packages/pre_commit/store.py", line 165, in _git_cmd
    cmd_output_b('git', *args, cwd=directory, env=env)
  File "/gnu/store/35ppc0zpffbzc6zsw9xnks1hxmr7wh19-python-pre-commit-1.20.0/lib/python3.7/site-packages/pre_commit/util.py", line 147, in cmd_output_b
    returncode, cmd, retcode, output=(stdout_b, stderr_b),
pre_commit.util.CalledProcessError: Command: ('/home/igankevich/.guix-profile/bin/git', '-c', 'protocol.version=2', 'fetch', 'origin', 'v2.4.0', '--depth=1')
Return code: 128
Expected return code: 0
Output: (none)
Errors:
    fatal: unable to access 'https://github.com/pre-commit/pre-commit-hooks/': server certificate verification failed. CAfile: none CRLfile: none
```

It looks like pre-commit sanitises GIT_SSL_CAINFO environment variable. Guix uses this variable to specify the path to the certificates. I fixed this bug by _whitelisting_ GIT_SSL_CAINFO in `no_git_env` in `pre_commit/git.py`.

Changed files:
pre_commit/git.py

diff --git a/pre_commit/git.py b/pre_commit/git.py
index 3ee9ca3..c8faf60 100644
--- a/pre_commit/git.py
+++ b/pre_commit/git.py
@@ -32,7 +32,7 @@ def no_git_env(_env=None):
     return {
         k: v for k, v in _env.items()
         if not k.startswith('GIT_') or
-        k in {'GIT_EXEC_PATH', 'GIT_SSH', 'GIT_SSH_COMMAND'}
+        k in {'GIT_EXEC_PATH', 'GIT_SSH', 'GIT_SSH_COMMAND', 'GIT_SSL_CAINFO'}
     }
Repository: pre-commit/pre-commit
Issue: Uh oh, whoops, `pre-commit autoupdate --repo foo` only leaves foo

My bad 🤦‍♂️  

So it's supposed to leave everything else 'as is' and just update repo foo.

Whereas now it deletes all the other repos in the `.pre-commit-config.yaml`, and leaves the updated foo.

Changed files:
pre_commit/commands/autoupdate.py, tests/commands/autoupdate_test.py

diff --git a/pre_commit/commands/autoupdate.py b/pre_commit/commands/autoupdate.py
index ca8f9bb..5ba5a8e 100644
--- a/pre_commit/commands/autoupdate.py
+++ b/pre_commit/commands/autoupdate.py
@@ -116,11 +116,12 @@ def autoupdate(runner, tags_only, repo=None):
     input_config = load_config(runner.config_file_path)
 
     for repo_config in input_config['repos']:
-        # Skip any repo_configs that aren't the specified repo
-        if repo and repo != repo_config['repo']:
-            continue
-
-        if is_local_repo(repo_config) or is_meta_repo(repo_config):
+        if (
+            is_local_repo(repo_config) or
+            is_meta_repo(repo_config) or
+            # Skip updating any repo_configs that aren't for the specified repo
+            repo and repo != repo_config['repo']
+        ):
             output_repos.append(repo_config)
             continue
         output.write('Updating {}...'.format(repo_config['repo']))
diff --git a/tests/commands/autoupdate_test.py b/tests/commands/autoupdate_test.py
index c78af1f..ee20c7d 100644
--- a/tests/commands/autoupdate_test.py
+++ b/tests/commands/autoupdate_test.py
@@ -127,10 +127,12 @@ def test_autoupdate_out_of_date_repo(
 def test_autoupdate_out_of_date_repo_with_correct_repo_name(
         out_of_date_repo, in_tmpdir, mock_out_store_directory,
 ):
-    # Write out the config
-    config = make_config_from_repo(
+    stale_config = make_config_from_repo(
         out_of_date_repo.path, sha=out_of_date_repo.original_sha, check=False,
     )
+    local_config = config_with_local_hooks()
+    config = {'repos': [stale_config, local_config]}
+    # Write out the config
     write_config('.', config)
 
     runner = Runner('.', C.CONFIG_FILE)
@@ -141,6 +143,7 @@ def test_autoupdate_out_of_date_repo_with_correct_repo_name(
     assert ret == 0
     assert before != after
     assert out_of_date_repo.head_sha in after
+    assert local_config['repo'] in after
 
 
 def test_autoupdate_out_of_date_repo_with_wrong_repo_name(
Repository: pre-commit/pre-commit
Issue: pre-commit autoupdate fails when config is empty

Running `pre-commit autoupdate` with an empty `.pre-commit-config.yaml` results in the below error:
```An unexpected error has occurred: IndexError: list index out of range
Traceback (most recent call last):
  File "/usr/local/Cellar/pre-commit/1.14.2/libexec/lib/python3.7/site-packages/pre_commit/error_handler.py", line 46, in error_handler
    yield
  File "/usr/local/Cellar/pre-commit/1.14.2/libexec/lib/python3.7/site-packages/pre_commit/main.py", line 286, in main
    repos=args.repos,
  File "/usr/local/Cellar/pre-commit/1.14.2/libexec/lib/python3.7/site-packages/pre_commit/commands/autoupdate.py", line 117, in autoupdate
    migrate_config(config_file, quiet=True)
  File "/usr/local/Cellar/pre-commit/1.14.2/libexec/lib/python3.7/site-packages/pre_commit/commands/migrate_config.py", line 52, in migrate_config
    contents = _migrate_map(contents)
  File "/usr/local/Cellar/pre-commit/1.14.2/libexec/lib/python3.7/site-packages/pre_commit/commands/migrate_config.py", line 24, in _migrate_map
    while _is_header_line(lines[i]):
IndexError: list index out of range
```

Changed files:
tests/commands/migrate_config_test.py, pre_commit/commands/migrate_config.py

diff --git a/pre_commit/commands/migrate_config.py b/pre_commit/commands/migrate_config.py
index 3f73bb8..bac4231 100644
--- a/pre_commit/commands/migrate_config.py
+++ b/pre_commit/commands/migrate_config.py
@@ -21,7 +21,8 @@ def _migrate_map(contents):
     # Find the first non-header line
     lines = contents.splitlines(True)
     i = 0
-    while _is_header_line(lines[i]):
+    # Only loop on non empty configuration file
+    while i < len(lines) and _is_header_line(lines[i]):
         i += 1
 
     header = ''.join(lines[:i])
diff --git a/tests/commands/migrate_config_test.py b/tests/commands/migrate_config_test.py
index 8f9153f..c58b9f7 100644
--- a/tests/commands/migrate_config_test.py
+++ b/tests/commands/migrate_config_test.py
@@ -147,3 +147,13 @@ def test_migrate_config_sha_to_rev(tmpdir):
         '    rev: v1.2.0\\n'
         '    hooks: []\\n'
     )
+
+
+@pytest.mark.parametrize('contents', ('', '\\n'))
+def test_empty_configuration_file_user_error(tmpdir, contents):
+    cfg = tmpdir.join(C.CONFIG_FILE)
+    cfg.write(contents)
+    with tmpdir.as_cwd():
+        assert not migrate_config(C.CONFIG_FILE)
+    # even though the config is invalid, this should be a noop
+    assert cfg.read() == contents