Merge pull request #47 from guykisel/merge-conflict-hook
Add check-merge-conflict hook
diff --git a/README.md b/README.md
index e980a98..b4c7ee8 100644
--- a/README.md
+++ b/README.md
@@ -28,6 +28,7 @@
- `check-case-conflict` - Check for files that would conflict in case-insensitive filesystems.
- `check-docstring-first` - Checks a common error of defining a docstring after code.
- `check-json` - Attempts to load all json files to verify syntax.
+- `check-merge-conflict` - Check for files that contain merge conflict strings.
- `check-xml` - Attempts to load all xml files to verify syntax.
- `check-yaml` - Attempts to load all yaml files to verify syntax.
- `debug-statements` - Check for pdb / ipdb / pudb statements in code.
diff --git a/hooks.yaml b/hooks.yaml
index 0d84f03..595637f 100644
--- a/hooks.yaml
+++ b/hooks.yaml
@@ -31,6 +31,13 @@
entry: check-json
language: python
files: \.json$
+- id: check-merge-conflict
+ name: Check for merge conflicts
+ description: Check for files that contain merge conflict strings.
+ entry: check-merge-conflict
+ language: python
+ # Match all files
+ files: ''
- id: check-xml
name: Check Xml
description: This hook checks xml files for parseable syntax.
diff --git a/pre_commit_hooks/check_merge_conflict.py b/pre_commit_hooks/check_merge_conflict.py
new file mode 100644
index 0000000..ac405b2
--- /dev/null
+++ b/pre_commit_hooks/check_merge_conflict.py
@@ -0,0 +1,31 @@
+from __future__ import print_function
+
+import argparse
+import sys
+
+CONFLICT_PATTERNS = [
+ '<<<<<<< ',
+ '=======',
+ '>>>>>>> '
+]
+WARNING_MSG = 'Merge conflict string "{0}" found in {1}:{2}'
+
+
+def detect_merge_conflict(argv=None):
+ parser = argparse.ArgumentParser()
+ parser.add_argument('filenames', nargs='*')
+ args = parser.parse_args(argv)
+
+ retcode = 0
+ for filename in args.filenames:
+ with open(filename) as inputfile:
+ for i, line in enumerate(inputfile):
+ for pattern in CONFLICT_PATTERNS:
+ if line.startswith(pattern):
+ print(WARNING_MSG.format(pattern, filename, i + 1))
+ retcode = 1
+
+ return retcode
+
+if __name__ == '__main__':
+ sys.exit(detect_merge_conflict())
diff --git a/setup.py b/setup.py
index e4f0900..0455b53 100644
--- a/setup.py
+++ b/setup.py
@@ -41,6 +41,7 @@
'check-added-large-files = pre_commit_hooks.check_added_large_files:main',
'check-case-conflict = pre_commit_hooks.check_case_conflict:main',
'check-docstring-first = pre_commit_hooks.check_docstring_first:main',
+ 'check-merge-conflict = pre_commit_hooks.check_merge_conflict:detect_merge_conflict',
'check-json = pre_commit_hooks.check_json:check_json',
'check-xml = pre_commit_hooks.check_xml:check_xml',
'check-yaml = pre_commit_hooks.check_yaml:check_yaml',
diff --git a/tests/check_merge_conflict_test.py b/tests/check_merge_conflict_test.py
new file mode 100644
index 0000000..bcf90eb
--- /dev/null
+++ b/tests/check_merge_conflict_test.py
@@ -0,0 +1,26 @@
+import os.path
+
+import pytest
+
+from pre_commit_hooks.check_merge_conflict import detect_merge_conflict
+
+# Input, expected return value
+TESTS = (
+ (b'<<<<<<< HEAD', 1),
+ (b'=======', 1),
+ (b'>>>>>>> master', 1),
+ (b'# <<<<<<< HEAD', 0),
+ (b'# =======', 0),
+ (b'import my_module', 0),
+ (b'', 0),
+)
+
+
+@pytest.mark.parametrize(('input_s', 'expected_retval'), TESTS)
+def test_detect_merge_conflict(input_s, expected_retval, tmpdir):
+ path = os.path.join(tmpdir.strpath, 'file.txt')
+
+ with open(path, 'wb') as file_obj:
+ file_obj.write(input_s)
+
+ assert detect_merge_conflict([path]) == expected_retval