First commit of file-contents-sorter precommit hook

This commit is contained in:
Daniel Gallagher 2017-06-23 00:33:13 -07:00
parent 78818b90cd
commit 9425c5d6b5
5 changed files with 119 additions and 0 deletions

View file

@ -105,6 +105,12 @@
entry: end-of-file-fixer
language: python
files: \.(asciidoc|adoc|coffee|cpp|css|c|ejs|erb|groovy|h|haml|hh|hpp|hxx|html|in|j2|jade|json|js|less|markdown|md|ml|mli|pp|py|rb|rs|R|scala|scss|sh|slim|tex|tmpl|ts|txt|yaml|yml)$
- id: file-contents-sorter
name: File Contents Sorter
description: Sort the lines in specified files (defaults to alphabetical). You must provide list of target files as input in your .pre-commit-config.yaml file.
entry: file-contents-sorter
language: python
files: ''
- id: fix-encoding-pragma
name: Fix python encoding pragma
language: python

View file

@ -0,0 +1,57 @@
"""
A very simple pre-commit hook that, when passed one or more filenames
as arguments, will sort the lines in those files.
An example use case for this: you have a deploy-whitelist.txt file
in a repo that contains a list of filenames that is used to specify
files to be included in a docker container. This file has one filename
per line. Various users are adding/removing lines from this file; using
this hook on that file should reduce the instances of git merge
conflicts and keep the file nicely ordered.
"""
from __future__ import print_function
import argparse
PASS = 0
FAIL = 1
def sort_file_contents(f):
before = [line for line in f]
after = sorted(before)
before_string = b''.join(before)
after_string = b''.join(after)
if before_string == after_string:
return PASS
else:
f.seek(0)
f.write(after_string)
f.truncate()
return FAIL
def parse_commandline_input(argv):
parser = argparse.ArgumentParser()
parser.add_argument('filenames', nargs='+', help='Files to sort')
args = parser.parse_args(argv)
return args
def main(argv=None):
args = parse_commandline_input(argv)
retv = PASS
for arg in args.filenames:
with open(arg, 'rb+') as file_obj:
ret_for_file = sort_file_contents(file_obj)
if ret_for_file:
print('Sorting {}'.format(arg))
retv |= ret_for_file
return retv

View file

@ -2,6 +2,7 @@
coverage
flake8
ipdb
mock
pre-commit
pytest

View file

@ -49,6 +49,7 @@ setup(
'detect-private-key = pre_commit_hooks.detect_private_key:detect_private_key',
'double-quote-string-fixer = pre_commit_hooks.string_fixer:main',
'end-of-file-fixer = pre_commit_hooks.end_of_file_fixer:end_of_file_fixer',
'file-contents-sorter = pre_commit_hooks.file_contents_sorter:main',
'fix-encoding-pragma = pre_commit_hooks.fix_encoding_pragma:main',
'forbid-new-submodules = pre_commit_hooks.forbid_new_submodules:main',
'name-tests-test = pre_commit_hooks.tests_should_end_in_test:validate_files',

View file

@ -0,0 +1,54 @@
from argparse import ArgumentError
import pytest
from pre_commit_hooks.file_contents_sorter import FAIL
from pre_commit_hooks.file_contents_sorter import main
from pre_commit_hooks.file_contents_sorter import parse_commandline_input
from pre_commit_hooks.file_contents_sorter import PASS
from pre_commit_hooks.file_contents_sorter import sort_file_contents
def _n(*strs):
return b'\n'.join(strs) + '\n'
# Input, expected return value, expected output
TESTS = (
(b'', PASS, b''),
(_n('lonesome'), PASS, _n('lonesome')),
(b'missing_newline', PASS, b'missing_newline'),
(_n('alpha', 'beta'), PASS, _n('alpha', 'beta')),
(_n('beta', 'alpha'), FAIL, _n('alpha', 'beta')),
(_n('C', 'c'), PASS, _n('C', 'c')),
(_n('c', 'C'), FAIL, _n('C', 'c')),
(_n('mag ical ', ' tre vor'), FAIL, _n(' tre vor', 'mag ical ')),
(_n('@', '-', '_', '#'), FAIL, _n('#', '-', '@', '_')),
)
@pytest.mark.parametrize(('input_s', 'expected_retval', 'output'), TESTS)
def test_integration(input_s, expected_retval, output, tmpdir):
path = tmpdir.join('file.txt')
path.write_binary(input_s)
output_retval = main([path.strpath])
assert path.read_binary() == output
assert output_retval == expected_retval
def test_parse_commandline_input_errors_without_args():
with pytest.raises(SystemExit):
parse_commandline_input([])
@pytest.mark.parametrize(
('filename_list'),
(
['filename1'],
['filename1', 'filename2'],
)
)
def test_parse_commandline_input_success(filename_list):
args = parse_commandline_input(filename_list)
assert args.filenames == filename_list