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): mkdirp(os.path.join(path, '.git/hooks')) with io.open(os.path.join(path, '.git/hooks/pre-push'), 'w') as f: f.write( '#!/usr/bin/env bash\n' 'set -eu\n' 'read lr ls rr rs\n' 'test -n "$lr" -a -n "$ls" -a -n "$rr" -a -n "$rs"\n' 'echo legacy\n', ) make_executable(f.name) install(C.CONFIG_FILE, store, hook_type='pre-push') assert _get_commit_output(tempdir_factory)[0] == 0 retc, output = _get_push_output(tempdir_factory) assert retc == 0 first_line, _, third_line = output.splitlines()[:3] assert first_line == 'legacy' assert third_line.startswith('Bash hook') assert third_line.endswith('Passed')
def test_prepare_commit_msg_legacy( prepare_commit_msg_repo, tempdir_factory, store, ): hook_path = os.path.join( prepare_commit_msg_repo, '.git/hooks/prepare-commit-msg', ) mkdirp(os.path.dirname(hook_path)) with io.open(hook_path, 'w') as hook_file: hook_file.write( '#!/usr/bin/env bash\n' 'set -eu\n' 'test -e "$1"\n' 'echo legacy\n', ) make_executable(hook_path) install(C.CONFIG_FILE, store, hook_type='prepare-commit-msg') msg = 'Hi' retc, out = _get_commit_output(tempdir_factory, msg=msg) assert retc == 0 first_line, second_line = out.splitlines()[:2] assert first_line == 'legacy' assert second_line.startswith('Add "Signed off by:"...') commit_msg_path = os.path.join( prepare_commit_msg_repo, '.git/COMMIT_EDITMSG', ) with io.open(commit_msg_path) as f: assert 'Signed off by: ' in f.read()
def install( config_file, store, overwrite=False, hooks=False, hook_type='pre-commit', skip_on_missing_conf=False, ): """Install the pre-commit hooks.""" if cmd_output('git', 'config', 'core.hooksPath', retcode=None)[1].strip(): logger.error( 'Cowardly refusing to install hooks with `core.hooksPath` set.\n' 'hint: `git config --unset-all core.hooksPath`', ) return 1 hook_path, legacy_path = _hook_paths(hook_type) mkdirp(os.path.dirname(hook_path)) # 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): shutil.move(hook_path, legacy_path) # If we specify overwrite, we simply delete the legacy file if overwrite and os.path.exists(legacy_path): os.remove(legacy_path) elif os.path.exists(legacy_path): output.write_line( 'Running in migration mode with existing hooks at {}\n' 'Use -f to use only pre-commit.'.format(legacy_path), ) params = { 'CONFIG': config_file, 'HOOK_TYPE': hook_type, 'INSTALL_PYTHON': sys.executable, 'SKIP_ON_MISSING_CONFIG': skip_on_missing_conf, } with io.open(hook_path, 'w') as hook_file: contents = resource_text('hook-tmpl') before, rest = contents.split(TEMPLATE_START) to_template, after = rest.split(TEMPLATE_END) before = before.replace('#!/usr/bin/env python3', shebang()) hook_file.write(before + TEMPLATE_START) for line in to_template.splitlines(): var = line.split()[0] hook_file.write('{} = {!r}\n'.format(var, params[var])) hook_file.write(TEMPLATE_END + after) make_executable(hook_path) output.write_line('pre-commit installed at {}'.format(hook_path)) # If they requested we install all of the hooks, do so. if hooks: install_hooks(config_file, store) return 0
def test_install_hooks_dead_symlink( tempdir_factory, ): # pragma: no cover (non-windows) path = git_dir(tempdir_factory) runner = Runner(path, C.CONFIG_FILE) mkdirp(os.path.dirname(runner.pre_commit_path)) os.symlink('/fake/baz', os.path.join(path, '.git', 'hooks', 'pre-commit')) install(runner) assert os.path.exists(runner.pre_commit_path)
def test_install_hooks_dead_symlink( tempdir_factory, ): # pragma: no cover (non-windows) path = git_dir(tempdir_factory) runner = Runner(path) mkdirp(os.path.dirname(runner.pre_commit_path)) os.symlink('/fake/baz', os.path.join(path, '.git', 'hooks', 'pre-commit')) install(runner) assert os.path.exists(runner.pre_commit_path)
def install( runner, overwrite=False, hooks=False, hook_type='pre-commit', skip_on_missing_conf=False, ): """Install the pre-commit hooks.""" hook_path = runner.get_hook_path(hook_type) legacy_path = hook_path + '.legacy' mkdirp(os.path.dirname(hook_path)) # 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) # If we specify overwrite, we simply delete the legacy file if overwrite and os.path.exists(legacy_path): os.remove(legacy_path) elif os.path.exists(legacy_path): output.write_line( 'Running in migration mode with existing hooks at {}\n' 'Use -f to use only pre-commit.'.format( legacy_path, ), ) with io.open(hook_path, 'w') as pre_commit_file_obj: if hook_type == 'pre-push': with io.open(resource_filename('pre-push-tmpl')) as f: hook_specific_contents = f.read() elif hook_type == 'commit-msg': with io.open(resource_filename('commit-msg-tmpl')) as f: hook_specific_contents = f.read() elif hook_type == 'pre-commit': hook_specific_contents = '' else: raise AssertionError('Unknown hook type: {}'.format(hook_type)) skip_on_missing_conf = 'true' if skip_on_missing_conf else 'false' contents = io.open(resource_filename('hook-tmpl')).read().format( sys_executable=pipes.quote(sys.executable), hook_type=hook_type, hook_specific=hook_specific_contents, config_file=runner.config_file, skip_on_missing_conf=skip_on_missing_conf, ) pre_commit_file_obj.write(contents) make_executable(hook_path) output.write_line('pre-commit installed at {}'.format(hook_path)) # If they requested we install all of the hooks, do so. if hooks: install_hooks(runner) return 0
def install( runner, overwrite=False, hooks=False, hook_type='pre-commit', skip_on_missing_conf=False, ): """Install the pre-commit hooks.""" hook_path = runner.get_hook_path(hook_type) legacy_path = hook_path + '.legacy' mkdirp(os.path.dirname(hook_path)) # 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) # If we specify overwrite, we simply delete the legacy file if overwrite and os.path.exists(legacy_path): os.remove(legacy_path) elif os.path.exists(legacy_path): output.write_line( 'Running in migration mode with existing hooks at {}\n' 'Use -f to use only pre-commit.'.format(legacy_path, ), ) with io.open(hook_path, 'w') as pre_commit_file_obj: if hook_type == 'pre-push': with io.open(resource_filename('pre-push-tmpl')) as f: hook_specific_contents = f.read() elif hook_type == 'commit-msg': with io.open(resource_filename('commit-msg-tmpl')) as f: hook_specific_contents = f.read() elif hook_type == 'pre-commit': hook_specific_contents = '' else: raise AssertionError('Unknown hook type: {}'.format(hook_type)) skip_on_missing_conf = 'true' if skip_on_missing_conf else 'false' contents = io.open(resource_filename('hook-tmpl')).read().format( sys_executable=sys.executable, hook_type=hook_type, hook_specific=hook_specific_contents, skip_on_missing_conf=skip_on_missing_conf, ) pre_commit_file_obj.write(contents) make_executable(hook_path) output.write_line('pre-commit installed at {}'.format(hook_path)) # If they requested we install all of the hooks, do so. if hooks: install_hooks(runner) return 0
def test_uninstall_doesnt_remove_not_our_hooks(tempdir_factory): path = git_dir(tempdir_factory) with cwd(path): runner = Runner(path) mkdirp(os.path.dirname(runner.pre_commit_path)) with io.open(runner.pre_commit_path, 'w') as pre_commit_file: pre_commit_file.write('#!/usr/bin/env bash\necho 1\n') make_executable(runner.pre_commit_path) assert uninstall(runner) == 0 assert os.path.exists(runner.pre_commit_path)
def test_uninstall_doesnt_remove_not_our_hooks(tempdir_factory): path = git_dir(tempdir_factory) with cwd(path): runner = Runner(path, C.CONFIG_FILE) mkdirp(os.path.join(path, '.git/hooks')) with io.open(os.path.join(path, '.git/hooks/pre-commit'), 'w') as f: f.write('#!/usr/bin/env bash\necho 1\n') make_executable(f.name) assert uninstall(runner) == 0 assert os.path.exists(os.path.join(path, '.git/hooks/pre-commit'))
def test_uninstall_doesnt_remove_not_our_hooks(tempdir_factory): path = git_dir(tempdir_factory) with cwd(path): runner = Runner(path, C.CONFIG_FILE) mkdirp(os.path.dirname(runner.pre_commit_path)) with io.open(runner.pre_commit_path, 'w') as pre_commit_file: pre_commit_file.write('#!/usr/bin/env bash\necho 1\n') make_executable(runner.pre_commit_path) assert uninstall(runner) == 0 assert os.path.exists(runner.pre_commit_path)
def staged_files_only(patch_dir): """Clear any unstaged changes from the git working directory inside this context. """ # Determine if there are unstaged files tree = cmd_output('git', 'write-tree')[1].strip() retcode, diff_stdout_binary, _ = cmd_output( 'git', 'diff-index', '--ignore-submodules', '--binary', '--exit-code', '--no-color', '--no-ext-diff', tree, '--', retcode=None, encoding=None, ) if retcode and diff_stdout_binary.strip(): patch_filename = 'patch{}'.format(int(time.time())) patch_filename = os.path.join(patch_dir, patch_filename) logger.warning('Unstaged files detected.') logger.info('Stashing unstaged files to {}.'.format(patch_filename), ) # Save the current unstaged changes as a patch mkdirp(patch_dir) with io.open(patch_filename, 'wb') as patch_file: patch_file.write(diff_stdout_binary) # Clear the working directory of unstaged changes cmd_output('git', 'checkout', '--', '.') try: yield finally: # Try to apply the patch we saved try: _git_apply(patch_filename) except CalledProcessError: logger.warning( 'Stashed changes conflicted with hook auto-fixes... ' 'Rolling back fixes...', ) # We failed to apply the patch, presumably due to fixes made # by hooks. # Roll back the changes made by hooks. cmd_output('git', 'checkout', '--', '.') _git_apply(patch_filename) logger.info('Restored changes from {}.'.format(patch_filename)) else: # There weren't any staged files so we don't need to do anything # special yield
def install( runner, overwrite=False, hooks=False, hook_type='pre-commit', skip_on_missing_conf=False, ): """Install the pre-commit hooks.""" hook_path = runner.get_hook_path(hook_type) legacy_path = hook_path + '.legacy' mkdirp(os.path.dirname(hook_path)) # 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) # If we specify overwrite, we simply delete the legacy file if overwrite and os.path.exists(legacy_path): os.remove(legacy_path) elif os.path.exists(legacy_path): output.write_line( 'Running in migration mode with existing hooks at {}\n' 'Use -f to use only pre-commit.'.format(legacy_path), ) params = { 'CONFIG': runner.config_file, 'HOOK_TYPE': hook_type, 'INSTALL_PYTHON': sys.executable, 'SKIP_ON_MISSING_CONFIG': skip_on_missing_conf, } with io.open(hook_path, 'w') as hook_file: with io.open(resource_filename('hook-tmpl')) as f: contents = f.read() before, rest = contents.split(TEMPLATE_START) to_template, after = rest.split(TEMPLATE_END) hook_file.write(before + TEMPLATE_START) for line in to_template.splitlines(): var = line.split()[0] hook_file.write('{} = {!r}\n'.format(var, params[var])) hook_file.write(TEMPLATE_END + after) make_executable(hook_path) output.write_line('pre-commit installed at {}'.format(hook_path)) # If they requested we install all of the hooks, do so. if hooks: install_hooks(runner) return 0
def test_failing_existing_hook_returns_1(tempdir_factory, store): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') with cwd(path): # Write out a failing "old" hook mkdirp(os.path.join(path, '.git/hooks')) with io.open(os.path.join(path, '.git/hooks/pre-commit'), 'w') as f: f.write('#!/usr/bin/env bash\necho "fail!"\nexit 1\n') make_executable(f.name) assert install(C.CONFIG_FILE, store, hook_types=['pre-commit']) == 0 # We should get a failure from the legacy hook ret, output = _get_commit_output(tempdir_factory) assert ret == 1 assert FAIL_OLD_HOOK.match(output)
def test_failing_existing_hook_returns_1(tempdir_factory, store): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') with cwd(path): # Write out a failing "old" hook mkdirp(os.path.join(path, '.git/hooks')) with io.open(os.path.join(path, '.git/hooks/pre-commit'), 'w') as f: f.write('#!/usr/bin/env bash\necho "fail!"\nexit 1\n') make_executable(f.name) assert install(C.CONFIG_FILE, store) == 0 # We should get a failure from the legacy hook ret, output = _get_commit_output(tempdir_factory) assert ret == 1 assert FAIL_OLD_HOOK.match(output)
def test_install_overwrite(tempdir_factory): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') with cwd(path): runner = Runner(path) # Write out the "old" hook mkdirp(os.path.dirname(runner.pre_commit_path)) with io.open(runner.pre_commit_path, 'w') as hook_file: hook_file.write('#!/usr/bin/env bash\necho "legacy hook"\n') make_executable(runner.pre_commit_path) assert install(runner, overwrite=True) == 0 ret, output = _get_commit_output(tempdir_factory) assert ret == 0 assert NORMAL_PRE_COMMIT_RUN.match(output)
def test_install_overwrite(tempdir_factory): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') with cwd(path): runner = Runner(path, C.CONFIG_FILE) # Write out the "old" hook mkdirp(os.path.dirname(runner.pre_commit_path)) with io.open(runner.pre_commit_path, 'w') as hook_file: hook_file.write('#!/usr/bin/env bash\necho "legacy hook"\n') make_executable(runner.pre_commit_path) assert install(runner, overwrite=True) == 0 ret, output = _get_commit_output(tempdir_factory) assert ret == 0 assert NORMAL_PRE_COMMIT_RUN.match(output)
def staged_files_only(patch_dir): """Clear any unstaged changes from the git working directory inside this context. """ # Determine if there are unstaged files tree = cmd_output('git', 'write-tree')[1].strip() retcode, diff_stdout_binary, _ = cmd_output( 'git', 'diff-index', '--ignore-submodules', '--binary', '--exit-code', '--no-color', '--no-ext-diff', tree, '--', retcode=None, encoding=None, ) if retcode and diff_stdout_binary.strip(): patch_filename = 'patch{}'.format(int(time.time())) patch_filename = os.path.join(patch_dir, patch_filename) logger.warning('Unstaged files detected.') logger.info( 'Stashing unstaged files to {}.'.format(patch_filename), ) # Save the current unstaged changes as a patch mkdirp(patch_dir) with io.open(patch_filename, 'wb') as patch_file: patch_file.write(diff_stdout_binary) # Clear the working directory of unstaged changes cmd_output('git', 'checkout', '--', '.') try: yield finally: # Try to apply the patch we saved try: _git_apply(patch_filename) except CalledProcessError: logger.warning( 'Stashed changes conflicted with hook auto-fixes... ' 'Rolling back fixes...', ) # We failed to apply the patch, presumably due to fixes made # by hooks. # Roll back the changes made by hooks. cmd_output('git', 'checkout', '--', '.') _git_apply(patch_filename) logger.info('Restored changes from {}.'.format(patch_filename)) else: # There weren't any staged files so we don't need to do anything # special yield
def test_failing_existing_hook_returns_1(tempdir_factory): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') with cwd(path): runner = Runner(path, C.CONFIG_FILE) # Write out a failing "old" hook mkdirp(os.path.dirname(runner.pre_commit_path)) with io.open(runner.pre_commit_path, 'w') as hook_file: hook_file.write('#!/usr/bin/env bash\necho "fail!"\nexit 1\n') make_executable(runner.pre_commit_path) assert install(runner) == 0 # We should get a failure from the legacy hook ret, output = _get_commit_output(tempdir_factory) assert ret == 1 assert FAIL_OLD_HOOK.match(output)
def test_failing_existing_hook_returns_1(tempdir_factory): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') with cwd(path): runner = Runner(path) # Write out a failing "old" hook mkdirp(os.path.dirname(runner.pre_commit_path)) with io.open(runner.pre_commit_path, 'w') as hook_file: hook_file.write('#!/usr/bin/env bash\necho "fail!"\nexit 1\n') make_executable(runner.pre_commit_path) assert install(runner) == 0 # We should get a failure from the legacy hook ret, output = _get_commit_output(tempdir_factory) assert ret == 1 assert FAIL_OLD_HOOK.match(output)
def install(runner, overwrite=False, hooks=False, hook_type="pre-commit"): """Install the pre-commit hooks.""" hook_path = runner.get_hook_path(hook_type) legacy_path = hook_path + ".legacy" mkdirp(os.path.dirname(hook_path)) # If we have an existing hook, move it to pre-commit.legacy if os.path.lexists(hook_path) and not is_our_pre_commit(hook_path) and not is_previous_pre_commit(hook_path): os.rename(hook_path, legacy_path) # If we specify overwrite, we simply delete the legacy file if overwrite and os.path.exists(legacy_path): os.remove(legacy_path) elif os.path.exists(legacy_path): print( "Running in migration mode with existing hooks at {0}\n" "Use -f to use only pre-commit.".format(legacy_path) ) with io.open(hook_path, "w") as pre_commit_file_obj: if hook_type == "pre-push": with io.open(resource_filename("pre-push-tmpl")) as fp: pre_push_contents = fp.read() else: pre_push_contents = "" contents = ( io.open(resource_filename("hook-tmpl")) .read() .format(sys_executable=sys.executable, hook_type=hook_type, pre_push=pre_push_contents) ) pre_commit_file_obj.write(contents) make_executable(hook_path) print("pre-commit installed at {0}".format(hook_path)) # If they requested we install all of the hooks, do so. if hooks: # Set up our logging handler logger.addHandler(LoggingHandler(False)) logger.setLevel(logging.INFO) for repository in runner.repositories: repository.require_installed() return 0
def _install_hook_script( config_file, hook_type, overwrite=False, skip_on_missing_config=False, git_dir=None, ): hook_path, legacy_path = _hook_paths(hook_type, git_dir=git_dir) mkdirp(os.path.dirname(hook_path)) # 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): shutil.move(hook_path, legacy_path) # If we specify overwrite, we simply delete the legacy file if overwrite and os.path.exists(legacy_path): os.remove(legacy_path) elif os.path.exists(legacy_path): output.write_line( 'Running in migration mode with existing hooks at {}\n' 'Use -f to use only pre-commit.'.format(legacy_path), ) params = { 'CONFIG': config_file, 'HOOK_TYPE': hook_type, 'INSTALL_PYTHON': sys.executable, 'SKIP_ON_MISSING_CONFIG': skip_on_missing_config, } with io.open(hook_path, 'w') as hook_file: contents = resource_text('hook-tmpl') before, rest = contents.split(TEMPLATE_START) to_template, after = rest.split(TEMPLATE_END) before = before.replace('#!/usr/bin/env python3', shebang()) hook_file.write(before + TEMPLATE_START) for line in to_template.splitlines(): var = line.split()[0] hook_file.write('{} = {!r}\n'.format(var, params[var])) hook_file.write(TEMPLATE_END + after) make_executable(hook_path) output.write_line('pre-commit installed at {}'.format(hook_path))
def install(runner, overwrite=False, hooks=False, hook_type='pre-commit'): """Install the pre-commit hooks.""" hook_path = runner.get_hook_path(hook_type) legacy_path = hook_path + '.legacy' mkdirp(os.path.dirname(hook_path)) # If we have an existing hook, move it to pre-commit.legacy if (os.path.lexists(hook_path) and not is_our_pre_commit(hook_path) and not is_previous_pre_commit(hook_path)): os.rename(hook_path, legacy_path) # If we specify overwrite, we simply delete the legacy file if overwrite and os.path.exists(legacy_path): os.remove(legacy_path) elif os.path.exists(legacy_path): print('Running in migration mode with existing hooks at {0}\n' 'Use -f to use only pre-commit.'.format(legacy_path, )) with io.open(hook_path, 'w') as pre_commit_file_obj: if hook_type == 'pre-push': with io.open(resource_filename('pre-push-tmpl')) as fp: pre_push_contents = fp.read() else: pre_push_contents = '' contents = io.open(resource_filename('hook-tmpl')).read().format( sys_executable=sys.executable, hook_type=hook_type, pre_push=pre_push_contents, ) pre_commit_file_obj.write(contents) make_executable(hook_path) print('pre-commit installed at {0}'.format(hook_path)) # If they requested we install all of the hooks, do so. if hooks: # Set up our logging handler logger.addHandler(LoggingHandler(False)) logger.setLevel(logging.INFO) for repository in runner.repositories: repository.require_installed() return 0
def test_uninstall_restores_legacy_hooks(tempdir_factory): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') with cwd(path): runner = Runner(path, C.CONFIG_FILE) # Write out an "old" hook mkdirp(os.path.dirname(runner.pre_commit_path)) with io.open(runner.pre_commit_path, 'w') as hook_file: hook_file.write('#!/usr/bin/env bash\necho "legacy hook"\n') make_executable(runner.pre_commit_path) # Now install and uninstall pre-commit assert install(runner) == 0 assert uninstall(runner) == 0 # Make sure we installed the "old" hook correctly ret, output = _get_commit_output(tempdir_factory, touch_file='baz') assert ret == 0 assert EXISTING_COMMIT_RUN.match(output)
def test_commit_msg_legacy(commit_msg_repo, tempdir_factory, store): hook_path = os.path.join(commit_msg_repo, '.git/hooks/commit-msg') mkdirp(os.path.dirname(hook_path)) with io.open(hook_path, 'w') as hook_file: hook_file.write( '#!/usr/bin/env bash\n' 'set -eu\n' 'test -e "$1"\n' 'echo legacy\n', ) make_executable(hook_path) install(C.CONFIG_FILE, store, hook_types=['commit-msg']) msg = 'Hi\nSigned off by: asottile' retc, out = _get_commit_output(tempdir_factory, msg=msg) assert retc == 0 first_line, second_line = out.splitlines()[:2] assert first_line == 'legacy' assert second_line.startswith('Must have "Signed off by:"...')
def test_uninstall_restores_legacy_hooks(tempdir_factory): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') with cwd(path): runner = Runner(path) # Write out an "old" hook mkdirp(os.path.dirname(runner.pre_commit_path)) with io.open(runner.pre_commit_path, 'w') as hook_file: hook_file.write('#!/usr/bin/env bash\necho "legacy hook"\n') make_executable(runner.pre_commit_path) # Now install and uninstall pre-commit assert install(runner) == 0 assert uninstall(runner) == 0 # Make sure we installed the "old" hook correctly ret, output = _get_commit_output(tempdir_factory, touch_file='baz') assert ret == 0 assert EXISTING_COMMIT_RUN.match(output)
def test_install_existing_hook_no_overwrite_idempotent(tempdir_factory): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') with cwd(path): runner = Runner(path, C.CONFIG_FILE) # Write out an "old" hook mkdirp(os.path.dirname(runner.pre_commit_path)) with io.open(runner.pre_commit_path, 'w') as hook_file: hook_file.write('#!/usr/bin/env bash\necho "legacy hook"\n') make_executable(runner.pre_commit_path) # Install twice assert install(runner) == 0 assert install(runner) == 0 # We should run both the legacy and pre-commit hooks ret, output = _get_commit_output(tempdir_factory) assert ret == 0 assert output.startswith('legacy hook\n') assert NORMAL_PRE_COMMIT_RUN.match(output[len('legacy hook\n'):])
def test_commit_msg_legacy(commit_msg_repo, tempdir_factory, store): hook_path = os.path.join(commit_msg_repo, '.git/hooks/commit-msg') mkdirp(os.path.dirname(hook_path)) with io.open(hook_path, 'w') as hook_file: hook_file.write( '#!/usr/bin/env bash\n' 'set -eu\n' 'test -e "$1"\n' 'echo legacy\n', ) make_executable(hook_path) install(C.CONFIG_FILE, store, hook_type='commit-msg') msg = 'Hi\nSigned off by: asottile' retc, out = _get_commit_output(tempdir_factory, msg=msg) assert retc == 0 first_line, second_line = out.splitlines()[:2] assert first_line == 'legacy' assert second_line.startswith('Must have "Signed off by:"...')
def test_replace_old_commit_script(tempdir_factory, store): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') with cwd(path): # Install a script that looks like our old script pre_commit_contents = resource_text('hook-tmpl') new_contents = pre_commit_contents.replace( CURRENT_HASH, PRIOR_HASHES[-1], ) mkdirp(os.path.join(path, '.git/hooks')) with io.open(os.path.join(path, '.git/hooks/pre-commit'), 'w') as f: f.write(new_contents) make_executable(f.name) # Install normally assert install(C.CONFIG_FILE, store) == 0 ret, output = _get_commit_output(tempdir_factory) assert ret == 0 assert NORMAL_PRE_COMMIT_RUN.match(output)
def test_install_existing_hook_no_overwrite_idempotent(tempdir_factory): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') with cwd(path): runner = Runner(path) # Write out an "old" hook mkdirp(os.path.dirname(runner.pre_commit_path)) with io.open(runner.pre_commit_path, 'w') as hook_file: hook_file.write('#!/usr/bin/env bash\necho "legacy hook"\n') make_executable(runner.pre_commit_path) # Install twice assert install(runner) == 0 assert install(runner) == 0 # We should run both the legacy and pre-commit hooks ret, output = _get_commit_output(tempdir_factory) assert ret == 0 assert output.startswith('legacy hook\n') assert NORMAL_PRE_COMMIT_RUN.match(output[len('legacy hook\n'):])
def test_replace_old_commit_script(tempdir_factory, store): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') with cwd(path): # Install a script that looks like our old script pre_commit_contents = resource_text('hook-tmpl') new_contents = pre_commit_contents.replace( CURRENT_HASH, PRIOR_HASHES[-1], ) mkdirp(os.path.join(path, '.git/hooks')) with io.open(os.path.join(path, '.git/hooks/pre-commit'), 'w') as f: f.write(new_contents) make_executable(f.name) # Install normally assert install(C.CONFIG_FILE, store, hook_types=['pre-commit']) == 0 ret, output = _get_commit_output(tempdir_factory) assert ret == 0 assert NORMAL_PRE_COMMIT_RUN.match(output)
def test_replace_old_commit_script(tempdir_factory): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') with cwd(path): runner = Runner(path, C.CONFIG_FILE) # Install a script that looks like our old script pre_commit_contents = io.open(resource_filename('hook-tmpl'), ).read() new_contents = pre_commit_contents.replace( IDENTIFYING_HASH, PREVIOUS_IDENTIFYING_HASHES[-1], ) mkdirp(os.path.dirname(runner.pre_commit_path)) with io.open(runner.pre_commit_path, 'w') as pre_commit_file: pre_commit_file.write(new_contents) make_executable(runner.pre_commit_path) # Install normally assert install(runner) == 0 ret, output = _get_commit_output(tempdir_factory) assert ret == 0 assert NORMAL_PRE_COMMIT_RUN.match(output)
def test_replace_old_commit_script(tempdir_factory): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') with cwd(path): runner = Runner(path) # Install a script that looks like our old script pre_commit_contents = io.open( resource_filename('hook-tmpl'), ).read() new_contents = pre_commit_contents.replace( IDENTIFYING_HASH, PREVIOUS_IDENTIFYING_HASHES[-1], ) mkdirp(os.path.dirname(runner.pre_commit_path)) with io.open(runner.pre_commit_path, 'w') as pre_commit_file: pre_commit_file.write(new_contents) make_executable(runner.pre_commit_path) # Install normally assert install(runner) == 0 ret, output = _get_commit_output(tempdir_factory) assert ret == 0 assert NORMAL_PRE_COMMIT_RUN.match(output)
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): mkdirp(os.path.join(path, '.git/hooks')) with io.open(os.path.join(path, '.git/hooks/pre-push'), 'w') as f: f.write( '#!/usr/bin/env bash\n' 'set -eu\n' 'read lr ls rr rs\n' 'test -n "$lr" -a -n "$ls" -a -n "$rr" -a -n "$rs"\n' 'echo legacy\n', ) make_executable(f.name) install(C.CONFIG_FILE, store, hook_types=['pre-push']) assert _get_commit_output(tempdir_factory)[0] == 0 retc, output = _get_push_output(tempdir_factory) assert retc == 0 first_line, _, third_line = output.splitlines()[:3] assert first_line == 'legacy' assert third_line.startswith('Bash hook') assert third_line.endswith('Passed')
def test_install_existing_hooks_no_overwrite(tempdir_factory): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') with cwd(path): runner = Runner(path) # Write out an "old" hook mkdirp(os.path.dirname(runner.pre_commit_path)) with io.open(runner.pre_commit_path, 'w') as hook_file: hook_file.write('#!/usr/bin/env bash\necho "legacy hook"\n') make_executable(runner.pre_commit_path) # Make sure we installed the "old" hook correctly ret, output = _get_commit_output(tempdir_factory, touch_file='baz') assert ret == 0 assert EXISTING_COMMIT_RUN.match(output) # Now install pre-commit (no-overwrite) assert install(runner) == 0 # We should run both the legacy and pre-commit hooks ret, output = _get_commit_output(tempdir_factory) assert ret == 0 assert output.startswith('legacy hook\n') assert NORMAL_PRE_COMMIT_RUN.match(output[len('legacy hook\n'):])
def _write_legacy_hook(path): mkdirp(os.path.join(path, '.git/hooks')) with io.open(os.path.join(path, '.git/hooks/pre-commit'), 'w') as f: f.write('#!/usr/bin/env bash\necho "legacy hook"\n') make_executable(f.name)