summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md15
-rw-r--r--examples/gitlint1
-rw-r--r--gitlint/cli.py4
-rw-r--r--gitlint/tests/test_cli.py16
-rw-r--r--gitlint/tests/test_hooks.py59
5 files changed, 81 insertions, 14 deletions
diff --git a/README.md b/README.md
index c10b345..5d6c289 100644
--- a/README.md
+++ b/README.md
@@ -78,6 +78,7 @@ Usage: gitlint [OPTIONS]
Options:
--install-hook Install gitlint as a git commit-msg hook
+ --uninstall-hook Uninstall gitlint commit-msg hook
-C, --config PATH Config file location (default: .gitlint).
-c TEXT Config flags in format <rule>.<option>=<value> (e.g.: -c
T1.line-length=80). Flag can be used multiple times to
@@ -120,6 +121,7 @@ gitlint --config myconfigfile
By default, gitlint will look for an optional ```.gitlint``` file for configuration.
```ini
+# All these sections are optional, edit this file as you like.
[general]
ignore=title-trailing-punctuation, T3
# verbosity should be a value between 1 and 3, the commandline -v flags take precedence over
@@ -200,15 +202,13 @@ after each commit.
```bash
gitlint --install-hook
+# To remove the hook
+gitlint --uninstall-hook
```
-Important Notes:
-
-- You currently cannot uninstall the ```commit-msg``` hook using gitlint. You will need to manually remove the hook from
- ```.git/hooks/commit-msg``` in your local git repository.
-- Gitlint cannot work together with an existing hook. If you already have a ```.git/hooks/commit-msg``` file in your
- local repository, gitlint will refuse to install the ```commit-msg``` hook.
-
+Important: Gitlint cannot work together with an existing hook. If you already have a ```.git/hooks/commit-msg```
+file in your local repository, gitlint will refuse to install the ```commit-msg``` hook. gitlint will also only
+uninstall unmodified commit-msg hooks that were installed by gitlint.
## Contributing ##
@@ -262,7 +262,6 @@ python setup.py --long-description | rst2html.py > output.html
- body-changed-file-mention: list all files/directories that need to be mentioned as part of the violation
- body-changed-file-mention: distinction between change file and directory in output
- Git hooks:
- - uninstall of gitlint ```commit-msg``` hook (only uninstall if the hook is a gitlint hook)
- appending to an existing hook (after user confirmation)
- Check a range of commit messages at once (similar to how git log works, eg.: ```git log -3```)
- Rules for different attributes of the the commit message: author, date, etc
diff --git a/examples/gitlint b/examples/gitlint
index 230dfb8..4696aed 100644
--- a/examples/gitlint
+++ b/examples/gitlint
@@ -1,3 +1,4 @@
+# All these sections are optional, edit this file as you like.
[general]
ignore=title-trailing-punctuation, T3
# verbosity should be a value between 1 and 3, the commandline -v flags take precedence over
diff --git a/gitlint/cli.py b/gitlint/cli.py
index f127c1b..deff009 100644
--- a/gitlint/cli.py
+++ b/gitlint/cli.py
@@ -64,7 +64,7 @@ def uninstall_hook(ctx, param, value):
@click.option('--install-hook', is_flag=True, callback=install_hook, is_eager=True, expose_value=False,
help="Install gitlint as a git commit-msg hook")
@click.option('--uninstall-hook', is_flag=True, callback=uninstall_hook, is_eager=True, expose_value=False,
- help="[experimental] Uninstall gitlint commit-msg hook")
+ help="Uninstall gitlint commit-msg hook")
@click.option('-C', '--config', type=click.Path(exists=True),
help="Config file location (default: {0}).".format(DEFAULT_CONFIG_FILE))
@click.option('-c', multiple=True,
@@ -97,7 +97,7 @@ def cli(config, c, ignore, verbose, silent):
lint_config.verbosity = verbose
except LintConfigError as e:
click.echo("Config Error: {0}".format(e.message))
- exit(CONFIG_ERROR_CODE) # return 10000 on config error
+ exit(CONFIG_ERROR_CODE) # return CONFIG_ERROR_CODE on config error
if sys.stdin.isatty():
gitcontext = GitContext.from_local_repository()
diff --git a/gitlint/tests/test_cli.py b/gitlint/tests/test_cli.py
index 35789f4..594a677 100644
--- a/gitlint/tests/test_cli.py
+++ b/gitlint/tests/test_cli.py
@@ -60,3 +60,19 @@ class CLITests(BaseTestCase):
self.assertEqual(result.exit_code, 1)
self.assertEqual(result.output, "test\n")
install_hook.assert_called_once_with()
+
+ @patch('gitlint.hooks.GitHookInstaller.uninstall_commit_msg_hook')
+ def test_uninstall_hook(self, uninstall_hook):
+ result = self.cli.invoke(cli.cli, ["--uninstall-hook"])
+ expected = "Successfully uninstalled gitlint commit-msg hook from {0}\n\n".format(
+ hooks.COMMIT_MSG_HOOK_DST_PATH)
+ self.assertEqual(result.exit_code, 0)
+ self.assertEqual(result.output, expected)
+ uninstall_hook.assert_called_once_with()
+
+ @patch('gitlint.hooks.GitHookInstaller.uninstall_commit_msg_hook', side_effect=hooks.GitHookInstallerError("test"))
+ def test_uninstall_hook_negative(self, uninstall_hook):
+ result = self.cli.invoke(cli.cli, ["--uninstall-hook"])
+ self.assertEqual(result.exit_code, 1)
+ self.assertEqual(result.output, "test\n")
+ uninstall_hook.assert_called_once_with()
diff --git a/gitlint/tests/test_hooks.py b/gitlint/tests/test_hooks.py
index 48fdbfb..b80685f 100644
--- a/gitlint/tests/test_hooks.py
+++ b/gitlint/tests/test_hooks.py
@@ -1,6 +1,7 @@
from gitlint.tests.base import BaseTestCase
-from gitlint.hooks import GitHookInstaller, GitHookInstallerError, COMMIT_MSG_HOOK_SRC_PATH, COMMIT_MSG_HOOK_DST_PATH
-from mock import patch, ANY
+from gitlint.hooks import GitHookInstaller, GitHookInstallerError, COMMIT_MSG_HOOK_SRC_PATH, COMMIT_MSG_HOOK_DST_PATH, \
+ GITLINT_HOOK_IDENTIFIER
+from mock import patch, ANY, mock_open
class HookTests(BaseTestCase):
@@ -23,7 +24,8 @@ class HookTests(BaseTestCase):
def test_install_commit_msg_hook_negative(self, isdir, path_exists, copy):
# mock that current dir is not a git repo
isdir.return_value = False
- with self.assertRaises(GitHookInstallerError):
+ expected_msg = "The current directory is not a git repository"
+ with self.assertRaisesRegexp(GitHookInstallerError, expected_msg):
GitHookInstaller.install_commit_msg_hook()
isdir.assert_called_once_with('.git/hooks')
path_exists.assert_not_called()
@@ -32,5 +34,54 @@ class HookTests(BaseTestCase):
# mock that there is already a commit hook present
isdir.return_value = True
path_exists.return_value = True
- with self.assertRaises(GitHookInstallerError):
+ expected_msg = "There is already a commit-msg hook file present in {}".format(COMMIT_MSG_HOOK_DST_PATH) + \
+ ". gitlint currently does not support appending to an existing commit-msg file."
+ with self.assertRaisesRegexp(GitHookInstallerError, expected_msg):
GitHookInstaller.install_commit_msg_hook()
+
+ @patch('os.remove')
+ @patch('os.path.exists', return_value=True)
+ @patch('os.path.isdir', return_value=True)
+ def test_uninstall_commit_msg_hook(self, isdir, path_exists, remove):
+ read_data = "#!/bin/sh\n" + GITLINT_HOOK_IDENTIFIER
+ with patch('gitlint.hooks.open', mock_open(read_data=read_data), create=True):
+ GitHookInstaller.uninstall_commit_msg_hook()
+
+ isdir.assert_called_once_with('.git/hooks')
+ path_exists.assert_called_once_with(COMMIT_MSG_HOOK_DST_PATH)
+ remove.assert_called_once_with(COMMIT_MSG_HOOK_DST_PATH)
+
+ @patch('os.remove')
+ @patch('os.path.exists', return_value=True)
+ @patch('os.path.isdir', return_value=True)
+ def test_uninstall_commit_msg_hook_negative(self, isdir, path_exists, remove):
+ # mock that the current directory is not a git repo
+ isdir.return_value = False
+ expected_msg = "The current directory is not a git repository"
+ with self.assertRaisesRegexp(GitHookInstallerError, expected_msg):
+ GitHookInstaller.install_commit_msg_hook()
+ isdir.assert_called_once_with('.git/hooks')
+ path_exists.assert_not_called()
+ remove.assert_not_called()
+
+ # mock that there is no commit hook present
+ isdir.return_value = True
+ path_exists.return_value = False
+ expected_msg = "There is no commit-msg hook present in {}".format(COMMIT_MSG_HOOK_DST_PATH)
+ with self.assertRaisesRegexp(GitHookInstallerError, expected_msg):
+ GitHookInstaller.uninstall_commit_msg_hook()
+ isdir.assert_called_once_with('.git/hooks')
+ path_exists.assert_called_once_with(COMMIT_MSG_HOOK_DST_PATH)
+ remove.assert_not_called()
+
+ # mock that there is a different (=not gitlint) commit hook
+ isdir.return_value = True
+ path_exists.return_value = True
+ read_data = "#!/bin/sh\nfoo"
+ expected_msg = "The commit-msg hook in {} was not installed by gitlint ".format(COMMIT_MSG_HOOK_DST_PATH) + \
+ "\(or it was modified\).\nUninstallation of 3th party or modified gitlint hooks " + \
+ "is not supported."
+ with patch('gitlint.hooks.open', mock_open(read_data=read_data), create=True):
+ with self.assertRaisesRegexp(GitHookInstallerError, expected_msg):
+ GitHookInstaller.uninstall_commit_msg_hook()
+ remove.assert_not_called()