Skip to content

Commit

Permalink
Documentation improvements + extra-path default path fix
Browse files Browse the repository at this point in the history
Extra-path now defaults to 'None' instead of the current working
directory.

Documentation improvements:
 - Features section on the homepage
 - More documentation of the user-defined rules (still WIP)
  • Loading branch information
jroovers-cisco committed Dec 2, 2016
1 parent 9235aeb commit 9c6f70d
Show file tree
Hide file tree
Showing 13 changed files with 142 additions and 52 deletions.
6 changes: 3 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

## v0.8.0 (In Development) ##

- debug output improvements: Gitlint will now print a lot more information when using ```--debug```
- Debug output improvements: Gitlint will now print a lot more information when using ```--debug```

## v0.7.1 (2016-06-18) ##
Bugfixes:

- **Behavior change**: gitlint no longer prints the file path by default when using a ```.gitlint``` file. The path
will still be printed when using the new ```--debug``` flag. Special thanks to [Slipcon](https://github.com/slipcon).
- **Behavior Change**: gitlint no longer prints the file path by default when using a ```.gitlint``` file. The path
will still be printed when using the new ```--debug``` flag. Special thanks to [Slipcon](https://github.com/slipcon)
for submitting this.
- Gitlint now prints a correct violation message for the ```title-match-regex``` rule. Special thanks to
[Slipcon](https://github.com/slipcon) for submitting this.
Expand Down
20 changes: 12 additions & 8 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ gitlint --config myconfigfile.ini
```

The block below shows a sample ```.gitlint``` file. Details about rule config options can be found on the
[Rules](rules.md) page, details about general can be found on the
[Rules](rules.md) page, details about the ```[general]``` section can be found in the
[General Configuration](configuration.md#general-configuration) section of this page.

```ini
Expand All @@ -24,6 +24,9 @@ verbosity = 2
# By default gitlint will ignore merge commits. Set to 'false' to disable.
ignore-merge-commits=true

# Set the extra-path where gitlint will search for user defined rules
# See http://jorisroovers.github.io/gitlint/user_defined_rules for details
# extra-path=examples/

[title-max-length]
line-length=20
Expand Down Expand Up @@ -99,10 +102,11 @@ Configuring gitlint happens the following order of precedence:
The table below outlines configuration options that modify gitlint's overall behavior. These options can be specified
using commandline flags or in ```general``` section in a ```.gitlint``` configuration file.

Name | gitlint version | commandline flag | Description
---------------------|-----------------|------------------------------------|-------------------------------------
silent | >= 0.1 | ```--silent``` | Enable silent mode (no output). Use [exit](index.md#exit-codes) code to determine result.
verbosity | >= 0.1 | ```--verbosity=3``` | Amount of output gitlint will show when printing errors.
ignore-merge-commits | >= 0.7.0 | Not available | Whether or not to ignore merge commits.
ignore | >= 0.1 | ```--ignore=T1,body-min-length``` | Comma seperated list of rules to ignore (by name or id)
debug | >= 0.7.1 | ```--debug``` | Enable debugging output
Name | gitlint version | commandline flag | Description
---------------------|-----------------|---------------------------------------|-------------------------------------
silent | >= 0.1 | ```--silent``` | Enable silent mode (no output). Use [exit](index.md#exit-codes) code to determine result.
verbosity | >= 0.1 | ```--verbosity=3``` | Amount of output gitlint will show when printing errors.
ignore-merge-commits | >= 0.7.0 | Not available | Whether or not to ignore merge commits.
ignore | >= 0.1 | ```--ignore=T1,body-min-length``` | Comma seperated list of rules to ignore (by name or id)
debug | >= 0.7.1 | ```--debug``` | Enable debugging output
extra-path | >= 0.8.0 | ```---extra-path=/home/joe/rules/``` | Path where gitlint looks for [user-defined rules](user_defined_rules.md).
34 changes: 22 additions & 12 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,24 @@ Great for use as a ```commit-msg``` git hook or as part of your gating script in

<script type="text/javascript" src="https://asciinema.org/a/30477.js" id="asciicast-30477" async></script>

Many of the gitlint validations are based on
!!! note
Gitlint is not the only git commit message linter out there, if you are looking for an alternative written in a different language,
have a look at [fit-commit](https://github.com/m1foley/fit-commit) (Ruby) or
[node-commit-msg](https://github.com/clns/node-commit-msg) (Node.js).

## Features ##
- **Commit message hook**: Auto-trigger validations against new commit message right when you're committing.
- **Easily integrated**: Gitlint will validate any git commit message you give it via standard input. Perfect for integration with your own scripts or CI system.
- **Sane defaults:** Many of gitlint's validations are based on
[well-known](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html),
[community](http://addamhardy.com/blog/2013/06/05/good-commit-messages-and-enforcing-them-with-git-hooks/),
[standards](http://chris.beams.io/posts/git-commit/), others are based on checks that we've found
useful throughout the years. Gitlint has sane defaults, but
[you can also easily customize it to your own liking](configuration.md).

Gitlint supports python versions 2.6, 2.7 and 3.3+.
If you are looking for an alternative written in a different language, have a look at
[fit-commit](https://github.com/m1foley/fit-commit) (Ruby) or
[node-commit-msg](https://github.com/clns/node-commit-msg) (Node.js).
useful throughout the years.
- **Easily configurable:** Gitlint has sane defaults, but [you can also easily customize it to your own liking](configuration.md).
- **User-defined Rules:** Want to do more then what gitlint offers out of the box? Write your own [user defined rules](user_defined_rules).
- **Broad python version support:** Gitlint supports python versions 2.6, 2.7 and 3.3+.
- **Production-ready:** Gitlint has very high unit test coverage, integration tests and python code standards (pep8, pylint) are strictly enforced.
Gitlint also eats its own dogfood: gitlint commit messages are checked by itself on every commit.

## Getting Started ##
```bash
Expand Down Expand Up @@ -44,7 +51,8 @@ $ cat examples/commit-message-2 | gitlint
3: B2 Line has trailing whitespace: "Lines typically need to have a max length, meaning that they can't exceed a preset number of characters, usually 80 or 120. "
3: B3 Line contains hard tab characters (\t): "Lines typically need to have a max length, meaning that they can't exceed a preset number of characters, usually 80 or 120. "
```
NOTE: The returned exit code equals the number of errors found. [Some exit codes are special](index.md#exit-codes).
!!! note
The returned exit code equals the number of errors found. [Some exit codes are special](index.md#exit-codes).

For a list of available rules and their configuration options, have a look at the [Rules](rules.md) page.

Expand Down Expand Up @@ -111,9 +119,11 @@ gitlint install-hook
gitlint uninstall-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.
!!! 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.

## Merge commits ##
As of version 0.7.0, gitlint ignores merge commits by default. The rationale behind this is that in many cases
Expand Down
92 changes: 76 additions & 16 deletions docs/user_defined_rules.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,83 @@
# User Defined Rules
Gitlint versions 0.8.0 and above support the concept of User Defined rules: the ability for you
*New in gitlint 0.8.0*

Gitlint supports the concept of user-defined rules: the ability for users
to write your own custom rules that are executed when gitlint is.

This can be done using the ```extra-path``` general option, which can be set using the ```--extra-path```
commandline flag, by adding it under the ```[general]``` section in your ```.gitlint``` file or using
one of the other ways to configure gitlint. For more details, please refer to the
[Configuration](configuration.md) page.
In a nutshell, you use ```--extra-path /home/joe/myextensions``` to point gitlint to a ```myextensions``` directory where it will search
for python files containing gitlint rule classes.

```bash
cat examples/commit-message-1 | gitlint --extra-path examples/
1: UC2 Body does not contain a 'Signed-Off-By Line'
# other violations were removed for brevity
```

This was the result of executing the SignedOffBy user-defined ```CommitRule``` that was found in the
[examples/gitlint/my_commit_rules.py](https://github.com/jorisroovers/gitlint/blob/master/examples/my_commit_rules.py) file:

```python
class SignedOffBy(CommitRule):
""" This rule will enforce that each commit contains a "Signed-Off-By" line.
We keep things simple here and just check whether the commit body contains a line that starts with "Signed-Off-By".
"""

# A rule MUST have a human friendly name
name = "body-requires-signed-off-by"

# A rule MUST have an *unique* id, we recommend starting with UC (for User-defined Commit-rule).
id = "UC2"

def validate(self, commit):
for line in commit.message.body:
if line.startswith("Signed-Off-By"):
return []

return [RuleViolation(self.id, "Body does not contain a 'Signed-Off-By Line'", "", 1)]
```

As always ```--extra-path``` can also be set by adding it under the ```[general]``` section in your ```.gitlint``` file or using
one of the other ways to configure gitlint. For more details, please refer to the [Configuration](configuration.md) page.

If you want to check whether your rules are discovered, you can use the ```--debug``` flag:

If you want to check whether your rules are properly discovered by gitlint, you can use the ```--debug``` flag:

```bash
$ gitlint --debug
TODO: CONTINUE
$ gitlint --debug --extra-path examples/
[output cut for brevity]
UC1: body-max-line-count
body-max-line-count=3
UC2: body-requires-signed-off-by
UL1: title-no-special-chars
special-chars=['$', '^', '%', '@', '!', '*', '(', ')']
```

!!! Note
In most cases it's really the easiest to just copy an example from the
[examples](https://github.com/jorisroovers/gitlint/tree/master/examples) directory and modify it to your needs.
The remainder of this page contains the technical details, mostly for reference.

## Line and Commit Rules ##
TODO

The classes below are examples of user-defined CommitRules. Commit rules are gitlint rules that
act on the entire commit at once. Once the rules are discovered, gitlint will automatically take care of applying them
to the entire commit. This happens exactly once per commit.

A CommitRule contrasts with a LineRule (see examples/my_line_rules.py) in that a commit rule is only applied once on
an entire commit. This allows commit rules to implement more complex checks that span multiple lines and/or checks
that should only be done once per gitlint run.

While every LineRule can be implemented as a CommitRule, it's usually easier and more concise to go with a LineRule if
that fits your needs.

## Violations ##
TODO
## Options ##
TODO

## TODO:
- Document extra_config parameter in the configuration section

## Rule requirements
## Rule requirements ##

As long as you stick with simple scenarios that are similar to the sample User Defined rules (see the ```examples``` directory), gitlint
should be able to discover and execute your custom rules. If you want to do something more exotic however, you might run into some issues.
Expand All @@ -35,10 +94,11 @@ ultimate source of truth, here are some of the requirements that gitlint enforce

### Rule class requirements ###

- Rules *must* extend from ```LineRule``` or ```CommitRule```
- Rule classes *must* have ```id``` and ```name``` string attributes. The ```options_spec``` is optional, but if set, it *must* be a list.
- Rule classes *must* have a ```validate``` method. In case of a ```CommitRule```, ```validate``` *must* take a single ```commit``` parameter.
- Rules **must** extend from ```LineRule``` or ```CommitRule```
- Rule classes **must** have ```id``` and ```name``` string attributes. The ```options_spec``` is optional, but if set, it **must** be a list.
- Rule classes **must** have a ```validate``` method. In case of a ```CommitRule```, ```validate``` *must* take a single ```commit``` parameter.
In case of ```LineRule```, ```validate``` must take ```line``` and ```commit``` as first and second parameters.
- User Rule id's *cannot* be of the form ```R[0-9]+```, ```T[0-9]+```, ```B[0-9]+``` or ```M[0-9]+``` as these rule ids are reserved for gitlint itself.
- Rule *should* have a unique id as only one rule can exist with a given id. While gitlint does not enforce this, the rule that will
- LineRule classes **must**
- User Rule id's **cannot** be of the form ```R[0-9]+```, ```T[0-9]+```, ```B[0-9]+``` or ```M[0-9]+``` as these rule ids are reserved for gitlint itself.
- Rule **should** have a unique id as only one rule can exist with a given id. While gitlint does not enforce this, the rule that will
actually be chosen will be system specific.
3 changes: 2 additions & 1 deletion examples/gitlint
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ ignore-merge-commits=true
# Enable debug mode (prints more output). Disabled by default
debug = true

# Set the extra path where gitlint will search for user defined rules (uncomment to test)
# Set the extra-path where gitlint will search for user defined rules
# See http://jorisroovers.github.io/gitlint/user_defined_rules for details
# extra-path=examples/

[title-max-length]
Expand Down
11 changes: 10 additions & 1 deletion examples/my_commit_rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,13 @@


class BodyMaxLineCount(CommitRule):
# A rule MUST have a human friendly name
name = "body-max-line-count"

# A rule MUST have an *unique* id, we recommend starting with UC (for User-defined Commit-rule).
id = "UC1"

# A rule MAY have an option_spec if its behavior should be configurable.
options_spec = [IntOption('body-max-line-count', 3, "Maximum body line count")]

def validate(self, commit):
Expand All @@ -29,12 +34,16 @@ class SignedOffBy(CommitRule):
""" This rule will enforce that each commit contains a "Signed-Off-By" line.
We keep things simple here and just check whether the commit body contains a line that starts with "Signed-Off-By".
"""

# A rule MUST have a human friendly name
name = "body-requires-signed-off-by"

# A rule MUST have an *unique* id, we recommend starting with UC (for User-defined Commit-rule).
id = "UC2"

def validate(self, commit):
for line in commit.message.body:
if line.startswith("Signed-Off-By"):
return []

return [RuleViolation(self.id, "Body does not contain a 'Signed-Off-By Line'")]
return [RuleViolation(self.id, "Body does not contain a 'Signed-Off-By Line'", "", 1)]
12 changes: 8 additions & 4 deletions gitlint/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,7 @@ def __init__(self, config_path=None, target=None):
self._ignore_merge_commits = options.BoolOption('ignore-merge-commits', True, "Ignore merge commits")
self._debug = options.BoolOption('debug', False, "Enable debug mode")
self.config_path = config_path
self._extra_path = options.DirectoryOption('extra_path', ".",
"Path to a directory with extra user-defined rules")
self._extra_path = None
if target:
self.target = target
else:
Expand Down Expand Up @@ -98,12 +97,17 @@ def debug(self, value):

@property
def extra_path(self):
return self._extra_path.value
return self._extra_path.value if self._extra_path else None

@extra_path.setter
def extra_path(self, value):
try:
self._extra_path.set(value)
if self.extra_path:
self._extra_path.set(value)
else:
self._extra_path = options.DirectoryOption('extra_path', value,
"Path to a directory with extra user-defined rules")

rule_classes = user_rules.find_rule_classes(self.extra_path)

# Add the newly found rules to the existing rules
Expand Down
3 changes: 2 additions & 1 deletion gitlint/files/gitlint
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
# Enable debug mode (prints more output). Disabled by default.
# debug=true

# Set the extra path where gitlint will search for user defined rules
# Set the extra-path where gitlint will search for user defined rules
# See http://jorisroovers.github.io/gitlint/user_defined_rules for details
# extra-path=examples/

# [title-max-length]
Expand Down
2 changes: 1 addition & 1 deletion gitlint/tests/expected/debug_output1
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[GENERAL]
config path: {config_path}
extra path: {extra_path}
extra path: None
ignore merge commits: False
verbosity: 1
[RULES]
Expand Down
3 changes: 1 addition & 2 deletions gitlint/tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,7 @@ def test_config_file_debug(self, _git_linter):
config_path = self.get_sample_path("config/gitlintconfig")
result = self.cli.invoke(cli.cli, ["--config", config_path, "--debug"])
self.assertEqual(result.exit_code, 0)
expected = self.get_expected('debug_output1', {'config_path': config_path,
'extra_path': os.path.abspath(os.getcwd())})
expected = self.get_expected('debug_output1', {'config_path': config_path})
self.assertEqual(result.output, expected)

def test_config_file_negative(self):
Expand Down
3 changes: 3 additions & 0 deletions gitlint/tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ def test_set_general_option(self):
# extra_path
config.set_general_option("extra-path", self.get_rule_rules_path())
self.assertEqual(config.extra_path, self.get_rule_rules_path())
# reset value (this is a different code path)
config.set_general_option("extra-path", self.SAMPLES_DIR)
self.assertEqual(config.extra_path, self.SAMPLES_DIR)

def test_set_general_option_negative(self):
config = LintConfig()
Expand Down
2 changes: 1 addition & 1 deletion qa/expected/debug_output1
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[GENERAL]
config path: /vagrant/qa/samples/config/gitlintconfig
extra path: {extra_path}
extra path: None
ignore merge commits: True
verbosity: 2
[RULES]
Expand Down
3 changes: 1 addition & 2 deletions qa/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,7 @@ def test_config_from_file_debug(self):
config_path = self.get_sample_path("config/gitlintconfig")
output = gitlint("--config", config_path, "--debug", _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[4])

expected = self.get_expected('debug_output1', {'config_path': config_path,
'extra_path': self.tmp_git_repo})
expected = self.get_expected('debug_output1', {'config_path': config_path})

# TODO(jroovers): test for trailing whitespace -> git automatically strips whitespace when passing
# taking a commit message via 'git commit -m'
Expand Down

0 comments on commit 9c6f70d

Please sign in to comment.