mirror of
https://github.com/pre-commit/pre-commit-hooks.git
synced 2026-04-03 10:56:52 +00:00
First commit of file-contents-sorter precommit hook
This commit is contained in:
parent
78818b90cd
commit
9425c5d6b5
5 changed files with 119 additions and 0 deletions
|
|
@ -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
|
||||
|
|
|
|||
57
pre_commit_hooks/file_contents_sorter.py
Normal file
57
pre_commit_hooks/file_contents_sorter.py
Normal 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
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
coverage
|
||||
flake8
|
||||
ipdb
|
||||
mock
|
||||
pre-commit
|
||||
pytest
|
||||
|
|
|
|||
1
setup.py
1
setup.py
|
|
@ -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',
|
||||
|
|
|
|||
54
tests/file_contents_sorter_test.py
Normal file
54
tests/file_contents_sorter_test.py
Normal 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue