summaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/configuration.md482
-rw-r--r--docs/contrib_rules.md38
-rw-r--r--docs/contributing.md217
-rw-r--r--docs/demos/asciicinema.json16
-rw-r--r--docs/extra.css8
-rw-r--r--docs/extra.js5
-rw-r--r--docs/images/dev-container.pngbin0 -> 212226 bytes
-rw-r--r--docs/images/gitlint-packages.drawio.svg351
-rw-r--r--docs/images/gitlint-packages.pngbin0 -> 51975 bytes
-rw-r--r--docs/images/readme-gitlint.pngbin0 -> 348007 bytes
-rw-r--r--docs/index.md339
-rw-r--r--docs/rules.md494
-rw-r--r--docs/user_defined_rules.md337
13 files changed, 1710 insertions, 577 deletions
diff --git a/docs/configuration.md b/docs/configuration.md
index 641b361..af49d7c 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -1,21 +1,21 @@
# Configuration
Gitlint can be configured through different means.
-# Config files #
-You can modify gitlint's behavior by adding a ```.gitlint``` file to your git repository.
+## The .gitlint file
+You can modify gitlint's behavior by adding a `.gitlint` file to your git repository.
-Generate a default ```.gitlint``` config file by running:
-```bash
+Generate a default `.gitlint` config file by running:
+```sh
gitlint generate-config
```
You can also use a different config file like so:
-```bash
-gitlint --config myconfigfile.ini
+```sh
+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 the ```[general]``` section can be found in the
+The block below shows a sample `.gitlint` file. Details about rule config options 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
@@ -25,7 +25,7 @@ The block below shows a sample ```.gitlint``` file. Details about rule config op
# one rule and each key in it is an option for that specific rule.
#
# Rules and sections can be referenced by their full name or by id. For example
-# section "[body-max-line-length]" could be written as "[B1]". Full section names are
+# section "[body-max-line-length]" could also be written as "[B1]". Full section names are
# used in here for clarity.
# Rule reference documentation: http://jorisroovers.github.io/gitlint/rules/
#
@@ -39,19 +39,31 @@ ignore=title-trailing-punctuation, T3
# precedence over this
verbosity = 2
-# By default gitlint will ignore merge, revert, fixup and squash commits.
+# By default gitlint will ignore merge, revert, fixup, fixup=amend, and squash commits.
ignore-merge-commits=true
ignore-revert-commits=true
ignore-fixup-commits=true
+ignore-fixup-amend-commits=true
ignore-squash-commits=true
-# Ignore any data send to gitlint via stdin
+# Ignore any data sent to gitlint via stdin
ignore-stdin=true
-# Fetch additional meta-data from the local repository when manually passing a
+# Fetch additional meta-data from the local repository when manually passing a
# commit message to gitlint via stdin or --commit-msg. Disabled by default.
staged=true
+# Hard fail when the target commit range is empty. Note that gitlint will
+# already fail by default on invalid commit ranges. This option is specifically
+# to tell gitlint to fail on *valid but empty* commit ranges.
+# Disabled by default.
+fail-without-commits=true
+
+# Whether to use Python `search` instead of `match` semantics in rules that use
+# regexes. Context: https://github.com/jorisroovers/gitlint/issues/254
+# Disabled by default, but will be enabled by default in the future.
+regex-style-search=true
+
# Enable debug mode (prints more output). Disabled by default.
debug=true
@@ -68,6 +80,11 @@ extra-path=examples/
[title-max-length]
line-length=80
+# Conversely, you can also enforce minimal length of a title with the
+# "title-min-length" rule:
+[title-min-length]
+min-length=5
+
[title-must-not-contain-word]
# Comma-separated list of words that should not occur in the title. Matching is case
# insensitive. It's fine if the keyword occurs as part of a larger word (so "WIPING"
@@ -75,7 +92,7 @@ line-length=80
words=wip
[title-match-regex]
-# python like regex (https://docs.python.org/2/library/re.html) that the
+# python like regex (https://docs.python.org/3/library/re.html) that the
# commit-msg title must be matched to.
# Note that the regex can contradict with other rules if not used correctly
# (e.g. title-must-not-contain-word).
@@ -95,14 +112,20 @@ ignore-merge-commits=false
[body-changed-file-mention]
# List of files that need to be explicitly mentioned in the body when they are changed
# This is useful for when developers often erroneously edit certain files or git submodules.
-# By specifying this rule, developers can only change the file when they explicitly reference
-# it in the commit message.
-files=gitlint/rules.py,README.md
+# By specifying this rule, developers can only change the file when they explicitly
+# reference it in the commit message.
+files=gitlint-core/gitlint/rules.py,README.md
+
+[body-match-regex]
+# python-style regex that the commit-msg body must match.
+# E.g. body must end in My-Commit-Tag: foo
+regex=My-Commit-Tag: foo$
[author-valid-email]
-# python like regex (https://docs.python.org/2/library/re.html) that the
+# python like regex (https://docs.python.org/3/library/re.html) that the
# commit author email address should be matched to
-# For example, use the following regex if you only want to allow email addresses from foo.com
+# E.g.: For example, use the following regex if you only want to allow email
+# addresses from foo.com
regex=[^@]+@foo.com
[ignore-by-title]
@@ -117,12 +140,26 @@ ignore=T1,body-min-length
[ignore-by-body]
# Ignore certain rules for commits of which the body has a line that matches a regex
# E.g. Match bodies that have a line that that contain "release"
-# regex=(.*)release(.*)
+regex=(.*)release(.*)
#
# Ignore certain rules, you can reference them by their id or by their full name
# Use 'all' to ignore all rules
ignore=T1,body-min-length
+[ignore-body-lines]
+# Ignore certain lines in a commit body that match a regex.
+# E.g. Ignore all lines that start with 'Co-Authored-By'
+regex=^Co-Authored-By
+
+[ignore-by-author-name]
+# Ignore certain rules for commits of which the author name matches a regex
+# E.g. Match commits made by dependabot
+regex=(.*)dependabot(.*)
+
+# Ignore certain rules, you can reference them by their id or by their full name
+# Use 'all' to ignore all rules
+ignore=T1,body-min-length
+
# This is a contrib rule - a community contributed rule. These are disabled by default.
# You need to explicitly enable them one-by-one by adding them to the "contrib" option
# under [general] section above.
@@ -131,20 +168,20 @@ ignore=T1,body-min-length
types = bugfix,user-story,epic
```
-# Commandline config #
+## Commandline config
-You can also use one or more ```-c``` flags like so:
+You can also use one or more `-c` flags like so:
```
$ gitlint -c general.verbosity=2 -c title-max-length.line-length=80 -c B1.line-length=100
```
-The generic config flag format is ```-c <rule>.<option>=<value>``` and supports all the same rules and options which
-you can also use in a ```.gitlint``` config file.
+The generic config flag format is `-c <rule>.<option>=<value>` and supports all the same rules and options which
+you can also use in a `.gitlint` config file.
-# Commit specific config #
+## Commit specific config
You can also configure gitlint by adding specific lines to your commit message.
-For now, we only support ignoring commits by adding ```gitlint-ignore: all``` to the commit
+For now, we only support ignoring commits by adding `gitlint-ignore: all` to the commit
message like so:
```
@@ -154,9 +191,9 @@ I want gitlint to ignore this entire commit message.
gitlint-ignore: all
```
-```gitlint-ignore: all``` can occur on any line, as long as it is at the start of the line.
+`gitlint-ignore: all` can occur on any line, as long as it is at the start of the line.
-You can also specify specific rules to be ignored as follows:
+You can also specify specific rules to be ignored as follows:
```
WIP: This is my commit message
@@ -166,44 +203,47 @@ gitlint-ignore: T1, body-hard-tab
-# Configuration precedence #
+## Configuration precedence
gitlint configuration is applied in the following order of precedence:
-1. Commit specific config (e.g.: ```gitlint-ignore: all``` in the commit message)
-2. Configuration Rules (e.g.: [ignore-by-title](/rules/#i1-ignore-by-title))
-3. Commandline convenience flags (e.g.: ```-vv```, ```--silent```, ```--ignore```)
-4. Commandline configuration flags (e.g.: ```-c title-max-length=123```)
-5. Configuration file (local ```.gitlint``` file, or file specified using ```-C```/```--config```)
-6. Default gitlint config
+1. Commit specific config (e.g.: `gitlint-ignore: all` in the commit message)
+2. Configuration Rules (e.g.: [ignore-by-title](rules.md#i1-ignore-by-title))
+3. Commandline convenience flags (e.g.: `-vv`, `--silent`, `--ignore`)
+4. Environment variables (e.g.: `GITLINT_VERBOSITY=3`)
+5. Commandline configuration flags (e.g.: `-c title-max-length=123`)
+6. Configuration file (local `.gitlint` file, or file specified using `-C`/`--config`)
+7. Default gitlint config
-# General Options
+## General Options
Below we outline all 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.
+using commandline flags or in `[general]` section in a `.gitlint` configuration file.
-## silent
+### silent
Enable silent mode (no output). Use [exit](index.md#exit-codes) code to determine result.
-Default value | gitlint version | commandline flag
----------------|------------------|-------------------
- false | >= 0.1.0 | ```--silent```
+| Default value | gitlint version | commandline flag | environment variable |
+| ------------- | --------------- | ---------------- | -------------------- |
+| `False` | >= 0.1.0 | `--silent` | `GITLINT_SILENT` |
-### Examples
+#### Examples
```sh
# CLI
gitlint --silent
+GITLINT_SILENT=1 gitlint # using env variable
```
+------------------------------------------------------------------------------------------------------------------------
-## verbosity
+### verbosity
Amount of output gitlint will show when printing errors.
-Default value | gitlint version | commandline flag
----------------|------------------|-------------------
- 3 | >= 0.1.0 | `-v`
+| Default value | gitlint version | commandline flag | environment variable |
+| ------------- | --------------- | ---------------- | -------------------- |
+| 3 | >= 0.1.0 | `-v` | `GITLINT_VERBOSITY` |
-### Examples
+#### Examples
```sh
# CLI
gitlint -vvv # default (level 3)
@@ -212,221 +252,377 @@ gitlint -v # even less (level 1)
gitlint --silent # no output (level 0)
gitlint -c general.verbosity=1 # Set specific level
gitlint -c general.verbosity=0 # Same as --silent
+GITLINT_VERBOSITY=2 gitlint # using env variable
```
```ini
-.gitlint
+# .gitlint
[general]
verbosity=2
```
+------------------------------------------------------------------------------------------------------------------------
-## ignore-merge-commits
+### ignore
-Whether or not to ignore merge commits.
+Comma separated list of rules to ignore (by name or id).
-Default value | gitlint version | commandline flag
----------------|------------------|-------------------
- true | >= 0.7.0 | Not Available
+| Default value | gitlint version | commandline flag | environment variable |
+| ---------------- | --------------- | ---------------- | -------------------- |
+| [] (=empty list) | >= 0.1.0 | `--ignore` | `GITLINT_IGNORE` |
-### Examples
+#### Examples
```sh
# CLI
-gitlint -c general.ignore-merge-commits=false
+gitlint --ignore=body-min-length # ignore single rule
+gitlint --ignore=T1,body-min-length # ignore multiple rule
+gitlint -c general.ignore=T1,body-min-length # different way of doing the same
+GITLINT_IGNORE=T1,body-min-length gitlint # using env variable
```
```ini
#.gitlint
[general]
-ignore-merge-commits=false
+ignore=T1,body-min-length
```
+------------------------------------------------------------------------------------------------------------------------
-## ignore-revert-commits
+### debug
-Whether or not to ignore revert commits.
+Enable debugging output.
-Default value | gitlint version | commandline flag
----------------|------------------|-------------------
- true | >= 0.13.0 | Not Available
+| Default value | gitlint version | commandline flag | environment variable |
+| ------------- | --------------- | ---------------- | -------------------- |
+| false | >= 0.7.1 | `--debug` | `GITLINT_DEBUG` |
-### Examples
+#### Examples
```sh
# CLI
-gitlint -c general.ignore-revert-commits=false
+gitlint --debug
+GITLINT_DEBUG=1 gitlint # using env variable
+# --debug is special, the following does NOT work
+# gitlint -c general.debug=true
+```
+------------------------------------------------------------------------------------------------------------------------
+
+### target
+
+Target git repository gitlint should be linting against.
+
+| Default value | gitlint version | commandline flag | environment variable |
+| ------------- | --------------- | ---------------- | -------------------- |
+| (empty) | >= 0.8.0 | `--target` | `GITLINT_TARGET` |
+
+#### Examples
+```sh
+# CLI
+gitlint --target=/home/joe/myrepo/
+gitlint -c general.target=/home/joe/myrepo/ # different way of doing the same
+GITLINT_TARGET=/home/joe/myrepo/ gitlint # using env variable
```
```ini
#.gitlint
[general]
-ignore-revert-commits=false
+target=/home/joe/myrepo/
```
+------------------------------------------------------------------------------------------------------------------------
-## ignore-fixup-commits
+### config
-Whether or not to ignore [fixup](https://git-scm.com/docs/git-commit#git-commit---fixupltcommitgt) commits.
+Path where gitlint looks for a config file.
+
+| Default value | gitlint version | commandline flag | environment variable |
+| ------------- | --------------- | ---------------- | -------------------- |
+| `.gitlint` | >= 0.1.0 | `--config` | `GITLINT_CONFIG` |
+
+#### Examples
+```sh
+gitlint --config=/home/joe/gitlint.ini
+gitlint -C /home/joe/gitlint.ini # different way of doing the same
+GITLINT_CONFIG=/home/joe/gitlint.ini # using env variable
+```
+------------------------------------------------------------------------------------------------------------------------
+
+### extra-path
+
+Path where gitlint looks for [user-defined rules](user_defined_rules.md).
-Default value | gitlint version | commandline flag
----------------|------------------|-------------------
- true | >= 0.9.0 | Not Available
+| Default value | gitlint version | commandline flag | environment variable |
+| ------------- | --------------- | ---------------- | -------------------- |
+| (empty) | >= 0.8.0 | `--extra-path` | `GITLINT_EXTRA_PATH` |
-### Examples
+#### Examples
```sh
# CLI
-gitlint -c general.ignore-fixup-commits=false
+gitlint --extra-path=/home/joe/rules/
+gitlint -c general.extra-path=/home/joe/rules/ # different way of doing the same
+GITLINT_EXTRA_PATH=/home/joe/rules/ gitlint # using env variable
```
```ini
#.gitlint
[general]
-ignore-fixup-commits=false
+extra-path=/home/joe/rules/
```
+------------------------------------------------------------------------------------------------------------------------
+### contrib
-## ignore-squash-commits
+Comma-separated list of [Contrib rules](contrib_rules.md) to enable (by name or id).
-Whether or not to ignore [squash](https://git-scm.com/docs/git-commit#git-commit---squashltcommitgt) commits.
+| Default value | gitlint version | commandline flag | environment variable |
+| ------------- | --------------- | ---------------- | -------------------- |
+| (empty) | >= 0.12.0 | `--contrib` | `GITLINT_CONTRIB` |
-Default value | gitlint version | commandline flag
----------------|------------------|-------------------
- true | >= 0.9.0 | Not Available
+#### Examples
+```sh
+# CLI
+gitlint --contrib=contrib-title-conventional-commits,CC1
+# different way of doing the same
+gitlint -c general.contrib=contrib-title-conventional-commits,CC1
+# using env variable
+GITLINT_CONTRIB=contrib-title-conventional-commits,CC1 gitlint
+```
+```ini
+#.gitlint
+[general]
+contrib=contrib-title-conventional-commits,CC1
+```
+------------------------------------------------------------------------------------------------------------------------
+
+### staged
+
+Attempt smart guesses about meta info (like author name, email, branch, changed files, etc) when manually passing a
+commit message to gitlint via stdin or `--commit-msg`.
+
+Since in such cases no actual git commit exists (yet) for the message being linted, gitlint
+needs to apply some heuristics (like checking `git config` and any staged changes) to make a smart guess about what the
+likely author name, email, commit date, changed files and branch of the ensuing commit would be.
-### Examples
+When not using the `--staged` flag while linting a commit message via stdin or `--commit-msg`, gitlint will only have
+access to the commit message itself for linting and won't be able to enforce rules like
+[M1:author-valid-email](rules.md#m1-author-valid-email).
+
+| Default value | gitlint version | commandline flag | environment variable |
+| ------------- | --------------- | ---------------- | -------------------- |
+| false | >= 0.13.0 | `--staged` | `GITLINT_STAGED` |
+
+#### Examples
```sh
# CLI
-gitlint -c general.ignore-squash-commits=false
+gitlint --staged
+gitlint -c general.staged=true # different way of doing the same
+GITLINT_STAGED=1 gitlint # using env variable
```
```ini
#.gitlint
[general]
-ignore-squash-commits=false
+staged=true
```
+------------------------------------------------------------------------------------------------------------------------
-## ignore
+### fail-without-commits
-Comma separated list of rules to ignore (by name or id).
+Hard fail when the target commit range is empty. Note that gitlint will
+already fail by default on invalid commit ranges. This option is specifically
+to tell gitlint to fail on **valid but empty** commit ranges.
-Default value | gitlint version | commandline flag
----------------------------|------------------|-------------------
- [] (=empty list) | >= 0.1.0 | `--ignore`
+| Default value | gitlint version | commandline flag | environment variable |
+| ------------- | --------------- | ------------------------ | ------------------------------ |
+| false | >= 0.15.2 | `--fail-without-commits` | `GITLINT_FAIL_WITHOUT_COMMITS` |
-### Examples
+#### Examples
```sh
# CLI
-gitlint --ignore=body-min-length # ignore single rule
-gitlint --ignore=T1,body-min-length # ignore multiple rule
-gitlint -c general.ignore=T1,body-min-length # different way of doing the same
+# The following will cause gitlint to hard fail (i.e. exit code > 0)
+# since HEAD..HEAD is a valid but empty commit range.
+gitlint --fail-without-commits --commits HEAD..HEAD
+GITLINT_FAIL_WITHOUT_COMMITS=1 gitlint # using env variable
```
```ini
#.gitlint
[general]
-ignore=T1,body-min-length
+fail-without-commits=true
```
-## debug
+---
+### regex-style-search
+
+Whether to use Python `re.search()` instead of `re.match()` semantics in all built-in rules that use regular expressions.
+
+| Default value | gitlint version | commandline flag | environment variable |
+| ------------- | --------------- | ---------------- | -------------------- |
+| false | >= 0.18.0 | Not Available | Not Available |
+
+!!! important
+ At this time, `regex-style-search` is **disabled** by default, but it will be **enabled** by default in the future.
+
+
+
+Gitlint will log a warning when you're using a rule that uses a custom regex and this option is not enabled:
+
+```plain
+WARNING: I1 - ignore-by-title: gitlint will be switching from using Python regex 'match' (match beginning) to
+'search' (match anywhere) semantics. Please review your ignore-by-title.regex option accordingly.
+To remove this warning, set general.regex-style-search=True.
+More details: https://jorisroovers.github.io/gitlint/configuration/#regex-style-search
+```
+
+*If you don't have any custom regex specified, gitlint will not log a warning and no action is needed.*
+
+**To remove the warning:**
+
+1. Review your regex in the rules gitlint warned for and ensure it's still accurate when using [`re.search()` semantics](https://docs.python.org/3/library/re.html#search-vs-match).
+2. Enable `regex-style-search` in your `.gitlint` file (or using [any other way to configure gitlint](http://127.0.0.1:8000/gitlint/configuration/)):
+
+```ini
+[general]
+regex-style-search=true
+```
+
+#### More context
+Python offers [two different primitive operations based on regular expressions](https://docs.python.org/3/library/re.html#search-vs-match):
+`re.match()` checks for a match only at the beginning of the string, while `re.search()` checks for a match anywhere
+in the string.
-Enable debugging output.
-Default value | gitlint version | commandline flag
----------------|------------------|-------------------
- false | >= 0.7.1 | `--debug`
-### Examples
+Most rules in gitlint already use `re.search()` instead of `re.match()`, but there's a few notable exceptions that
+use `re.match()`, which can lead to unexpected matching behavior.
+
+- M1 - author-valid-email
+- I1 - ignore-by-title
+- I2 - ignore-by-body
+- I3 - ignore-body-lines
+- I4 - ignore-by-author-name
+
+The `regex-style-search` option is meant to fix this inconsistency. Setting it to `true` will force the above rules to
+use `re.search()` instead of `re.match()`. For detailed context, see [issue #254](https://github.com/jorisroovers/gitlint/issues/254).
+
+
+#### Examples
```sh
# CLI
-gitlint --debug
-# --debug is special, the following does NOT work
-# gitlint -c general.debug=true
+gitlint -c general.regex-style-search=true
+```
+```ini
+#.gitlint
+[general]
+regex-style-search=true
```
+------------------------------------------------------------------------------------------------------------------------
+### ignore-stdin
-## target
+Ignore any stdin data. Sometimes useful when running gitlint in a CI server.
-Target git repository gitlint should be linting against.
+| Default value | gitlint version | commandline flag | environment variable |
+| ------------- | --------------- | ---------------- | ---------------------- |
+| false | >= 0.12.0 | `--ignore-stdin` | `GITLINT_IGNORE_STDIN` |
+
+#### Examples
+```sh
+# CLI
+gitlint --ignore-stdin
+gitlint -c general.ignore-stdin=true # different way of doing the same
+GITLINT_IGNORE_STDIN=1 gitlint # using env variable
+```
+```ini
+#.gitlint
+[general]
+ignore-stdin=true
+```
+------------------------------------------------------------------------------------------------------------------------
+
+### ignore-merge-commits
-Default value | gitlint version | commandline flag
----------------------------|------------------|-------------------
- (empty) | >= 0.8.0 | `--target`
+Whether or not to ignore merge commits.
-### Examples
+| Default value | gitlint version | commandline flag | environment variable |
+| ------------- | --------------- | ---------------- | -------------------- |
+| true | >= 0.7.0 | Not Available | Not Available |
+
+#### Examples
```sh
# CLI
-gitlint --target=/home/joe/myrepo/
-gitlint -c general.target=/home/joe/myrepo/ # different way of doing the same
+gitlint -c general.ignore-merge-commits=false
```
```ini
#.gitlint
[general]
-target=/home/joe/myrepo/
+ignore-merge-commits=false
```
+------------------------------------------------------------------------------------------------------------------------
-## extra-path
+### ignore-revert-commits
-Path where gitlint looks for [user-defined rules](user_defined_rules.md).
+Whether or not to ignore revert commits.
-Default value | gitlint version | commandline flag
----------------------------|------------------|-------------------
- (empty) | >= 0.8.0 | `--extra-path`
+| Default value | gitlint version | commandline flag | environment variable |
+| ------------- | --------------- | ---------------- | -------------------- |
+| true | >= 0.13.0 | Not Available | Not Available |
-### Examples
+#### Examples
```sh
# CLI
-gitlint --extra-path=/home/joe/rules/
-gitlint -c general.extra-path=/home/joe/rules/ # different way of doing the same
+gitlint -c general.ignore-revert-commits=false
```
```ini
#.gitlint
[general]
-extra-path=/home/joe/rules/
+ignore-revert-commits=false
```
+------------------------------------------------------------------------------------------------------------------------
-## contrib
+### ignore-fixup-commits
-[Contrib rules](contrib_rules) to enable.
+Whether or not to ignore [fixup](https://git-scm.com/docs/git-commit#git-commit---fixupltcommitgt) commits.
-Default value | gitlint version | commandline flag
----------------------------|------------------|-------------------
- (empty) | >= 0.12.0 | `--contrib`
+| Default value | gitlint version | commandline flag | environment variable |
+| ------------- | --------------- | ---------------- | -------------------- |
+| true | >= 0.9.0 | Not Available | Not Available |
-### Examples
+#### Examples
```sh
# CLI
-gitlint --contrib=contrib-title-conventional-commits,CC1
-gitlint -c general.contrib=contrib-title-conventional-commits,CC1 # different way of doing the same
+gitlint -c general.ignore-fixup-commits=false
```
```ini
#.gitlint
[general]
-contrib=contrib-title-conventional-commits,CC1
+ignore-fixup-commits=false
```
-## ignore-stdin
+------------------------------------------------------------------------------------------------------------------------
-Ignore any stdin data. Sometimes useful when running gitlint in a CI server.
+### ignore-fixup-amend-commits
+
+Whether or not to ignore [fixup=amend](https://git-scm.com/docs/git-commit#Documentation/git-commit.txt---fixupamendrewordltcommitgt) commits.
-Default value | gitlint version | commandline flag
----------------|------------------|-------------------
- false | >= 0.12.0 | `--ignore-stdin`
+| Default value | gitlint version | commandline flag | environment variable |
+| ------------- | --------------- | ---------------- | -------------------- |
+| true | >= 0.18.0 | Not Available | Not Available |
-### Examples
+#### Examples
```sh
# CLI
-gitlint --ignore-stdin
-gitlint -c general.ignore-stdin=true # different way of doing the same
+gitlint -c general.ignore-fixup-amend-commits=false
```
```ini
#.gitlint
[general]
-ignore-stdin=true
+ignore-fixup-amend-commits=false
```
+------------------------------------------------------------------------------------------------------------------------
-## staged
+### ignore-squash-commits
-Fetch additional meta-data from the local `repository when manually passing a commit message to gitlint via stdin or ```--commit-msg```.
+Whether or not to ignore [squash](https://git-scm.com/docs/git-commit#git-commit---squashltcommitgt) commits.
-Default value | gitlint version | commandline flag
----------------|------------------|-------------------
- false | >= 0.13.0 | `--staged`
+| Default value | gitlint version | commandline flag | environment variable |
+| ------------- | --------------- | ---------------- | -------------------- |
+| true | >= 0.9.0 | Not Available | Not Available |
-### Examples
+#### Examples
```sh
# CLI
-gitlint --staged
-gitlint -c general.staged=true # different way of doing the same
+gitlint -c general.ignore-squash-commits=false
```
```ini
#.gitlint
[general]
-staged=true
+ignore-squash-commits=false
``` \ No newline at end of file
diff --git a/docs/contrib_rules.md b/docs/contrib_rules.md
index a4f4f0d..e085f23 100644
--- a/docs/contrib_rules.md
+++ b/docs/contrib_rules.md
@@ -1,16 +1,17 @@
# Using Contrib Rules
+
_Introduced in gitlint v0.12.0_
Contrib rules are community-**contrib**uted rules that are disabled by default, but can be enabled through configuration.
Contrib rules are meant to augment default gitlint behavior by providing users with rules for common use-cases without
forcing these rules on all gitlint users. This also means that users don't have to
-re-implement these commonly used rules themselves as [user-defined](user_defined_rules) rules.
+re-implement these commonly used rules themselves as [user-defined](user_defined_rules.md) rules.
-To enable certain contrib rules, you can use the ```--contrib``` flag.
+To enable certain contrib rules, you can use the `--contrib` flag.
```sh
$ cat examples/commit-message-1 | gitlint --contrib contrib-title-conventional-commits,CC1
-1: CC1 Body does not contain a 'Signed-Off-By' line
+1: CC1 Body does not contain a 'Signed-off-by' line
1: CL1 Title does not start with one of fix, feat, chore, docs, style, refactor, perf, test: "WIP: This is the title of a commit message."
# These are the default violations
@@ -20,7 +21,7 @@ $ cat examples/commit-message-1 | gitlint --contrib contrib-title-conventional-c
3: B1 Line exceeds max length (123>80): "Lines typically need to have a max length, meaning that they can't exceed a preset number of characters, usually 80 or 120."
```
-Same thing using a ```.gitlint``` file:
+Same thing using a `.gitlint` file:
```ini
[general]
@@ -36,12 +37,14 @@ types = bugfix,user-story,epic
You can also configure contrib rules using [any of the other ways to configure gitlint](configuration.md).
-# Available Contrib Rules
+## Available Contrib Rules
ID | Name | gitlint version | Description
------|-------------------------------------|------------------ |-------------------------------------------
CT1 | contrib-title-conventional-commits | >= 0.12.0 | Enforces [Conventional Commits](https://www.conventionalcommits.org/) commit message style on the title.
-CC1 | contrib-requires-signed-off-by | >= 0.12.0 | Commit body must contain a `Signed-Off-By` line.
+CC1 | contrib-body-requires-signed-off-by | >= 0.12.0 | Commit body must contain a `Signed-off-by` line.
+CC2 | contrib-disallow-cleanup-commits | >= 0.18.0 | Commit title must not contain `fixup!`, `squash!`, `amend!`.
+CC3 | contrib-allowed-authors | >= 0.18.0 | Enforce that only authors listed in the `AUTHORS` file are allowed to commit.
## CT1: contrib-title-conventional-commits ##
@@ -53,15 +56,28 @@ CT1 | contrib-title-conventional-commits | >= 0.12.0 | Enforces [C
Name | gitlint version | Default | Description
---------------|--------------------|--------------|----------------------------------
-types | >= 0.12.0 | `fix,feat,chore,docs,style,refactor,perf,test,revert` | Comma separated list of allowed commit types.
+types | >= 0.12.0 | `fix,feat,chore,docs,style,refactor,perf,test,revert,ci,build` | Comma separated list of allowed commit types.
-## CC1: contrib-requires-signed-off-by ##
+## CC1: contrib-body-requires-signed-off-by ##
ID | Name | gitlint version | Description
------|---------------------------------------|--------------------|-------------------------------------------
-CC1 | contrib-requires-signed-off-by | >= 0.12.0 | Commit body must contain a `Signed-Off-By` line. This means, a line that starts with the `Signed-Off-By` keyword.
+CC1 | contrib-body-requires-signed-off-by | >= 0.12.0 | Commit body must contain a `Signed-off-by` line. This means, a line that starts with the `Signed-off-by` keyword.
+
+
+## CC2: contrib-disallow-cleanup-commits ##
+
+ID | Name | gitlint version | Description
+------|----------------------------------|--------------------|-------------------------------------------
+CC2 | contrib-disallow-cleanup-commits | >= 0.18.0 | Commit title must not contain `fixup!`, `squash!` or `amend!`. This means `git commit --fixup` and `git commit --squash` commits are not allowed.
+
+## CC3: contrib-allowed-authors ##
+
+ID | Name | gitlint version | Description
+------|----------------------------------|--------------------|-------------------------------------------
+CC3 | contrib-allowed-authors | >= 0.18.0 | The commit author must be listed in an `AUTHORS` file to be allowed to commit. Possible file names are also `AUTHORS.txt` and `AUTHORS.md`.
+## Contributing Contrib rules
-# Contributing Contrib rules
-We'd love for you to contribute new Contrib rules to gitlint or improve existing ones! Please visit the [Contributing](contributing) page on how to get started. \ No newline at end of file
+We'd love for you to contribute new Contrib rules to gitlint or improve existing ones! Please visit the [Contributing](contributing.md) page on how to get started.
diff --git a/docs/contributing.md b/docs/contributing.md
index 0cd6eaf..d111bc6 100644
--- a/docs/contributing.md
+++ b/docs/contributing.md
@@ -3,97 +3,178 @@
We'd love for you to contribute to gitlint. Thanks for your interest!
The [source-code and issue tracker](https://github.com/jorisroovers/gitlint) are hosted on Github.
-Often it takes a while for us (well, actually just [me](https://github.com/jorisroovers)) to get back to you
-(sometimes up to a few months, this is a hobby project), but rest assured that we read your message and appreciate
-your interest!
-We maintain a [loose roadmap on our wiki](https://github.com/jorisroovers/gitlint/wiki/Roadmap), but
-that's open to a lot of change and input.
+!!! note
+ Often it takes a while for us (well, actually just [me](https://github.com/jorisroovers)) to get back to you
+ (sometimes up to a few months, this is a hobby project), but rest assured that we read your message and appreciate
+ your interest!
+ We maintain a [loose project plan on github projects](https://github.com/users/jorisroovers/projects/1/), but
+ that's open to a lot of change and input.
-# Guidelines
+## Overall Guidelines
When contributing code, please consider all the parts that are typically required:
-- [Unit tests](https://github.com/jorisroovers/gitlint/tree/master/gitlint/tests) (automatically
+- [Unit tests](https://github.com/jorisroovers/gitlint/tree/main/gitlint-core/gitlint/tests) (automatically
[enforced by CI](https://github.com/jorisroovers/gitlint/actions)). Please consider writing
new ones for your functionality, not only updating existing ones to make the build pass.
-- [Integration tests](https://github.com/jorisroovers/gitlint/tree/master/qa) (also automatically
+- [Integration tests](https://github.com/jorisroovers/gitlint/tree/main/qa) (also automatically
[enforced by CI](https://github.com/jorisroovers/gitlint/actions)). Again, please consider writing new ones
for your functionality, not only updating existing ones to make the build pass.
-- [Documentation](https://github.com/jorisroovers/gitlint/tree/master/docs)
+- [Documentation](https://github.com/jorisroovers/gitlint/tree/main/docs).
Since we want to maintain a high standard of quality, all of these things will have to be done regardless before code
-can make it as part of a release. If you can already include them as part of your PR, it's a huge timesaver for us
-and it's likely that your PR will be merged and released a lot sooner. Thanks!
+can make it as part of a release. **Gitlint commits and pull requests are gated on all of our tests and checks as well as
+code-review**. If you can already include them as part of your PR, it's a huge timesaver for us
+and it's likely that your PR will be merged and released a lot sooner.
-# Development #
+!!! important
+ It's a good idea to open an issue before submitting a PR for non-trivial changes, so we can discuss what you have
+ in mind before you spend the effort. Thanks!
-There is a Vagrantfile in this repository that can be used for development.
-```bash
-vagrant up
-vagrant ssh
-```
+## Releases
+Gitlint releases typically go out when there's either enough new features and fixes
+to make it worthwhile or when there's a critical fix for a bug that fundamentally breaks gitlint.
-Or you can choose to use your local environment:
+While the amount of overhead of doing a release isn't huge, it's also not zero. In practice this means that it might
+take weeks or months before merged code actually gets released - we know that can be frustrating but please
+understand it's a well-considered trade-off based on available time.
-```bash
-virtualenv .venv
-pip install -r requirements.txt -r test-requirements.txt -r doc-requirements.txt
-python setup.py develop
-```
+### Dev Builds
+While final releases are usually months apart, we do dev builds on every commit to `main`:
-To run tests:
-```bash
-./run_tests.sh # run unit tests and print test coverage
-./run_test.sh gitlint/tests/test_body_rules.py::BodyRuleTests::test_body_missing # run a single test
-./run_tests.sh --no-coverage # run unit tests without test coverage
-./run_tests.sh --collect-only --no-coverage # Only collect, don't run unit tests
-./run_tests.sh --integration # Run integration tests (requires that you have gitlint installed)
-./run_tests.sh --build # Run build tests (=build python package)
-./run_tests.sh --pep8 # pep8 checks
-./run_tests.sh --stats # print some code stats
-./run_tests.sh --git # inception: run gitlint against itself
-./run_tests.sh --lint # run pylint checks
-./run_tests.sh --all # Run unit, integration, pep8 and gitlint checks
+- **gitlint**: [https://pypi.org/project/gitlint/#history](https://pypi.org/project/gitlint/#history)
+- **gitlint-core**: [https://pypi.org/project/gitlint-core/#history](https://pypi.org/project/gitlint-core/#history)
+It usually takes about 5 min after merging a PR to `main` for new dev builds to show up. Note that the installation
+of a recently published version can still fail for a few minutes after a new version shows up on PyPI while the package
+is replicated to all download mirrors.
+To install a dev build of gitlint:
+```sh
+# Find latest dev build on https://pypi.org/project/gitlint/#history
+pip install gitlint=="0.19.0.dev68"
```
-The ```Vagrantfile``` comes with ```virtualenv```s for python 2.7, 3.5, 3.6, 3.7 and pypy2.
-You can easily run tests against specific python environments by using the following commands *inside* of the Vagrant VM:
+
+## Environment setup
+### Local setup
+
+Gitlint uses [hatch](https://hatch.pypa.io/latest/) for project management.
+You do not need to setup a `virtualenv`, hatch will take care of that for you.
+
+```sh
+pip install hatch
```
-./run_tests.sh --envs 27 # Run the unit tests against Python 2.7
-./run_tests.sh --envs 27,35,pypy2 # Run the unit tests against Python 2.7, Python 3.5 and Pypy2
-./run_tests.sh --envs 27,35 --pep8 # Run pep8 checks against Python 2.7 and Python 3.5 (also works for ```--git```, ```--integration```, ```--pep8```, ```--stats``` and ```--lint```).
-./run_tests.sh --envs all --all # Run all tests against all environments
-./run_tests.sh --all-env --all # Idem: Run all tests against all environments
+
+### Github Devcontainer
+
+We provide a devcontainer on github to make it easier to get started with gitlint development using VSCode.
+
+To start one, click the plus button under the *Code* dropdown on
+[the gitlint repo on github](https://github.com/jorisroovers/gitlint).
+
+**It can take ~15min for all post installation steps to finish.**
+
+![Gitlint Dev Container Instructions](images/dev-container.png)
+
+
+By default we have python 3.11 installed in the dev container, but you can also use [asdf](https://asdf-vm.com/)
+(preinstalled) to install additional python versions:
+
+```sh
+# Ensure ASDF overrides system python in PATH
+# You can also append this line to your ~/.bash_profile in the devcontainer to have this happen automatically on login
+source "$(brew --prefix asdf)/libexec/asdf.sh"
+
+# Install python 3.9.15
+asdf install python 3.9.15
+# List all available python versions
+asdf list all python
+# List installed python versions
+asdf list python
```
-!!! important
- Gitlint commits and pull requests are gated on all of our tests and checks.
+## Running tests
+```sh
+# Gitlint
+hatch run dev:gitlint # run the local source copy of gitlint
+hatch run dev:gitlint --version # This is just the gitlint binary, any flag will work
+hatch run dev:gitlint --debug
-# Packaging #
+# Unit tests
+hatch run test:unit-tests # run unit tests
+hatch run test:unit-tests gitlint-core/gitlint/tests/rules/test_body_rules.py::BodyRuleTests::test_body_missing # run a single test
+hatch run test:unit-tests -k test_body_missing_merge_commit # Run a specific tests using a pytest keyword expression
+hatch run test:unit-tests-no-cov # run unit tests without test coverage
-To see the package description in HTML format
+# Integration tests
+hatch run qa:install-local # One-time install: install the local gitlint source copy for integration testing
+hatch run qa:integration-tests # Run integration tests
+
+# Formatting check (black)
+hatch run test:format # Run formatting checks
+
+# Linting (ruff)
+hatch run test:lint # Run Ruff
+
+# Project stats
+hatch run test:stats
+```
+## Autoformatting and autofixing
+
+We use [black](https://black.readthedocs.io/en/stable/) for code formatting.
+
+```sh
+hatch run test:autoformat # format all python code
+hatch run test:autoformat gitlint-core/gitlint/lint.py # format a specific file
```
-pip install docutils
-export LC_ALL=en_US.UTF-8
-export LANG=en_US.UTF-8
-python setup.py --long-description | rst2html.py > output.html
+
+We use [ruff](https://github.com/charliermarsh/ruff) for linting, it can autofix many of the issue it finds
+(although not always perfect).
+```sh
+hatch run test:autofix # Attempt to fix linting issues
```
-# Documentation #
+## Documentation
We use [mkdocs](https://www.mkdocs.org/) for generating our documentation from markdown.
-To use it, do the following outside of the vagrant box (on your host machine):
-```bash
-pip install -r doc-requirements.txt # install doc requirements
-mkdocs serve
+To use it:
+```sh
+hatch run docs:serve
```
-Then access the documentation website on your host machine on [http://localhost:8000]().
+Then access the documentation website on [http://localhost:8000]().
+
+## Packaging
+
+Gitlint consists of 2 python packages: [gitlint](https://pypi.org/project/gitlint/)
+and [gitlint-core](https://pypi.org/project/gitlint-core/).
+
+The `gitlint` package is just a wrapper package around `gitlint-core[trusted-deps]` which strictly pins gitlint
+dependencies to known working versions.
+
+There are scenarios where users (or OS package managers) may want looser dependency requirements.
+In these cases, users can just install `gitlint-core` directly (`pip install gitlint-core`).
+
+[Issue 162](https://github.com/jorisroovers/gitlint/issues/162) has all the background of how we got to the decision
+to split gitlint in 2 packages.
+
+![Gitlint package structure](images/gitlint-packages.png)
+
+To build the packages locally:
+```sh
+# gitlint
+hatch build
+hatch clean # cleanup
+
+# gitlint-core
+cd gitlint-core
+hatch build
+hatch clean # cleanup
+```
-# Tools #
-We keep a small set of scripts in the ```tools/``` directory:
+## Tools
+We keep a small set of scripts in the `tools/` directory:
```sh
tools/create-test-repo.sh # Create a test git repo in your /tmp directory
@@ -101,27 +182,27 @@ tools/windows/create-test-repo.bat # Windows: create git test repo
tools/windows/run_tests.bat # Windows run unit tests
```
-# Contrib rules
-Since gitlint 0.12.0, we support [Contrib rules](../contrib_rules): community contributed rules that are part of gitlint
+## Contrib rules
+Since gitlint 0.12.0, we support [Contrib rules](contrib_rules.md): community contributed rules that are part of gitlint
itself. Thanks for considering to add a new one to gitlint!
Before starting, please read all the other documentation on this page about contributing first.
Then, we suggest taking the following approach to add a Contrib rule:
-1. **Write your rule as a [user-defined rule](../user_defined_rules)**. In terms of code, Contrib rules are identical to
+1. **Write your rule as a [user-defined rule](user_defined_rules.md)**. In terms of code, Contrib rules are identical to
user-defined rules, they just happen to have their code sit within the gitlint codebase itself.
-2. **Add your user-defined rule to gitlint**. You should put your file(s) in the [gitlint/contrib/rules](https://github.com/jorisroovers/gitlint/tree/master/gitlint/contrib/rules) directory.
-3. **Write unit tests**. The gitlint codebase contains [Contrib rule test files you can copy and modify](https://github.com/jorisroovers/gitlint/tree/master/gitlint/tests/contrib).
-4. **Write documentation**. In particular, you should update the [gitlint/docs/contrib_rules.md](https://github.com/jorisroovers/gitlint/blob/master/docs/contrib_rules.md) file with details on your Contrib rule.
+2. **Add your user-defined rule to gitlint**. You should put your file(s) in the [gitlint/contrib/rules](https://github.com/jorisroovers/gitlint/tree/main/gitlint-core/gitlint/contrib/rules) directory.
+3. **Write unit tests**. The gitlint codebase contains [Contrib rule test files you can copy and modify](https://github.com/jorisroovers/gitlint/tree/main/gitlint-core/gitlint/tests/contrib/rules).
+4. **Write documentation**. In particular, you should update the [gitlint/docs/contrib_rules.md](https://github.com/jorisroovers/gitlint/blob/main/docs/contrib_rules.md) file with details on your Contrib rule.
5. **Create a Pull Request**: code review typically requires a bit of back and forth. Thanks for your contribution!
-## Contrib rule requirements
+### Contrib rule requirements
If you follow the steps above and follow the existing gitlint conventions wrt naming things, you should already be fairly close to done.
In case you're looking for a slightly more formal spec, here's what gitlint requires of Contrib rules.
-- Since Contrib rules are really just user-defined rules that live within the gitlint code-base, all the [user-rule requirements](../user_defined_rules/#rule-requirements) also apply to Contrib rules.
+- Since Contrib rules are really just user-defined rules that live within the gitlint code-base, all the [user-rule requirements](user_defined_rules.md#rule-requirements) also apply to Contrib rules.
- All contrib rules **must** have associated unit tests. We *sort of* enforce this by a unit test that verifies that there's a
test file for each contrib file.
- All contrib rules **must** have names that start with `contrib-`. This is to easily distinguish them from default gitlint rules.
@@ -129,4 +210,4 @@ In case you're looking for a slightly more formal spec, here's what gitlint requ
- All contrib rules **must** have unique names and ids.
- You **can** add multiple rule classes to the same file, but classes **should** be logically grouped together in a single file that implements related rules.
- Contrib rules **should** be meaningfully different from one another. If a behavior change or tweak can be added to an existing rule by adding options, that should be considered first. However, large [god classes](https://en.wikipedia.org/wiki/God_object) that implement multiple rules in a single class should obviously also be avoided.
-- Contrib rules **should** use [options](../user_defined_rules/#options) to make rules configurable.
+- Contrib rules **should** use [options](user_defined_rules.md#options) to make rules configurable.
diff --git a/docs/demos/asciicinema.json b/docs/demos/asciicinema.json
index b499765..a5664c7 100644
--- a/docs/demos/asciicinema.json
+++ b/docs/demos/asciicinema.json
@@ -1448,7 +1448,7 @@
],
[
0.002767,
- "\u001b[1;1H\u001b[93m 1 \r\n 2 \u001b[m\u001b[96m# Please enter the commit message for your changes. Lines starting\u001b[m\r\n\u001b[93m 3 \u001b[m\u001b[96m# with '#' will be ignored, and an empty message aborts the commit.\u001b[m\r\n\u001b[93m 4 \u001b[m\u001b[96m# On branch \u001b[m\u001b[38;5;224mmaster\u001b[m\r\n\u001b[93m 5 \u001b[m\u001b[96m# \u001b[m\u001b[38;5;81mChanges to be committed:\u001b[m\r\n\u001b[93m 6 \u001b[m\u001b[96m# \u001b[m\u001b[38;5;121mnew file\u001b[m\u001b[96m: \u001b[m\u001b[95m foo.txt\u001b[m\r\n\u001b[93m 7 \u001b[m\u001b[96m#\u001b[m\r\n\u001b[94m~ \u001b[9;1H~ \u001b[10;1H~ \u001b[11;1H~ \u001b[12;1H~ \u001b[13;1H~ "
+ "\u001b[1;1H\u001b[93m 1 \r\n 2 \u001b[m\u001b[96m# Please enter the commit message for your changes. Lines starting\u001b[m\r\n\u001b[93m 3 \u001b[m\u001b[96m# with '#' will be ignored, and an empty message aborts the commit.\u001b[m\r\n\u001b[93m 4 \u001b[m\u001b[96m# On branch \u001b[m\u001b[38;5;224mmain\u001b[m\r\n\u001b[93m 5 \u001b[m\u001b[96m# \u001b[m\u001b[38;5;81mChanges to be committed:\u001b[m\r\n\u001b[93m 6 \u001b[m\u001b[96m# \u001b[m\u001b[38;5;121mnew file\u001b[m\u001b[96m: \u001b[m\u001b[95m foo.txt\u001b[m\r\n\u001b[93m 7 \u001b[m\u001b[96m#\u001b[m\r\n\u001b[94m~ \u001b[9;1H~ \u001b[10;1H~ \u001b[11;1H~ \u001b[12;1H~ \u001b[13;1H~ "
],
[
0.000062,
@@ -2404,7 +2404,7 @@
],
[
0.052844,
- "1: T3 Title has trailing punctuation (!): \"WIP: This is an patchset that I need to continue working on!\"\r\n1: T5 Title contains the word 'WIP' (case-insensitive): \"WIP: This is an patchset that I need to continue working on!\"\r\n3: B6 Body message is missing\r\n"
+ "1: T3 Title has trailing punctuation (!): \"WIP: This is a patchset that I need to continue working on!\"\r\n1: T5 Title contains the word 'WIP' (case-insensitive): \"WIP: This is a patchset that I need to continue working on!\"\r\n3: B6 Body message is missing\r\n"
],
[
0.006075,
@@ -2412,7 +2412,7 @@
],
[
0.000020,
- "gitlint: \u001b[31mYour commit message contains the above violations.\u001b[0m\r\n"
+ "gitlint: \u001b[31mYour commit message contains violations.\u001b[0m\r\n"
],
[
0.002541,
@@ -2432,7 +2432,7 @@
],
[
0.004763,
- "[master 4b1f92d] WIP: This is an patchset that I need to continue working on!\r\n"
+ "[main 4b1f92d] WIP: This is a patchset that I need to continue working on!\r\n"
],
[
0.001504,
@@ -3108,11 +3108,11 @@
],
[
0.050694,
- "1: T1 Title exceeds max length (60\u003e50): \"WIP: This is an patchset that I need to continue working on!\"\r\n"
+ "1: T1 Title exceeds max length (60\u003e50): \"WIP: This is a patchset that I need to continue working on!\"\r\n"
],
[
0.000006,
- "1: T3 Title has trailing punctuation (!): \"WIP: This is an patchset that I need to continue working on!\"\r\n1: T5 Title contains the word 'WIP' (case-insensitive): \"WIP: This is an patchset that I need to continue working on!\"\r\n3: B6 Body message is missing\r\n"
+ "1: T3 Title has trailing punctuation (!): \"WIP: This is a patchset that I need to continue working on!\"\r\n1: T5 Title contains the word 'WIP' (case-insensitive): \"WIP: This is a patchset that I need to continue working on!\"\r\n3: B6 Body message is missing\r\n"
],
[
0.005418,
@@ -3508,7 +3508,7 @@
],
[
0.050989,
- "1: T1 Title exceeds max length (60\u003e50): \"WIP: This is an patchset that I need to continue working on!\"\r\n1: T5 Title contains the word 'WIP' (case-insensitive): \"WIP: This is an patchset that I need to continue working on!\"\r\n"
+ "1: T1 Title exceeds max length (60\u003e50): \"WIP: This is a patchset that I need to continue working on!\"\r\n1: T5 Title contains the word 'WIP' (case-insensitive): \"WIP: This is a patchset that I need to continue working on!\"\r\n"
],
[
0.000025,
@@ -3795,4 +3795,4 @@
"exit\r\n"
]
]
-}
+} \ No newline at end of file
diff --git a/docs/extra.css b/docs/extra.css
index 5643925..12a7663 100644
--- a/docs/extra.css
+++ b/docs/extra.css
@@ -2,3 +2,11 @@ a.toctree-l3 {
margin-left: 10px;
/* display: none; */
}
+
+.wy-nav-content {
+ max-width: 1000px;
+}
+
+.document hr {
+ border-top: 1px solid #666;
+} \ No newline at end of file
diff --git a/docs/extra.js b/docs/extra.js
new file mode 100644
index 0000000..4af1fa4
--- /dev/null
+++ b/docs/extra.js
@@ -0,0 +1,5 @@
+document.addEventListener("DOMContentLoaded", function () {
+ document.querySelectorAll("table").forEach(function (table) {
+ table.classList.add("docutils");
+ });
+}); \ No newline at end of file
diff --git a/docs/images/dev-container.png b/docs/images/dev-container.png
new file mode 100644
index 0000000..6cac5a2
--- /dev/null
+++ b/docs/images/dev-container.png
Binary files differ
diff --git a/docs/images/gitlint-packages.drawio.svg b/docs/images/gitlint-packages.drawio.svg
new file mode 100644
index 0000000..6098e3d
--- /dev/null
+++ b/docs/images/gitlint-packages.drawio.svg
@@ -0,0 +1,351 @@
+<svg host="65bd71144e" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="491px" height="391px" viewBox="-0.5 -0.5 491 391" content="&lt;mxfile&gt;&lt;diagram id=&quot;x7jBp0SZ1TbX-vMHKkT6&quot; name=&quot;Page-1&quot;&gt;7Vtbb+o4EP41SGcfQEmccHks0O4e6axUbbW3p5VLDFg1MccxBc6vX9+SkNiUAEkvu62q4owvib/5ZjwzoR0wWe1+ZnC9/JXGiHQCL951wLQTBFHoi79SsNeCsB9owYLhWIv8QvCAfyAj9Ix0g2OUlgZySgnH67JwRpMEzXhJBhmj2/KwOSXlu67hAlmChxkktvRPHPOllg6DQSH/BeHFMruz3x/pnhXMBpudpEsY0+2BCNx2wIRRynVrtZsgIrHLcNHz7o705g/GUMLrTAB6wjMkG7O3TtAnYur4UTQWsrHAnOCEd2eUoaxTLJj3m43wfYbOdok5eljDmbzeCgKIQUu+IuLKF01I8CIRbaYBGj8jxrHA9sbIOZUTUjEfJ4vfDIogv5EcjnZHt+vnIAryIbpCnO3FEDMhZ5AhHsj0sC3UGAyNbHmgwiAyQmios8jXLtAVDQOwG+zQAfZl2BE05wVI39TVtN8QRiAqYzSwMfI9B0a58BqMoqOExAXhtGBOxYakkRPK1ND+9w3VA8B87nnycQqRnsvZJuUo7sZIuIqCzHqp8vJCjC/luJvTDSgHDN5SOYPT3gLtOIP/MPR9gxlKa/kLgQZ303wmUEHMgecKx7GcPhb3wD/go1rKE9drKlyV2mE07kRTudaG01SfIHLplDP6hCaGMwlN5CpzTEhF1IiuKs4mqqmroAFVDU+rCicph4R8KkthHozeTlkjS1kPdMOEbwm8iYidOsFEtr59FX/FdtRjK+x0B+Kzc/1TI8dEmd3hyHGUhpENWL8BwLJj3EHvGD9n5J0QPHuSvWA67Hk9kFsAq/p6cZAmmUwFiHqW3wt6vj2r1+sd2Mrh3APxwXOcYUTmYP+QJgSGFUZ4NiNGDgtqIrTy/fqECPpwJe1B60Zw4xxeVCd/0qO2wwhP02PQFj3sPOd+f/9VPf/sSWZ7ZzpQRjdJjOLm3KlfMR7g1zOeJo4fv386WDBZ4H8tAfRHvn1quRLAUdQAzsFHY6E/tOFpjYV2FHQps14zPRYBjc0gV6AYNsCg4Hjc8xnW1wnrA8/WVmthvW8nYaViWpQHBG9a25Aqkr9ezx/0vGPUeIWMIgRlXQHQi2xtjRw5BWhCW6G1dRQv0IO5pIwv6YImkNwWUhsBOeXl/Qceh2yBsujGDQlDBHL8XF7KtTsz9V6ng3koHpX9uJV0pSq/NLMKjG4Yg/uDYcaUz77PXc3xYbk8LRr6CQqF5ZjU848jS4cHGpKWcAdXmMi7/4FYDBNoxJPc0MDdnTIvMFap9l/GqamLv5WVRNnldHfYOd2bq8uIAAatMCF3bpmGwmEtJtgLDU4spDdjLXSJFl3JXEWt6RKuZRPOuFTcKfdUjpSOabwBJ1Y1iCB0+LDQFR4MGggP7ADzowIXOvKf1mA7/tJBZ+8H+GWHrkSiOzfO5EY9FHlGMkBScHiqX8c8stcP1ruDjq3ZgewKDYIeQVxEWl0TterOhLIVJLpfHsRdE5bJvjwyy/qw0FRiVvWy+6kezmCSzsVa2aomvvK2lMXlO+YTY5yuCTS7w4kIW8ycOaGQVxaqxiJWYLPGa7WMik1Fy84nrRjIKp5cFJg44sr6oW2F755n+E7gIyJjkbQtlH2UTEL+NBQQVXzJ0DYJZ+zaRDT0wguET5to1yaqb9rbMowj3K5vHa9jBX453w5dbzxBS1YAjpeV350VvCOm/54iBQ3DMxlBioQUyYebYVmN8L6saCrFmxSx9KdmSW2R1+H+r+HzMaO5hud5rc1B7H5bxHZFip/ErkdsQqn6LPO6+hroC5Qk34v0SnwwnD41TPV377+zNxn91+Q1sNC8vADQqZnIt560h0Ul7Ny0PbCXKi/UXNoO+hb2ZxXQ8npL1+t5Xl5l0UUXH5youqire8SweGJJeyWsp/CKFz+3chO2woHqm6qwah4NlfCqWUZ2n6OEqowHQ1DhzXUlPFDjW5JiBl6n6NzqRc3z/WzCXJnkVUuirqp34PCXTbyiAC8WTC+tgLZmdprznYOCadkU9TvEK2yxNm6ur0L+j1gqzL4tjorL4vvv2oEU/0QAbv8F&lt;/diagram&gt;&lt;/mxfile&gt;">
+ <defs/>
+ <g>
+ <rect x="210" y="140" width="280" height="250" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/>
+ <g transform="translate(-0.5 -0.5)">
+ <switch>
+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe flex-end; width: 275px; height: 1px; padding-top: 147px; margin-left: 210px;">
+ <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: right;">
+ <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
+ <b>
+ gitlint-core
+ </b>
+ </div>
+ </div>
+ </div>
+ </foreignObject>
+ <text x="485" y="159" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="end">
+ gitlint-core
+ </text>
+ </switch>
+ </g>
+ <rect x="235" y="190" width="100" height="100" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/>
+ <rect x="375" y="190" width="100" height="100" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/>
+ <g transform="translate(-0.5 -0.5)">
+ <switch>
+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 197px; margin-left: 376px;">
+ <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
+ <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
+ <i>
+ <font color="#ff0000">
+ trusted-deps
+ </font>
+ </i>
+ </div>
+ </div>
+ </div>
+ </foreignObject>
+ <text x="425" y="209" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
+ trusted-deps
+ </text>
+ </switch>
+ </g>
+ <rect x="370" y="170" width="100" height="20" fill="none" stroke="none" pointer-events="all"/>
+ <g transform="translate(-0.5 -0.5)">
+ <switch>
+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 180px; margin-left: 420px;">
+ <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
+ <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;">
+ <b>
+ extra_requires
+ </b>
+ </div>
+ </div>
+ </div>
+ </foreignObject>
+ <text x="420" y="184" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
+ extra_requires
+ </text>
+ </switch>
+ </g>
+ <rect x="229" y="170" width="100" height="20" fill="none" stroke="none" pointer-events="all"/>
+ <g transform="translate(-0.5 -0.5)">
+ <switch>
+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 180px; margin-left: 279px;">
+ <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
+ <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;">
+ <b>
+ install_requires
+ </b>
+ </div>
+ </div>
+ </div>
+ </foreignObject>
+ <text x="279" y="184" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
+ install_requires
+ </text>
+ </switch>
+ </g>
+ <rect x="230" y="310" width="245" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/>
+ <g transform="translate(-0.5 -0.5)">
+ <switch>
+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 243px; height: 1px; padding-top: 340px; margin-left: 231px;">
+ <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
+ <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
+ Source Code, CLI entry point, etc
+ </div>
+ </div>
+ </div>
+ </foreignObject>
+ <text x="353" y="344" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
+ Source Code, CLI entry point, etc
+ </text>
+ </switch>
+ </g>
+ <rect x="380" y="220" width="90" height="50" fill="none" stroke="none" pointer-events="all"/>
+ <g transform="translate(-0.5 -0.5)">
+ <switch>
+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 1px; height: 1px; padding-top: 245px; margin-left: 382px;">
+ <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left;">
+ <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;">
+ <div>
+ Click==8.0.3
+ <br/>
+ <span>
+ arrow==1.2.1
+ <br/>
+ ...
+ </span>
+ </div>
+ </div>
+ </div>
+ </div>
+ </foreignObject>
+ <text x="382" y="249" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px">
+ Click==8.0.3...
+ </text>
+ </switch>
+ </g>
+ <rect x="240" y="220" width="70" height="50" fill="none" stroke="none" pointer-events="all"/>
+ <g transform="translate(-0.5 -0.5)">
+ <switch>
+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 1px; height: 1px; padding-top: 245px; margin-left: 242px;">
+ <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left;">
+ <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;">
+ <div>
+ Click&gt;=8
+ <br/>
+ <span>
+ arrow&gt;=1
+ <br/>
+ ...
+ </span>
+ </div>
+ </div>
+ </div>
+ </div>
+ </foreignObject>
+ <text x="242" y="249" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px">
+ Click&gt;=8...
+ </text>
+ </switch>
+ </g>
+ <rect x="180" y="130" width="90" height="20" rx="3" ry="3" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/>
+ <g transform="translate(-0.5 -0.5)">
+ <switch>
+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 140px; margin-left: 181px;">
+ <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
+ <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
+ PyPI package
+ </div>
+ </div>
+ </div>
+ </foreignObject>
+ <text x="225" y="144" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
+ PyPI package
+ </text>
+ </switch>
+ </g>
+ <rect x="210" y="11" width="280" height="95" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/>
+ <g transform="translate(-0.5 -0.5)">
+ <switch>
+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe flex-end; width: 275px; height: 1px; padding-top: 18px; margin-left: 210px;">
+ <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: right;">
+ <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
+ <b>
+ gitlint
+ </b>
+ </div>
+ </div>
+ </div>
+ </foreignObject>
+ <text x="485" y="30" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="end">
+ gitlint
+ </text>
+ </switch>
+ </g>
+ <rect x="180" y="1" width="90" height="20" rx="3" ry="3" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/>
+ <g transform="translate(-0.5 -0.5)">
+ <switch>
+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 11px; margin-left: 181px;">
+ <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
+ <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
+ PyPI package
+ </div>
+ </div>
+ </div>
+ </foreignObject>
+ <text x="225" y="15" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
+ PyPI package
+ </text>
+ </switch>
+ </g>
+ <rect x="235" y="46" width="200" height="45" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/>
+ <rect x="229" y="26" width="100" height="20" fill="none" stroke="none" pointer-events="all"/>
+ <g transform="translate(-0.5 -0.5)">
+ <switch>
+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 36px; margin-left: 279px;">
+ <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
+ <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;">
+ <b>
+ install_requires
+ </b>
+ </div>
+ </div>
+ </div>
+ </foreignObject>
+ <text x="279" y="40" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
+ install_requires
+ </text>
+ </switch>
+ </g>
+ <rect x="243" y="53.5" width="195" height="30" fill="none" stroke="none" pointer-events="all"/>
+ <g transform="translate(-0.5 -0.5)">
+ <switch>
+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe flex-start; width: 193px; height: 1px; padding-top: 61px; margin-left: 245px;">
+ <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left;">
+ <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
+ gitlint-core[
+ <i>
+ <font color="#ff0000">
+ trusted-deps
+ </font>
+ </i>
+ ]==0.17.0
+ </div>
+ </div>
+ </div>
+ </foreignObject>
+ <text x="245" y="73" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px">
+ gitlint-core[trusted-deps]==0.17...
+ </text>
+ </switch>
+ </g>
+ <path d="M 350 80 L 350 230 Q 350 240 359.32 240 L 368.63 240" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/>
+ <path d="M 373.88 240 L 366.88 243.5 L 368.63 240 L 366.88 236.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/>
+ <path d="M 100 68 L 193.63 68" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/>
+ <path d="M 198.88 68 L 191.88 71.5 L 193.63 68 L 191.88 64.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/>
+ <path d="M 50 91.5 C 50 72.7 50 63.3 70 63.3 C 56.67 63.3 56.67 44.5 70 44.5 C 83.33 44.5 83.33 63.3 70 63.3 C 90 63.3 90 72.7 90 91.5 Z" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/>
+ <path d="M 50 277 C 50 258.2 50 248.8 70 248.8 C 56.67 248.8 56.67 230 70 230 C 83.33 230 83.33 248.8 70 248.8 C 90 248.8 90 258.2 90 277 Z" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/>
+ <rect x="20" y="100" width="100" height="30" fill="none" stroke="none" pointer-events="all"/>
+ <g transform="translate(-0.5 -0.5)">
+ <switch>
+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 115px; margin-left: 21px;">
+ <div data-drawio-colors="color: #000000; background-color: #FFFFFF; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
+ <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: normal; overflow-wrap: normal;">
+ <span style="font-family: &quot;helvetica&quot; ; font-size: 12px ; font-weight: 400 ; letter-spacing: normal ; text-align: center ; text-indent: 0px ; text-transform: none ; word-spacing: 0px ; display: inline ; float: none">
+ <i>
+ pip install gitlint
+ </i>
+ </span>
+ </div>
+ </div>
+ </div>
+ </foreignObject>
+ <text x="70" y="119" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
+ pip install gitl...
+ </text>
+ </switch>
+ </g>
+ <rect x="15" y="290" width="130" height="30" fill="none" stroke="none" pointer-events="all"/>
+ <g transform="translate(-0.5 -0.5)">
+ <switch>
+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 305px; margin-left: 16px;">
+ <div data-drawio-colors="color: #000000; background-color: #FFFFFF; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
+ <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: normal; overflow-wrap: normal;">
+ <span style="font-family: &quot;helvetica&quot; ; font-size: 12px ; font-weight: 400 ; letter-spacing: normal ; text-align: center ; text-indent: 0px ; text-transform: none ; word-spacing: 0px ; display: inline ; float: none">
+ <i>
+ pip install gitlint-core
+ </i>
+ </span>
+ </div>
+ </div>
+ </div>
+ </foreignObject>
+ <text x="80" y="309" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
+ pip install gitlint-c...
+ </text>
+ </switch>
+ </g>
+ <rect x="0" y="0" width="160" height="30" fill="none" stroke="none" pointer-events="all"/>
+ <g transform="translate(-0.5 -0.5)">
+ <switch>
+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 15px; margin-left: 1px;">
+ <div data-drawio-colors="color: #000000; background-color: #FFFFFF; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
+ <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: normal; overflow-wrap: normal;">
+ <span style="font-family: &quot;helvetica&quot; ; font-size: 12px ; font-weight: 400 ; letter-spacing: normal ; text-indent: 0px ; text-transform: none ; word-spacing: 0px ; display: inline ; float: none">
+ Use strict dependencies (most users)
+ </span>
+ </div>
+ </div>
+ </div>
+ </foreignObject>
+ <text x="80" y="19" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
+ Use strict dependencies (m...
+ </text>
+ </switch>
+ </g>
+ <rect x="0" y="180" width="160" height="30" fill="none" stroke="none" pointer-events="all"/>
+ <g transform="translate(-0.5 -0.5)">
+ <switch>
+ <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
+ <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 195px; margin-left: 1px;">
+ <div data-drawio-colors="color: #000000; background-color: #FFFFFF; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
+ <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: normal; overflow-wrap: normal;">
+ <span style="font-family: &quot;helvetica&quot; ; font-size: 12px ; font-weight: 400 ; letter-spacing: normal ; text-indent: 0px ; text-transform: none ; word-spacing: 0px ; display: inline ; float: none">
+ Use loose dependencies
+ <br/>
+ (at your risk)
+ </span>
+ </div>
+ </div>
+ </div>
+ </foreignObject>
+ <text x="80" y="199" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
+ Use loose dependencies...
+ </text>
+ </switch>
+ </g>
+ <path d="M 100 253.5 L 193.63 253.03" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/>
+ <path d="M 198.88 253.01 L 191.9 256.54 L 193.63 253.03 L 191.86 249.54 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/>
+ <path d="M 210 250 L 215 250 Q 220 250 220 240 L 220 213 Q 220 203 224.07 203 L 228.13 203" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/>
+ <path d="M 233.38 203 L 226.38 206.5 L 228.13 203 L 226.38 199.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/>
+ <ellipse cx="210" cy="253.5" rx="10" ry="10" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/>
+ <path d="M 220 68 L 228.64 68.29" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/>
+ <path d="M 233.88 68.46 L 226.77 71.73 L 228.64 68.29 L 227 64.73 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/>
+ <ellipse cx="210" cy="68" rx="10" ry="10" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/>
+ </g>
+ <switch>
+ <g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/>
+ <a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank">
+ <text text-anchor="middle" font-size="10px" x="50%" y="100%">
+ Viewer does not support full SVG 1.1
+ </text>
+ </a>
+ </switch>
+</svg> \ No newline at end of file
diff --git a/docs/images/gitlint-packages.png b/docs/images/gitlint-packages.png
new file mode 100644
index 0000000..00d3ec1
--- /dev/null
+++ b/docs/images/gitlint-packages.png
Binary files differ
diff --git a/docs/images/readme-gitlint.png b/docs/images/readme-gitlint.png
new file mode 100644
index 0000000..516c915
--- /dev/null
+++ b/docs/images/readme-gitlint.png
Binary files differ
diff --git a/docs/index.md b/docs/index.md
index 3155b19..b735b6b 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,4 +1,4 @@
-# Intro
+# Introduction
Gitlint is a git commit message linter written in python: it checks your commit messages for style.
Great for use as a [commit-msg git hook](#using-gitlint-as-a-commit-msg-hook) or as part of your gating script in a
@@ -7,46 +7,55 @@ Great for use as a [commit-msg git hook](#using-gitlint-as-a-commit-msg-hook) or
<script type="text/javascript" src="https://asciinema.org/a/30477.js" id="asciicast-30477" async></script>
!!! note
- **Gitlint support for Windows is experimental**, and [there are some known issues](https://github.com/jorisroovers/gitlint/issues?q=is%3Aissue+is%3Aopen+label%3Awindows).
+ **Gitlint works on Windows**, but [there are some known issues](https://github.com/jorisroovers/gitlint/issues?q=is%3Aissue+is%3Aopen+label%3Awindows).
Also, 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),
[node-commit-msg](https://github.com/clns/node-commit-msg) (Node.js) or [commitlint](http://marionebl.github.io/commitlint) (Node.js).
-## Features ##
+
+!!! important
+ **Gitlint requires Python 3.7 (or above). For Python 2.7 and Python 3.5 use `gitlint==0.14.0` (released 2020-10-24), for Python 3.6 `gitlint==0.18.0` (released 2022-11-16).**
+
+## Features
- **Commit message hook**: [Auto-trigger validations against new commit message right when you're committing](#using-gitlint-as-a-commit-msg-hook). Also [works with pre-commit](#using-gitlint-through-pre-commit).
- **Easily integrated**: Gitlint is designed to work [with your own scripts or CI system](#using-gitlint-in-a-ci-environment).
- **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/2013/06/05/good-commit-messages-and-enforcing-them-with-git-hooks.html),
+[community](https://addamhardy.com/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.
- **Easily configurable:** Gitlint has sane defaults, but [you can also easily customize it to your own liking](configuration.md).
- - **Community contributed rules**: Conventions that are common but not universal [can be selectively enabled](contrib_rules).
+ - **Community contributed rules**: Conventions that are common but not universal [can be selectively enabled](contrib_rules.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.md).
- - **Broad python version support:** Gitlint supports python versions 2.7, 3.5+, PyPy2 and PyPy3.5.
- **Full unicode support:** Lint your Russian, Chinese or Emoji commit messages with ease!
- **Production-ready:** Gitlint checks a lot of the boxes you're looking for: actively maintained, high unit test coverage, integration tests,
- python code standards (pep8, pylint), good documentation, widely used, proven track record.
+ python code standards ([black](https://github.com/psf/black), [ruff](https://github.com/charliermarsh/ruff)),
+ good documentation, widely used, proven track record.
-# Getting Started
-## Installation
-```bash
+## Getting Started
+### Installation
+```sh
# Pip is recommended to install the latest version
pip install gitlint
-# macOS
-brew tap rockyluke/devops
-brew install gitlint
+# Alternative: by default, gitlint is installed with pinned dependencies.
+# To install gitlint with looser dependency requirements, only install gitlint-core.
+pip install gitlint-core
-# Ubuntu
-apt-get install gitlint
+# Community maintained packages:
+brew install gitlint # Homebrew (macOS)
+sudo port install gitlint # Macports (macOS)
+apt-get install gitlint # Ubuntu
+# Other package managers, see https://repology.org/project/gitlint/versions
# Docker: https://hub.docker.com/r/jorisroovers/gitlint
-docker run -v $(pwd):/repo jorisroovers/gitlint
+docker run --ulimit nofile=1024 -v $(pwd):/repo jorisroovers/gitlint
+# NOTE: --ulimit is required to work around a limitation in Docker
+# Details: https://github.com/jorisroovers/gitlint/issues/129
```
-## Usage
+### Usage
```sh
# Check the last commit message
gitlint
@@ -64,7 +73,7 @@ gitlint install-hook
```
Output example:
-```bash
+```sh
$ cat examples/commit-message-2 | gitlint
1: T1 Title exceeds max length (134>80): "This is the title of a commit message that is over 80 characters and contains hard tabs and trailing whitespace and the word wiping "
1: T2 Title has trailing whitespace: "This is the title of a commit message that is over 80 characters and contains hard tabs and trailing whitespace and the word wiping "
@@ -77,11 +86,24 @@ $ cat examples/commit-message-2 | gitlint
!!! note
The returned exit code equals the number of errors found. [Some exit codes are special](index.md#exit-codes).
-# Configuration
+### Shell completion
+
+```sh
+# Bash: add to ~/.bashrc
+eval "$(_GITLINT_COMPLETE=bash_source gitlint)"
+
+# Zsh: add to ~/.zshrc
+eval "$(_GITLINT_COMPLETE=zsh_source gitlint)"
+
+# Fish: add to ~/.config/fish/completions/foo-bar.fish
+eval (env _GITLINT_COMPLETE=fish_source gitlint)
+```
+
+## Configuration
For in-depth documentation of general and rule-specific configuration options, have a look at the [Configuration](configuration.md) and [Rules](rules.md) pages.
-Short example ```.gitlint``` file ([full reference](configuration.md)):
+Short example `.gitlint` file ([full reference](configuration.md)):
```ini
[general]
@@ -89,7 +111,7 @@ Short example ```.gitlint``` file ([full reference](configuration.md)):
# their id or by their full name
ignore=body-is-missing,T3
-# Ignore any data send to gitlint via stdin
+# Ignore any data sent to gitlint via stdin
ignore-stdin=true
# Configure title-max-length rule, set title length to 80 (72 = default)
@@ -103,7 +125,7 @@ line-length=123
Example use of flags:
-```bash
+```sh
# Change gitlint's verbosity.
$ gitlint -v
# Ignore certain rules
@@ -129,9 +151,11 @@ Options:
current working directory]
-C, --config FILE 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 set multiple config values.
- --commits TEXT The range of commits to lint. [default: HEAD]
+ (e.g.: -c T1.line-length=80). Flag can be
+ used multiple times to set multiple config values.
+ --commit TEXT Hash (SHA) of specific commit to lint.
+ --commits TEXT The range of commits (refspec or comma-separated
+ hashes) to lint. [default: HEAD]
-e, --extra-path PATH Path to a directory or python module with extra
user-defined rules
--ignore TEXT Ignore rules (comma-separated by id or name).
@@ -140,12 +164,14 @@ Options:
--msg-filename FILENAME Path to a file containing a commit-msg.
--ignore-stdin Ignore any stdin data. Useful for running in CI
server.
- --staged Read staged commit meta-info from the local
- repository.
- -v, --verbose Verbosity, more v's for more verbose output (e.g.:
- -v, -vv, -vvv). [default: -vvv]
- -s, --silent Silent mode (no output). Takes precedence over -v,
- -vv, -vvv.
+ --staged Attempt smart guesses about meta info (like
+ author name, email, branch, changed files, etc)
+ for staged commits.
+ --fail-without-commits Hard fail when the target commit range is empty.
+ -v, --verbose Verbosity, more v's for more verbose output
+ (e.g.: -v, -vv, -vvv). [default: -vvv]
+ -s, --silent Silent mode (no output).
+ Takes precedence over -v, -vv, -vvv.
-d, --debug Enable debugging output.
--version Show the version and exit.
--help Show this message and exit.
@@ -154,19 +180,20 @@ Commands:
generate-config Generates a sample gitlint config file.
install-hook Install gitlint as a git commit-msg hook.
lint Lints a git repository [default command]
+ run-hook Runs the gitlint commit-msg hook.
uninstall-hook Uninstall gitlint commit-msg hook.
When no COMMAND is specified, gitlint defaults to 'gitlint lint'.
```
-# Using gitlint as a commit-msg hook ##
+## Using gitlint as a commit-msg hook
_Introduced in gitlint v0.4.0_
-You can also install gitlint as a git ```commit-msg``` hook so that gitlint checks your commit messages automatically
+You can also install gitlint as a git `commit-msg` hook so that gitlint checks your commit messages automatically
after each commit.
-```bash
+```sh
gitlint install-hook
# To remove the hook
gitlint uninstall-hook
@@ -174,13 +201,13 @@ 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
+ 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.
If you're looking to use gitlint in conjunction with other hooks, you should consider
[using gitlint with pre-commit](#using-gitlint-through-pre-commit).
-# Using gitlint through [pre-commit](https://pre-commit.com)
+## Using gitlint through [pre-commit](https://pre-commit.com)
`gitlint` can be configured as a plugin for the `pre-commit` git hooks
framework. Simply add the configuration to your `.pre-commit-config.yaml`:
@@ -198,10 +225,10 @@ pre-commit install --hook-type commit-msg
```
!!! important
- It's important that you run ```pre-commit install --hook-type commit-msg```, even if you've already used
- ```pre-commit install``` before. ```pre-commit install``` does **not** install commit-msg hooks by default!
+ It's important that you run `pre-commit install --hook-type commit-msg`, even if you've already used
+ `pre-commit install` before. `pre-commit install` does **not** install commit-msg hooks by default!
-To manually trigger gitlint using ```pre-commit``` for your last commit message, use the following command:
+To manually trigger gitlint using `pre-commit` for your last commit message, use the following command:
```sh
pre-commit run gitlint --hook-stage commit-msg --commit-msg-filename .git/COMMIT_EDITMSG
```
@@ -211,16 +238,49 @@ In case you want to change gitlint's behavior, you should either use a `.gitlint
your `.pre-commit-config.yaml` file like so:
```yaml
- repo: https://github.com/jorisroovers/gitlint
- rev: # Fill in a tag / sha here
+ rev: # Fill in a tag / sha here (e.g. v0.18.0)
hooks:
- id: gitlint
- stages: [commit-msg]
- entry: gitlint
args: [--contrib=CT1, --msg-filename]
```
-# Using gitlint in a CI environment ##
-By default, when just running ```gitlint``` without additional parameters, gitlint lints the last commit in the current
+!!! important
+
+ You need to add `--msg-filename` at the end of your custom `args` list as the gitlint-hook will fail otherwise.
+
+
+### gitlint and pre-commit in CI
+gitlint also supports a `gitlint-ci` pre-commit hook that can be used in CI environments.
+
+Configure it like so:
+```yaml
+- repo: https://github.com/jorisroovers/gitlint
+ rev: # insert ref, e.g. v0.18.0
+ hooks:
+ - id: gitlint # this is the regular commit-msg hook
+ - id: gitlint-ci # hook for CI environments
+```
+
+And invoke it in your CI environment like this:
+
+```sh
+pre-commit run --hook-stage manual gitlint-ci
+```
+
+By default this will only lint the latest commit.
+If you want to lint more commits you can modify the `gitlint-ci` hook like so:
+
+```yaml
+- repo: https://github.com/jorisroovers/gitlint
+ rev: # insert ref, e.g. v0.18.0
+ hooks:
+ - id: gitlint
+ - id: gitlint-ci
+ args: [--debug, --commits, mybranch] # enable debug mode, lint all commits in mybranch
+```
+
+## Using gitlint in a CI environment
+By default, when just running `gitlint` without additional parameters, gitlint lints the last commit in the current
working directory.
This makes it easy to use gitlint in a CI environment (Jenkins, TravisCI, Github Actions, pre-commit, CircleCI, Gitlab, etc).
@@ -229,59 +289,76 @@ In fact, this is exactly what we do ourselves: on every commit,
This will cause the build to fail when we submit a bad commit message.
Alternatively, gitlint will also lint any commit message that you feed it via stdin like so:
-```bash
+```sh
# lint the last commit message
git log -1 --pretty=%B | gitlint
# lint a specific commit: 62c0519
git log -1 --pretty=%B 62c0519 | gitlint
```
-Note that gitlint requires that you specify ```--pretty=%B``` (=only print the log message, not the metadata),
-future versions of gitlint might fix this and not require the ```--pretty``` argument.
+Note that gitlint requires that you specify `--pretty=%B` (=only print the log message, not the metadata),
+future versions of gitlint might fix this and not require the `--pretty` argument.
-## Linting a range of commits ##
+## Linting specific commits or branches
-_Introduced in gitlint v0.9.0 (experimental in v0.8.0)_
+Gitlint can lint specific commits using `--commit`:
+```sh
+gitlint --commit 019cf40580a471a3958d3c346aa8bfd265fe5e16
+gitlint --commit 019cf40 # short SHAs work too
+gitlint --commit HEAD~2 # as do special references
+gitlint --commit mybranch # lint latest commit on a branch
+```
-Gitlint allows users to commit a number of commits at once like so:
+You can also lint multiple commits using `--commits` (plural):
-```bash
+```sh
# Lint a specific commit range:
gitlint --commits "019cf40...d6bc75a"
-# You can also use git's special references:
-gitlint --commits "origin..HEAD"
-# Or specify a single specific commit in refspec format, like so:
-gitlint --commits "019cf40^...019cf40"
+# Lint all commits on a branch
+gitlint --commits mybranch
+# Lint all commits that are different between a branch and your main branch
+gitlint --commits "main..mybranch"
+# Use git's special references
+gitlint --commits "origin/main..HEAD"
+
+# You can also pass multiple, comma separated commit hashes:
+gitlint --commits 019cf40,c50eb150,d6bc75a
+# These can include special references as well
+gitlint --commits HEAD~1,mybranch-name,origin/main,d6bc75a
+# You can also lint a single commit with --commits:
+gitling --commits 019cf40,
```
-The ```--commits``` flag takes a **single** refspec argument or commit range. Basically, any range that is understood
+The `--commits` flag takes a **single** refspec argument or commit range. Basically, any range that is understood
by [git rev-list](https://git-scm.com/docs/git-rev-list) as a single argument will work.
-Prior to v0.8.1 gitlint didn't support this feature. However, older versions of gitlint can still lint a range or set
-of commits at once by creating a simple bash script that pipes the commit messages one by one into gitlint. This
-approach can still be used with newer versions of gitlint in case ```--commits``` doesn't provide the flexibility you
-are looking for.
+Alternatively, you can pass `--commits` a comma-separated list of commit hashes (both short and full-length SHAs work,
+as well as special references such as `HEAD` and branch names).
+Gitlint will treat these as pointers to **single** commits and lint these in the order you passed.
+`--commits` also accepts a single commit SHA with a trailing comma.
-```bash
-#!/bin/bash
+For cases where the `--commits` option doesn't provide the flexibility you need, you can always use a simple shell
+script to lint an arbitrary set of commits, like shown in the example below.
-for commit in $(git rev-list master); do
- commit_msg=$(git log -1 --pretty=%B $commit)
- echo "$commit"
- echo "$commit_msg" | gitlint
+```sh
+#!/bin/sh
+
+for commit in $(git rev-list my-branch); do
+ echo "Commit $commit"
+ gitlint --commit $commit
echo "--------"
done
```
!!! note
One downside to this approach is that you invoke gitlint once per commit vs. once per set of commits.
- This means you'll incur the gitlint startup time once per commit, making this approach rather slow if you want to
- lint a large set of commits. Always use ```--commits``` if you can to avoid this performance penalty.
+ This means you'll incur the gitlint startup time once per commit, making it rather slow if you want to
+ lint a large set of commits. Always use `--commits` if you can to avoid this performance penalty.
-# Merge, fixup and squash commits ##
-_Introduced in gitlint v0.7.0 (merge), v0.9.0 (fixup, squash) and v0.13.0 (revert)_
+## Merge, fixup, squash and revert commits
+_Introduced in gitlint v0.7.0 (merge), v0.9.0 (fixup, squash), v0.13.0 (revert) and v0.18.0 (fixup=amend)_
-**Gitlint ignores merge, revert, fixup and squash commits by default.**
+**Gitlint ignores merge, revert, fixup, and squash commits by default.**
For merge and revert commits, the rationale for ignoring them is
that most users keep git's default messages for these commits (i.e *Merge/Revert "[original commit message]"*).
@@ -291,28 +368,26 @@ For example, a common case is that *"Merge:"* being auto-prepended triggers a
[title-max-length](rules.md#t1-title-max-length) violation. Most users don't want this, so we disable linting
on Merge and Revert commits by default.
-For [squash](https://git-scm.com/docs/git-commit#git-commit---squashltcommitgt) and [fixup](https://git-scm.com/docs/git-commit#git-commit---fixupltcommitgt) commits, the rationale is that these are temporary
+For [squash](https://git-scm.com/docs/git-commit#git-commit---squashltcommitgt) and [fixup](https://git-scm.com/docs/git-commit#git-commit---fixupltcommitgt) (including [fixup=amend](https://git-scm.com/docs/git-commit#Documentation/git-commit.txt---fixupamendrewordltcommitgt)) commits, the rationale is that these are temporary
commits that will be squashed into a different commit, and hence the commit messages for these commits are very
-short-lived and not intended to make it into the final commit history. In addition, by prepending *"fixup!"* or
-*"squash!"* to your commit message, certain gitlint rules might be violated
+short-lived and not intended to make it into the final commit history. In addition, by prepending *"fixup!"*,
+*"amend!"* or *"squash!"* to your commit message, certain gitlint rules might be violated
(e.g. [title-max-length](rules.md#t1-title-max-length)) which is often undesirable.
In case you *do* want to lint these commit messages, you can disable this behavior by setting the
-general ```ignore-merge-commits```, ```ignore-revert-commits```, ```ignore-fixup-commits``` or
-```ignore-squash-commits``` option to ```false```
+general `ignore-merge-commits`, `ignore-revert-commits`, `ignore-fixup-commits`, `ignore-fixup-amend-commits` or
+`ignore-squash-commits` option to `false`
[using one of the various ways to configure gitlint](configuration.md).
-# Ignoring commits ##
-_Introduced in gitlint v0.10.0_
+## Ignoring commits
-You can configure gitlint to ignore specific commits.
+You can configure gitlint to ignore specific commits or parts of a commit.
-One way to do this, is to by [adding a gitline-ignore line to your commit message](configuration.md#commit-specific-config).
+One way to do this, is by [adding a gitlint-ignore line to your commit message](configuration.md#commit-specific-config).
If you have a case where you want to ignore a certain type of commits all-together, you can
use gitlint's *ignore* rules.
-Here's an example gitlint file that configures gitlint to ignore rules ```title-max-length``` and ```body-min-length```
-for all commits with a title starting with *"Release"*.
+Here's a few examples snippets from a `.gitlint` file:
```ini
[ignore-by-title]
@@ -326,15 +401,95 @@ ignore=title-max-length,body-min-length
# Match commits message bodies that have a line that contains 'release'
regex=(.*)release(.*)
ignore=all
+
+[ignore-by-author-name]
+# Match commits by author name (e.g. ignore all rules when a commit is made by dependabot)
+regex=dependabot
+ignore=all
```
+If you just want to ignore certain lines in a commit, you can do that using the
+[ignore-body-lines](rules.md#i3-ignore-body-lines) rule.
+
+```ini
+# Ignore all lines that start with 'Co-Authored-By'
+[ignore-body-lines]
+regex=^Co-Authored-By
+```
+
+!!! warning
+
+ When ignoring specific lines, gitlint will no longer be aware of them while applying other rules.
+ This can sometimes be confusing for end-users, especially as line numbers of violations will typically no longer
+ match line numbers in the original commit message. Make sure to educate your users accordingly.
+
!!! note
- Right now it's not possible to write user-defined ignore rules to handle more complex use-cases.
- This is however something that we'd like to implement in a future version. If this is something you're interested in
- please let us know by [opening an issue](https://github.com/jorisroovers/gitlint/issues).
+ If you want to implement more complex ignore rules according to your own logic, you can do so using [user-defined
+ configuration rules](user_defined_rules.md#configuration-rules).
+
+## Named Rules
+
+Introduced in gitlint v0.14.0
+
+Named rules allow you to have multiple of the same rules active at the same time, which allows you to
+enforce the same rule multiple times but with different options. Named rules are so-called because they require an
+additional unique identifier (i.e. the rule *name*) during configuration.
+
+!!! warning
+
+ Named rules is an advanced topic. It's easy to make mistakes by defining conflicting instances of the same rule.
+ For example, by defining 2 `body-max-line-length` rules with different `line-length` options, you obviously create
+ a conflicting situation. Gitlint does not do any resolution of such conflicts, it's up to you to make sure
+ any configuration is non-conflicting. So caution advised!
+
+Defining a named rule is easy, for example using your `.gitlint` file:
+
+```ini
+# By adding the following section, you will add a second instance of the
+# title-must-not-contain-word (T5) rule (in addition to the one that is enabled
+# by default) with the name 'extra-words'.
+[title-must-not-contain-word:extra-words]
+words=foo,bar
+
+# So the generic form is
+# [<rule-id-or-name>:<your-chosen-name>]
+# Another example, referencing the rule type by id
+[T5:more-words]
+words=hur,dur
+
+# You can add as many additional rules and you can name them whatever you want
+# The only requirement is that names cannot contain whitespace or colons (:)
+[title-must-not-contain-word:This-Can_Be*Whatever$YouWant]
+words=wonderwoman,batman,power ranger
+```
+
+When executing gitlint, you will see the violations from the default `title-must-not-contain-word (T5)` rule, as well as
+the violations caused by the additional Named Rules.
+
+```sh
+$ gitlint
+1: T5 Title contains the word 'WIP' (case-insensitive): "WIP: foo wonderwoman hur bar"
+1: T5:This-Can_Be*Whatever$YouWant Title contains the word 'wonderwoman' (case-insensitive): "WIP: foo wonderwoman hur bar"
+1: T5:extra-words Title contains the word 'foo' (case-insensitive): "WIP: foo wonderwoman hur bar"
+1: T5:extra-words Title contains the word 'bar' (case-insensitive): "WIP: foo wonderwoman hur bar"
+1: T5:more-words Title contains the word 'hur' (case-insensitive): "WIP: foo wonderwoman hur bar"
+```
+
+Named rules are further treated identical to all other rules in gitlint:
+
+- You can reference them by their full name, when e.g. adding them to your `ignore` configuration
+```ini
+# .gitlint file example
+[general]
+ignore=T5:more-words,title-must-not-contain-word:extra-words
+```
+
+- You can use them to instantiate multiple of the same [user-defined rule](user_defined_rules.md)
+- You can configure them using [any of the ways you can configure regular gitlint rules](configuration.md)
+
-# Exit codes ##
+## Exit codes
Gitlint uses the exit code as a simple way to indicate the number of violations found.
Some exit codes are used to indicate special errors as indicated in the table below.
@@ -344,8 +499,8 @@ of violations counted by the exit code is 252. Note that gitlint does not have a
it can detect, it will just always return with exit code 252 when the number of violations is greater than or equal
to 252.
-Exit Code | Description
------------|------------------------------------------------------------
-253 | Wrong invocation of the ```gitlint``` command.
-254 | Something went wrong when invoking git.
-255 | Invalid gitlint configuration
+| Exit Code | Description |
+| --------- | ------------------------------------------ |
+| 253 | Wrong invocation of the `gitlint` command. |
+| 254 | Something went wrong when invoking git. |
+| 255 | Invalid gitlint configuration |
diff --git a/docs/rules.md b/docs/rules.md
index 173c5b1..a992f26 100644
--- a/docs/rules.md
+++ b/docs/rules.md
@@ -1,170 +1,318 @@
-# Overview #
+# Overview
-The table below shows an overview of all gitlint's built-in rules.
-Note that you can also [write your own user-defined rule](user_defined_rules.md) in case you don't find
+The table below shows an overview of all gitlint's built-in rules, with more specific details further down the page.
+
+Gitlint also has [community **contrib**uted rules](contrib_rules.md) which are not listed here as they're disabled by default.
+
+In addition, you can also [write your own user-defined rule](user_defined_rules.md) in case you don't find
what you're looking for.
-The rest of this page contains details on the available configuration options for each built-in rule.
-
-ID | Name | gitlint version | Description
-------|-----------------------------|-------------------|-------------------------------------------
-T1 | title-max-length | >= 0.1.0 | Title length must be &lt; 72 chars.
-T2 | title-trailing-whitespace | >= 0.1.0 | Title cannot have trailing whitespace (space or tab)
-T3 | title-trailing-punctuation | >= 0.1.0 | Title cannot have trailing punctuation (?:!.,;)
-T4 | title-hard-tab | >= 0.1.0 | Title cannot contain hard tab characters (\t)
-T5 | title-must-not-contain-word | >= 0.1.0 | Title cannot contain certain words (default: "WIP")
-T6 | title-leading-whitespace | >= 0.4.0 | Title cannot have leading whitespace (space or tab)
-T7 | title-match-regex | >= 0.5.0 | Title must match a given regex (default: .*)
-B1 | body-max-line-length | >= 0.1.0 | Lines in the body must be &lt; 80 chars
-B2 | body-trailing-whitespace | >= 0.1.0 | Body cannot have trailing whitespace (space or tab)
-B3 | body-hard-tab | >= 0.1.0 | Body cannot contain hard tab characters (\t)
-B4 | body-first-line-empty | >= 0.1.0 | First line of the body (second line of commit message) must be empty
-B5 | body-min-length | >= 0.4.0 | Body length must be at least 20 characters
-B6 | body-is-missing | >= 0.4.0 | Body message must be specified
-B7 | body-changed-file-mention | >= 0.4.0 | Body must contain references to certain files if those files are changed in the last commit
-M1 | author-valid-email | >= 0.9.0 | Author email address must be a valid email address
-I1 | ignore-by-title | >= 0.10.0 | Ignore a commit based on matching its title
-I2 | ignore-by-body | >= 0.10.0 | Ignore a commit based on matching its body
-
-## T1: title-max-length ##
-
-ID | Name | gitlint version | Description
-------|-----------------------------|-----------------|-------------------------------------------
-T1 | title-max-length | >= 0.1 | Title length must be &lt; 72 chars.
-### Options ###
-Name | gitlint version | Default | Description
----------------|-----------------|---------|----------------------------------
-line-length | >= 0.2 | 72 | Maximum allowed title length
+| ID | Name | gitlint version | Description |
+| --- | --------------------------- | --------------- | ------------------------------------------------------------------------------------------- |
+| T1 | title-max-length | >= 0.1.0 | Title length must be &lt;= 72 chars. |
+| T2 | title-trailing-whitespace | >= 0.1.0 | Title cannot have trailing whitespace (space or tab) |
+| T3 | title-trailing-punctuation | >= 0.1.0 | Title cannot have trailing punctuation (?:!.,;) |
+| T4 | title-hard-tab | >= 0.1.0 | Title cannot contain hard tab characters (\t) |
+| T5 | title-must-not-contain-word | >= 0.1.0 | Title cannot contain certain words (default: "WIP") |
+| T6 | title-leading-whitespace | >= 0.4.0 | Title cannot have leading whitespace (space or tab) |
+| T7 | title-match-regex | >= 0.5.0 | Title must match a given regex (default: None) |
+| T8 | title-min-length | >= 0.14.0 | Title length must be &gt;= 5 chars. |
+| B1 | body-max-line-length | >= 0.1.0 | Lines in the body must be &lt;= 80 chars |
+| B2 | body-trailing-whitespace | >= 0.1.0 | Body cannot have trailing whitespace (space or tab) |
+| B3 | body-hard-tab | >= 0.1.0 | Body cannot contain hard tab characters (\t) |
+| B4 | body-first-line-empty | >= 0.1.0 | First line of the body (second line of commit message) must be empty |
+| B5 | body-min-length | >= 0.4.0 | Body length must be at least 20 characters |
+| B6 | body-is-missing | >= 0.4.0 | Body message must be specified |
+| B7 | body-changed-file-mention | >= 0.4.0 | Body must contain references to certain files if those files are changed in the last commit |
+| B8 | body-match-regex | >= 0.14.0 | Body must match a given regex (default: None) |
+| M1 | author-valid-email | >= 0.9.0 | Author email address must be a valid email address |
+| I1 | ignore-by-title | >= 0.10.0 | Ignore a commit based on matching its title |
+| I2 | ignore-by-body | >= 0.10.0 | Ignore a commit based on matching its body |
+| I3 | ignore-body-lines | >= 0.14.0 | Ignore certain lines in a commit body that match a regex |
+| I4 | ignore-by-author-name | >= 0.16.0 | Ignore a commit based on matching its author name |
+
+
+
+## T1: title-max-length
+
+| ID | Name | gitlint version | Description |
+| --- | ---------------- | --------------- | ------------------------------------ |
+| T1 | title-max-length | >= 0.1 | Title length must be &lt;= 72 chars. |
+
+### Options
+
+| Name | gitlint version | Default | Description |
+| ----------- | --------------- | ------- | ---------------------------- |
+| line-length | >= 0.2 | 72 | Maximum allowed title length |
-## T2: title-trailing-whitespace ##
+### Examples
-ID | Name | gitlint version | Description
-------|-----------------------------|-----------------|-------------------------------------------
-T2 | title-trailing-whitespace | >= 0.1 | Title cannot have trailing whitespace (space or tab)
+#### .gitlint
+```ini
+# Titles should be max 72 chars
+[title-max-length]
+line-length=72
-## T3: title-trailing-punctuation ##
+# It's the 21st century, titles can be 120 chars long
+[title-max-length]
+line-length=120
+```
+------------------------------------------------------------------------------------------------------------------------
-ID | Name | gitlint version | Description
-------|-----------------------------|-----------------|-------------------------------------------
-T3 | title-trailing-punctuation | >= 0.1 | Title cannot have trailing punctuation (?:!.,;)
+## T2: title-trailing-whitespace
+| ID | Name | gitlint version | Description |
+| --- | ------------------------- | --------------- | ---------------------------------------------------- |
+| T2 | title-trailing-whitespace | >= 0.1 | Title cannot have trailing whitespace (space or tab) |
-## T4: title-hard-tab ##
+------------------------------------------------------------------------------------------------------------------------
-ID | Name | gitlint version | Description
-------|-----------------------------|-----------------|-------------------------------------------
-T4 | title-hard-tab | >= 0.1 | Title cannot contain hard tab characters (\t)
+## T3: title-trailing-punctuation
+| ID | Name | gitlint version | Description |
+| --- | -------------------------- | --------------- | ----------------------------------------------- |
+| T3 | title-trailing-punctuation | >= 0.1 | Title cannot have trailing punctuation (?:!.,;) |
-## T5: title-must-not-contain-word ##
+------------------------------------------------------------------------------------------------------------------------
-ID | Name | gitlint version | Description
-------|-----------------------------|-----------------|-------------------------------------------
-T5 | title-must-not-contain-word | >= 0.1 | Title cannot contain certain words (default: "WIP")
+## T4: title-hard-tab
-### Options ###
+| ID | Name | gitlint version | Description |
+| --- | -------------- | --------------- | --------------------------------------------- |
+| T4 | title-hard-tab | >= 0.1 | Title cannot contain hard tab characters (\t) |
-Name | gitlint version | Default | Description
----------------|-----------------|---------|----------------------------------
-words | >= 0.3 | WIP | Comma-separated list of words that should not be used in the title. Matching is case insensitive
+------------------------------------------------------------------------------------------------------------------------
-## T6: title-leading-whitespace ##
+## T5: title-must-not-contain-word
-ID | Name | gitlint version | Description
-------|-----------------------------|-----------------|-------------------------------------------
-T6 | title-leading-whitespace | >= 0.4 | Title cannot have leading whitespace (space or tab)
+| ID | Name | gitlint version | Description |
+| --- | --------------------------- | --------------- | --------------------------------------------------- |
+| T5 | title-must-not-contain-word | >= 0.1 | Title cannot contain certain words (default: "WIP") |
-## T7: title-match-regex ##
+### Options
-ID | Name | gitlint version | Description
-------|-----------------------------|-----------------|-------------------------------------------
-T7 | title-match-regex | >= 0.5 | Title must match a given regex (default: .*)
+| Name | gitlint version | Default | Description |
+| ----- | --------------- | ------- | ------------------------------------------------------------------------------------------------ |
+| words | >= 0.3 | WIP | Comma-separated list of words that should not be used in the title. Matching is case insensitive |
+### Examples
-### Options ###
+#### .gitlint
-Name | gitlint version | Default | Description
----------------|-----------------|---------|----------------------------------
-regex | >= 0.5 | .* | [Python-style regular expression](https://docs.python.org/3.5/library/re.html) that the title should match.
+```ini
+# Ensure the title doesn't contain swear words
+[title-must-not-contain-word]
+words=crap,darn,damn
+```
+------------------------------------------------------------------------------------------------------------------------
-## B1: body-max-line-length ##
+## T6: title-leading-whitespace
-ID | Name | gitlint version | Description
-------|-----------------------------|-----------------|-------------------------------------------
-B1 | body-max-line-length | >= 0.1 | Lines in the body must be &lt; 80 chars
+| ID | Name | gitlint version | Description |
+| --- | ------------------------ | --------------- | --------------------------------------------------- |
+| T6 | title-leading-whitespace | >= 0.4 | Title cannot have leading whitespace (space or tab) |
-### Options ###
+------------------------------------------------------------------------------------------------------------------------
-Name | gitlint version | Default | Description
----------------|-----------------|---------|----------------------------------
-line-length | >= 0.2 | 80 | Maximum allowed line length in the commit message body
+## T7: title-match-regex
-## B2: body-trailing-whitespace ##
+| ID | Name | gitlint version | Description |
+| --- | ----------------- | --------------- | -------------------------------------------- |
+| T7 | title-match-regex | >= 0.5 | Title must match a given regex (default: .*) |
-ID | Name | gitlint version | Description
-------|-----------------------------|-----------------|-------------------------------------------
-B2 | body-trailing-whitespace | >= 0.1 | Body cannot have trailing whitespace (space or tab)
+### Options
-## B3: body-hard-tab ##
+| Name | gitlint version | Default | Description |
+| ----- | --------------- | ------- | ------------------------------------------------------------------------------------ |
+| regex | >= 0.5 | .* | [Python regex](https://docs.python.org/library/re.html) that the title should match. |
-ID | Name | gitlint version | Description
-------|-----------------------------|-----------------|-------------------------------------------
-B3 | body-hard-tab | >= 0.1 | Body cannot contain hard tab characters (\t)
+### Examples
+#### .gitlint
-## B4: body-first-line-empty ##
+```ini
+# Ensure every title starts with a user-story like US123
+[title-match-regex]
+regex=^US[1-9][0-9]*
+```
+------------------------------------------------------------------------------------------------------------------------
-ID | Name | gitlint version | Description
-------|-----------------------------|-----------------|-------------------------------------------
-B4 | body-first-line-empty | >= 0.1 | First line of the body (second line of commit message) must be empty
+## T8: title-min-length ##
-## B5: body-min-length ##
+| ID | Name | gitlint version | Description |
+| --- | ---------------- | --------------- | ----------------------------------- |
+| T8 | title-min-length | >= 0.14.0 | Title length must be &gt;= 5 chars. |
-ID | Name | gitlint version | Description
-------|-----------------------------|-----------------|-------------------------------------------
-B5 | body-min-length | >= 0.4 | Body length must be at least 20 characters. In versions >= 0.8.0, gitlint will not count newline characters.
-### Options ###
+### Options
+
+| Name | gitlint version | Default | Description |
+| ---------- | --------------- | ------- | ----------------------------- |
+| min-length | >= 0.14.0 | 5 | Minimum required title length |
+
+### Examples
-Name | gitlint version | Default | Description
----------------|-----------------|---------|----------------------------------
-min-length | >= 0.4 | 20 | Minimum number of required characters in body
+#### .gitlint
-## B6: body-is-missing ##
+```ini
+# Titles should be min 3 chars
+[title-min-length]
+min-length=3
+```
+------------------------------------------------------------------------------------------------------------------------
-ID | Name | gitlint version | Description
-------|-----------------------------|-----------------|-------------------------------------------
-B6 | body-is-missing | >= 0.4 | Body message must be specified
+## B1: body-max-line-length
+| ID | Name | gitlint version | Description |
+| --- | -------------------- | --------------- | ---------------------------------------- |
+| B1 | body-max-line-length | >= 0.1 | Lines in the body must be &lt;= 80 chars |
-### Options ###
+### Options
-Name | gitlint version | Default | Description
-----------------------|-----------------|-----------|----------------------------------
-ignore-merge-commits | >= 0.4 | true | Whether this rule should be ignored during merge commits. Allowed values: true,false.
+| Name | gitlint version | Default | Description |
+| ----------- | --------------- | ------- | ------------------------------------------------------ |
+| line-length | >= 0.2 | 80 | Maximum allowed line length in the commit message body |
-## B7: body-changed-file-mention ##
+### Examples
-ID | Name | gitlint version | Description
-------|-----------------------------|-----------------|-------------------------------------------
-B7 | body-changed-file-mention | >= 0.4 | Body must contain references to certain files if those files are changed in the last commit
+#### .gitlint
+
+```ini
+# It's the 21st century, lines can be 120 chars long
+[body-max-line-length]
+line-length=120
+
+# Your tool prefers 72
+[body-max-line-length]
+line-length=72
+```
+------------------------------------------------------------------------------------------------------------------------
+
+## B2: body-trailing-whitespace
+
+| ID | Name | gitlint version | Description |
+| --- | ------------------------ | --------------- | --------------------------------------------------- |
+| B2 | body-trailing-whitespace | >= 0.1 | Body cannot have trailing whitespace (space or tab) |
+
+------------------------------------------------------------------------------------------------------------------------
+
+## B3: body-hard-tab
+
+| ID | Name | gitlint version | Description |
+| --- | ------------- | --------------- | -------------------------------------------- |
+| B3 | body-hard-tab | >= 0.1 | Body cannot contain hard tab characters (\t) |
+
+------------------------------------------------------------------------------------------------------------------------
+
+## B4: body-first-line-empty
+
+| ID | Name | gitlint version | Description |
+| --- | --------------------- | --------------- | -------------------------------------------------------------------- |
+| B4 | body-first-line-empty | >= 0.1 | First line of the body (second line of commit message) must be empty |
+
+------------------------------------------------------------------------------------------------------------------------
+
+## B5: body-min-length
+
+| ID | Name | gitlint version | Description |
+| --- | --------------- | --------------- | ------------------------------------------------------------------------------------------------------------ |
+| B5 | body-min-length | >= 0.4 | Body length must be at least 20 characters. In versions >= 0.8.0, gitlint will not count newline characters. |
### Options ###
-Name | gitlint version | Default | Description
-----------------------|-----------------|--------------|----------------------------------
-files | >= 0.4 | (empty) | Comma-separated list of files that need to an explicit mention in the commit message in case they are changed.
+| Name | gitlint version | Default | Description |
+| ---------- | --------------- | ------- | --------------------------------------------- |
+| min-length | >= 0.4 | 20 | Minimum number of required characters in body |
+
+### Examples
+
+#### .gitlint
+
+```ini
+# You want *something* in every commit body, but doesn't have to be as long as 20 chars.
+[body-min-length]
+min-length=5
+
+# You want a more elaborate message in every commit body
+[body-min-length]
+min-length=100
+```
+------------------------------------------------------------------------------------------------------------------------
+
+## B6: body-is-missing
+
+| ID | Name | gitlint version | Description |
+| --- | --------------- | --------------- | ------------------------------ |
+| B6 | body-is-missing | >= 0.4 | Body message must be specified |
+
+
+### Options
+
+| Name | gitlint version | Default | Description |
+| -------------------- | --------------- | ------- | ------------------------------------------------------------------------------------- |
+| ignore-merge-commits | >= 0.4 | true | Whether this rule should be ignored during merge commits. Allowed values: true,false. |
+
+------------------------------------------------------------------------------------------------------------------------
+## B7: body-changed-file-mention
+| ID | Name | gitlint version | Description |
+| --- | ------------------------- | --------------- | ------------------------------------------------------------------------------------------- |
+| B7 | body-changed-file-mention | >= 0.4 | Body must contain references to certain files if those files are changed in the last commit |
-## M1: author-valid-email ##
+### Options
-ID | Name | gitlint version | Description
-------|-----------------------------|-----------------|-------------------------------------------
-M1 | author-valid-email | >= 0.8.3 | Author email address must be a valid email address
+| Name | gitlint version | Default | Description |
+| ----- | --------------- | ------- | -------------------------------------------------------------------------------------------------------------- |
+| files | >= 0.4 | (empty) | Comma-separated list of files that need to an explicit mention in the commit message in case they are changed. |
+
+### Examples
+
+#### .gitlint
+
+```ini
+# Prevent that certain sensitive files are committed by mistake by forcing
+# users to mention them explicitly if they're deliberately changing them
+[body-changed-file-mention]
+files=generated.xml,secrets.txt,private-key.pem
+```
+------------------------------------------------------------------------------------------------------------------------
+
+## B8: body-match-regex
+
+| ID | Name | gitlint version | Description |
+| --- | ---------------- | --------------- | ----------------------------- |
+| B8 | body-match-regex | >= 0.14 | Body must match a given regex |
+
+### Options
+
+| Name | gitlint version | Default | Description |
+| ----- | --------------- | ------- | ----------------------------------------------------------------------------------- |
+| regex | >= 0.14 | None | [Python regex](https://docs.python.org/library/re.html) that the body should match. |
+
+### Examples
+
+#### .gitlint
+
+```ini
+# Ensure the body ends with Reviewed-By: <some value>
+[body-match-regex]
+regex=Reviewed-By:(.*)$
+
+# Ensure body contains the word "Foo" somewhere
+[body-match-regex]
+regex=(*.)Foo(.*)
+```
+------------------------------------------------------------------------------------------------------------------------
+
+## M1: author-valid-email
+
+| ID | Name | gitlint version | Description |
+| --- | ------------------ | --------------- | -------------------------------------------------- |
+| M1 | author-valid-email | >= 0.8.3 | Author email address must be a valid email address |
!!! note
Email addresses are [notoriously hard to validate and the official email valid spec is often too loose for any real world application](http://stackoverflow.com/a/201378/381010).
@@ -172,30 +320,37 @@ M1 | author-valid-email | >= 0.8.3 | Author email address mus
-### Options ###
+### Options
-Name | gitlint version | Default | Description
-----------------------|-------------------|------------------------------|----------------------------------
-regex | >= 0.9.0 | ```[^@ ]+@[^@ ]+\.[^@ ]+``` | Regex the commit author email address is matched against
+| Name | gitlint version | Default | Description |
+| ----- | --------------- | ----------------------- | ---------------------------------------------------------------------------------------------------------- |
+| regex | >= 0.9.0 | `[^@ ]+@[^@ ]+\.[^@ ]+` | [Python regex](https://docs.python.org/library/re.html) the commit author email address is matched against |
-!!! note
- An often recurring use-case is to only allow email addresses from a certain domain. The following regular expression achieves this: ```[^@]+@foo.com```
+### Examples
+#### .gitlint
-## I1: ignore-by-title ##
+```ini
+# Only allow email addresses from a foo.com domain
+[author-valid-email]
+regex=[^@]+@foo.com
+```
+------------------------------------------------------------------------------------------------------------------------
-ID | Name | gitlint version | Description
-------|-----------------------------|-----------------|-------------------------------------------
-I1 | ignore-by-title | >= 0.10.0 | Ignore a commit based on matching its title.
+## I1: ignore-by-title
+| ID | Name | gitlint version | Description |
+| --- | --------------- | --------------- | -------------------------------------------- |
+| I1 | ignore-by-title | >= 0.10.0 | Ignore a commit based on matching its title. |
-### Options ###
-Name | gitlint version | Default | Description
-----------------------|-------------------|------------------------------|----------------------------------
-regex | >= 0.10.0 | None | Regex to match against commit title. On match, the commit will be ignored.
-ignore | >= 0.10.0 | all | Comma-seperated list of rule names or ids to ignore when this rule is matched.
+### Options
+
+| Name | gitlint version | Default | Description |
+| ------ | --------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------- |
+| regex | >= 0.10.0 | None | [Python regex](https://docs.python.org/library/re.html) to match against commit title. On match, the commit will be ignored. |
+| ignore | >= 0.10.0 | all | Comma-separated list of rule names or ids to ignore when this rule is matched. |
### Examples
@@ -210,20 +365,21 @@ ignore=title-max-length,body-min-length
# ignore all rules by setting ignore to 'all'
# ignore=all
```
+------------------------------------------------------------------------------------------------------------------------
-## I2: ignore-by-body ##
+## I2: ignore-by-body
-ID | Name | gitlint version | Description
-------|-----------------------------|-----------------|-------------------------------------------
-I2 | ignore-by-body | >= 0.10.0 | Ignore a commit based on matching its body.
+| ID | Name | gitlint version | Description |
+| --- | -------------- | --------------- | ------------------------------------------- |
+| I2 | ignore-by-body | >= 0.10.0 | Ignore a commit based on matching its body. |
-### Options ###
+### Options
-Name | gitlint version | Default | Description
-----------------------|-------------------|------------------------------|----------------------------------
-regex | >= 0.10.0 | None | Regex to match against each line of the body. On match, the commit will be ignored.
-ignore | >= 0.10.0 | all | Comma-seperated list of rule names or ids to ignore when this rule is matched.
+| Name | gitlint version | Default | Description |
+| ------ | --------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------- |
+| regex | >= 0.10.0 | None | [Python regex](https://docs.python.org/library/re.html) to match against each line of the body. On match, the commit will be ignored. |
+| ignore | >= 0.10.0 | all | Comma-separated list of rule names or ids to ignore when this rule is matched. |
### Examples
@@ -240,4 +396,66 @@ ignore=all
[ignore-by-body]
regex=(.*)release(.*)
ignore=T1,body-min-length,B6
-``` \ No newline at end of file
+```
+------------------------------------------------------------------------------------------------------------------------
+
+## I3: ignore-body-lines
+
+| ID | Name | gitlint version | Description |
+| --- | ----------------- | --------------- | --------------------------------------------------------- |
+| I3 | ignore-body-lines | >= 0.14.0 | Ignore certain lines in a commit body that match a regex. |
+
+
+### Options
+
+| Name | gitlint version | Default | Description |
+| ----- | --------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| regex | >= 0.14.0 | None | [Python regex](https://docs.python.org/library/re.html) to match against each line of the body. On match, that line will be ignored by gitlint (the rest of the body will still be linted). |
+
+### Examples
+
+#### .gitlint
+
+```ini
+# Ignore all lines that start with 'Co-Authored-By'
+[ignore-body-lines]
+regex=^Co-Authored-By
+
+# Ignore lines that start with 'Co-Authored-By' or with 'Signed-off-by'
+[ignore-body-lines]
+regex=(^Co-Authored-By)|(^Signed-off-by)
+
+# Ignore lines that contain 'foobar'
+[ignore-body-lines]
+regex=(.*)foobar(.*)
+```
+------------------------------------------------------------------------------------------------------------------------
+
+## I4: ignore-by-author-name
+
+| ID | Name | gitlint version | Description |
+| --- | --------------------- | --------------- | -------------------------------------------------- |
+| I4 | ignore-by-author-name | >= 0.16.0 | Ignore a commit based on matching its author name. |
+
+### Options
+
+| Name | gitlint version | Default | Description |
+| ------ | --------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------- |
+| regex | >= 0.16.0 | None | [Python regex](https://docs.python.org/library/re.html) to match against the commit author name. On match, the commit will be ignored. |
+| ignore | >= 0.16.0 | all | Comma-separated list of rule names or ids to ignore when this rule is matched. |
+
+### Examples
+
+#### .gitlint
+
+```ini
+# Ignore all commits authored by dependabot
+[ignore-by-author-name]
+regex=dependabot
+
+# For commits made by anyone with "[bot]" in their name, ignore
+# rules T1, body-min-length and B6
+[ignore-by-author-name]
+regex=(.*)\[bot\](.*)
+ignore=T1,body-min-length,B6
+```
diff --git a/docs/user_defined_rules.md b/docs/user_defined_rules.md
index a8a51d5..db21809 100644
--- a/docs/user_defined_rules.md
+++ b/docs/user_defined_rules.md
@@ -3,28 +3,29 @@ _Introduced in gitlint v0.8.0_
Gitlint supports the concept of **user-defined** rules: the ability for users to write their own custom rules in python.
-In a nutshell, use ```--extra-path /home/joe/myextensions``` to point gitlint to a ```myextensions``` directory where it will search
+In a nutshell, use `--extra-path /home/joe/myextensions` to point gitlint to a `myextensions` directory where it will search
for python files containing gitlint rule classes. You can also specify a single python module, ie
-```--extra-path /home/joe/my_rules.py```.
+`--extra-path /home/joe/my_rules.py`.
-```bash
+```sh
cat examples/commit-message-1 | gitlint --extra-path examples/
-# Example output of a user-defined Signed-Off-By rule
-1: UC2 Body does not contain a 'Signed-Off-By Line'
+# Example output of a user-defined Signed-off-by rule
+1: UC2 Body does not contain a 'Signed-off-by Line'
# other violations were removed for brevity
```
-The `SignedOffBy` user-defined ```CommitRule``` was discovered by gitlint when it scanned
-[examples/gitlint/my_commit_rules.py](https://github.com/jorisroovers/gitlint/blob/master/examples/my_commit_rules.py),
-which is part of the examples directory that was passed via ```--extra-path```:
+The `SignedOffBy` user-defined `CommitRule` was discovered by gitlint when it scanned
+[examples/gitlint/my_commit_rules.py](https://github.com/jorisroovers/gitlint/blob/main/examples/my_commit_rules.py),
+which is part of the examples directory that was passed via `--extra-path`:
```python
+# -*- coding: utf-8 -*-
from gitlint.rules import CommitRule, RuleViolation
class SignedOffBy(CommitRule):
- """ This rule will enforce that each commit contains a "Signed-Off-By" line.
+ """ 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".
+ line that starts with "Signed-off-by".
"""
# A rule MUST have a human friendly name
@@ -35,20 +36,22 @@ class SignedOffBy(CommitRule):
id = "UC2"
def validate(self, commit):
+ self.log.debug("SignedOffBy: This will be visible when running `gitlint --debug`")
+
for line in commit.message.body:
- if line.startswith("Signed-Off-By"):
+ if line.startswith("Signed-off-by"):
return
- msg = "Body does not contain a 'Signed-Off-By' line"
+ msg = "Body does not contain a 'Signed-off-by' line"
return [RuleViolation(self.id, msg, line_nr=1)]
```
-As always, ```--extra-path``` can also be set by adding it under the ```[general]``` section in your ```.gitlint``` file or using
+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](configuration.md).
-If you want to check whether your rules are properly discovered by gitlint, 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
+```sh
$ gitlint --debug --extra-path examples/
# [output cut for brevity]
UC1: body-max-line-count
@@ -60,40 +63,41 @@ $ gitlint --debug --extra-path examples/
!!! 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.
+ [examples](https://github.com/jorisroovers/gitlint/tree/main/examples) directory and modify it to your needs.
The remainder of this page contains the technical details, mostly for reference.
-# Line and Commit Rules ##
-The ```SignedOffBy``` class above was an example of a user-defined ```CommitRule```. Commit rules are gitlint rules that
+## Line and Commit Rules
+The `SignedOffBy` class above was an example of a user-defined `CommitRule`. 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 e.g.: [examples/my_line_rules.py](https://github.com/jorisroovers/gitlint/blob/master/examples/my_line_rules.py))
-in that a ```CommitRule``` is only applied once on an entire commit while a ```LineRule``` is applied for every line in the commit
-(you can also apply it once to the title using a ```target``` - see the examples section below).
+A `CommitRule` contrasts with a `LineRule`
+(see e.g.: [examples/my_line_rules.py](https://github.com/jorisroovers/gitlint/blob/main/examples/my_line_rules.py))
+in that a `CommitRule` is only applied once on an entire commit while a `LineRule` is applied for every line in the commit
+(you can also apply it once to the title using a `target` - see the examples section below).
The benefit of a commit rule is that it allows commit rules to implement more complex checks that span multiple lines and/or checks
that should only be done once per commit.
-While every ```LineRule``` can be implemented as a ```CommitRule```, it's usually easier and more concise to go with a ```LineRule``` if
+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.
-## Examples ##
+### Examples
-In terms of code, writing your own ```CommitRule``` or ```LineRule``` is very similar.
-The only 2 differences between a ```CommitRule``` and a ```LineRule``` are the parameters of the ```validate(...)``` method and the extra
-```target``` attribute that ```LineRule``` requires.
+In terms of code, writing your own `CommitRule` or `LineRule` is very similar.
+The only 2 differences between a `CommitRule` and a `LineRule` are the parameters of the `validate(...)` method and the extra
+`target` attribute that `LineRule` requires.
-Consider the following ```CommitRule``` that can be found in [examples/my_commit_rules.py](https://github.com/jorisroovers/gitlint/blob/master/examples/my_commit_rules.py):
+Consider the following `CommitRule` that can be found in [examples/my_commit_rules.py](https://github.com/jorisroovers/gitlint/blob/main/examples/my_commit_rules.py):
```python
+# -*- coding: utf-8 -*-
from gitlint.rules import CommitRule, RuleViolation
class SignedOffBy(CommitRule):
- """ This rule will enforce that each commit contains a "Signed-Off-By" line.
+ """ 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".
+ line that starts with "Signed-off-by".
"""
# A rule MUST have a human friendly name
@@ -104,18 +108,21 @@ class SignedOffBy(CommitRule):
id = "UC2"
def validate(self, commit):
+ self.log.debug("SignedOffBy: This will be visible when running `gitlint --debug`")
+
for line in commit.message.body:
- if line.startswith("Signed-Off-By"):
- return []
+ if line.startswith("Signed-off-by"):
+ return
- msg = "Body does not contain a 'Signed-Off-By Line'"
+ msg = "Body does not contain a 'Signed-off-by' line"
return [RuleViolation(self.id, msg, line_nr=1)]
```
-Note the use of the ```name``` and ```id``` class attributes and the ```validate(...)``` method taking a single ```commit``` parameter.
+Note the use of the `name` and `id` class attributes and the `validate(...)` method taking a single `commit` parameter.
-Contrast this with the following ```LineRule``` that can be found in [examples/my_line_rules.py](https://github.com/jorisroovers/gitlint/blob/master/examples/my_line_rules.py):
+Contrast this with the following `LineRule` that can be found in [examples/my_line_rules.py](https://github.com/jorisroovers/gitlint/blob/main/examples/my_line_rules.py):
```python
+# -*- coding: utf-8 -*-
from gitlint.rules import LineRule, RuleViolation, CommitMessageTitle
from gitlint.options import ListOption
@@ -138,81 +145,91 @@ class SpecialChars(LineRule):
options_spec = [ListOption('special-chars', ['$', '^', '%', '@', '!', '*', '(', ')'],
"Comma separated list of characters that should not occur in the title")]
- def validate(self, line, commit):
+ def validate(self, line, _commit):
+ self.log.debug("SpecialChars: This will be visible when running `gitlint --debug`")
+
violations = []
- # option values can be accessed via self.options
+ # options can be accessed by looking them up by their name in self.options
for char in self.options['special-chars'].value:
if char in line:
- violation = RuleViolation(self.id, "Title contains the special character '{}'".format(char), line)
+ msg = f"Title contains the special character '{char}'"
+ violation = RuleViolation(self.id, msg, line)
violations.append(violation)
return violations
+
```
Note the following 2 differences:
-- **extra ```target``` class attribute**: in this example set to ```CommitMessageTitle``` indicating that this ```LineRule```
-should only be applied once to the commit message title. The alternative value for ```target``` is ```CommitMessageBody```,
+- **extra `target` class attribute**: in this example set to `CommitMessageTitle` indicating that this `LineRule`
+should only be applied once to the commit message title. The alternative value for `target` is `CommitMessageBody`,
in which case gitlint will apply
your rule to **every** line in the commit message body.
-- **```validate(...)``` takes 2 parameters**: Line rules get the ```line``` against which they are applied as the first parameter and
-the ```commit``` object of which the line is part of as second.
+- **`validate(...)` takes 2 parameters**: Line rules get the `line` against which they are applied as the first parameter and
+the `commit` object of which the line is part of as second.
-In addition, you probably also noticed the extra ```options_spec``` class attribute which allows you to make your rules configurable.
-Options are not unique to ```LineRule```s, they can also be used by ```CommitRule```s and are further explained in the
+In addition, you probably also noticed the extra `options_spec` class attribute which allows you to make your rules configurable.
+Options are not unique to `LineRule`s, they can also be used by `CommitRule`s and are further explained in the
[Options](user_defined_rules.md#options) section below.
-# The commit object ##
-Both ```CommitRule```s and ```LineRule```s take a ```commit``` object in their ```validate(...)``` methods.
+## The commit object
+Both `CommitRule`s and `LineRule`s take a `commit` object in their `validate(...)` methods.
The table below outlines the various attributes of that commit object that can be used during validation.
-Property | Type | Description
--------------------------------| ---------------|-------------------
-commit.message | object | Python object representing the commit message
-commit.message.original | string | Original commit message as returned by git
-commit.message.full | string | Full commit message, with comments (lines starting with #) removed.
-commit.message.title | string | Title/subject of the commit message: the first line
-commit.message.body | string[] | List of lines in the body of the commit message (i.e. starting from the second line)
-commit.author_name | string | Name of the author, result of ```git log --pretty=%aN```
-commit.author_email | string | Email of the author, result of ```git log --pretty=%aE```
-commit.date | datetime | Python ```datetime``` object representing the time of commit
-commit.is_merge_commit | boolean | Boolean indicating whether the commit is a merge commit or not.
-commit.is_revert_commit | boolean | Boolean indicating whether the commit is a revert commit or not.
-commit.is_fixup_commit | boolean | Boolean indicating whether the commit is a fixup commit or not.
-commit.is_squash_commit | boolean | Boolean indicating whether the commit is a squash commit or not.
-commit.parents | string[] | List of parent commit ```sha```s (only for merge commits).
-commit.changed_files | string[] | List of files changed in the commit (relative paths).
-commit.branches | string[] | List of branch names the commit is part of
-commit.context | object | Object pointing to the bigger git context that the commit is part of
-commit.context.current_branch | string | Name of the currently active branch (of local repo)
-commit.context.repository_path | string | Absolute path pointing to the git repository being linted
-commit.context.commits | object[] | List of commits gitlint is acting on, NOT all commits in the repo.
-
-# Violations ##
-In order to let gitlint know that there is a violation in the commit being linted, users should have the ```validate(...)```
-method in their rules return a list of ```RuleViolation```s.
+| Property | Type | Description |
+| -------------------------------------------- | --------------------------------- | ------------------------------------------------------------------------------------ |
+| commit | `GitCommit` | Python object representing the commit |
+| commit.message | `GitCommitMessage` | Python object representing the commit message |
+| commit.message.original | `str` | Original commit message as returned by git |
+| commit.message.full | `str` | Full commit message, with comments (lines starting with #) removed. |
+| commit.message.title | `str` | Title/subject of the commit message: the first line |
+| commit.message.body | `str[]` | List of lines in the body of the commit message (i.e. starting from the second line) |
+| commit.author_name | `str` | Name of the author, result of `git log --pretty=%aN` |
+| commit.author_email | `str` | Email of the author, result of `git log --pretty=%aE` |
+| commit.date | `datetime.datetime` | Python `datetime` object representing the time of commit |
+| commit.is_merge_commit | `bool` | Boolean indicating whether the commit is a merge commit or not. |
+| commit.is_revert_commit | `bool` | Boolean indicating whether the commit is a revert commit or not. |
+| commit.is_fixup_commit | `bool` | Boolean indicating whether the commit is a fixup commit or not. |
+| commit.is_fixup_amend_commit | `bool` | Boolean indicating whether the commit is a (fixup) amend commit or not. |
+| commit.is_squash_commit | `bool` | Boolean indicating whether the commit is a squash commit or not. |
+| commit.parents | `str[]` | List of parent commit `sha`s (only for merge commits). |
+| commit.changed_files | `str[]` | List of files changed in the commit (relative paths). |
+| commit.changed_files_stats | `dict[str, GitChangedFilesStats]` | Dictionary mapping the changed files to a `GitChangedFilesStats` objects |
+| commit.changed_files_stats["path"].filepath | `pathlib.Path` | Relative path (compared to repo root) of the file that was changed. |
+| commit.changed_files_stats["path"].additions | `int` | Number of additions in the file. |
+| commit.changed_files_stats["path"].deletions | `int` | Number of deletions in the file. |
+| commit.branches | `str[]` | List of branch names the commit is part of |
+| commit.context | `GitContext` | Object pointing to the bigger git context that the commit is part of |
+| commit.context.current_branch | `str` | Name of the currently active branch (of local repo) |
+| commit.context.repository_path | `str` | Absolute path pointing to the git repository being linted |
+| commit.context.commits | `GitCommit[]` | List of commits gitlint is acting on, NOT all commits in the repo. |
+
+## Violations
+In order to let gitlint know that there is a violation in the commit being linted, users should have the `validate(...)`
+method in their rules return a list of `RuleViolation`s.
!!! important
- The ```validate(...)``` method doesn't always need to return a list, you can just skip the return statement in case there are no violations.
+ The `validate(...)` method doesn't always need to return a list, you can just skip the return statement in case there are no violations.
However, in case of a single violation, validate should return a **list** with a single item.
-The ```RuleViolation``` class has the following generic signature:
+The `RuleViolation` class has the following generic signature:
-```
+```python
RuleViolation(rule_id, message, content=None, line_nr=None):
```
With the parameters meaning the following:
-Parameter | Type | Description
---------------|---------|--------------------------------
-rule_id | string | Rule's unique string id
-message | string | Short description of the violation
-content | string | (optional) the violating part of commit or line
-line_nr | int | (optional) line number in the commit message where the violation occurs. **Automatically set to the correct line number for ```LineRule```s if not set explicitly.**
+| Parameter | Type | Description |
+| --------- | ----- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| rule_id | `str` | Rule's unique string id |
+| message | `str` | Short description of the violation |
+| content | `str` | (optional) the violating part of commit or line |
+| line_nr | `int` | (optional) line number in the commit message where the violation occurs. **Automatically set to the correct line number for `LineRule`s if not set explicitly.** |
-A typical ```validate(...)``` implementation for a ```CommitRule``` would then be as follows:
+A typical `validate(...)` implementation for a `CommitRule` would then be as follows:
```python
def validate(self, commit)
for line_nr, line in commit.message.body:
@@ -222,16 +239,17 @@ def validate(self, commit)
return []
```
-The parameters of this ```RuleViolation``` can be directly mapped onto gitlint's output as follows:
+The parameters of this `RuleViolation` can be directly mapped onto gitlint's output as follows:
![How Rule violations map to gitlint output](images/RuleViolation.png)
-# Options ##
+## Options
-In order to make your own rules configurable, you can add an optional ```options_spec``` attribute to your rule class
-(supported for both ```LineRule``` and ```CommitRule```).
+In order to make your own rules configurable, you can add an optional `options_spec` attribute to your rule class
+(supported for both `LineRule` and `CommitRule`).
```python
+# -*- coding: utf-8 -*-
from gitlint.rules import CommitRule, RuleViolation
from gitlint.options import IntOption
@@ -250,63 +268,148 @@ class BodyMaxLineCount(CommitRule):
line_count = len(commit.message.body)
max_line_count = self.options['max-line-count'].value
if line_count > max_line_count:
- message = "Body contains too many lines ({0} > {1})".format(line_count,
- max_line_count)
+ message = f"Body contains too many lines ({line_count} > {max_line_count})"
return [RuleViolation(self.id, message, line_nr=1)]
```
-By using ```options_spec```, you make your option available to be configured through a ```.gitlint``` file
+By using `options_spec`, you make your option available to be configured through a `.gitlint` file
or one of the [other ways to configure gitlint](configuration.md). Gitlint automatically takes care of the parsing and input validation.
-For example, to change the value of the ```max-line-count``` option, add the following to your ```.gitlint``` file:
+For example, to change the value of the `max-line-count` option, add the following to your `.gitlint` file:
```ini
[body-max-line-count]
body-max-line-count=1
```
-As ```options_spec``` is a list, you can obviously have multiple options per rule. The general signature of an option is:
-```Option(name, default_value, description)```.
+As `options_spec` is a list, you can obviously have multiple options per rule. The general signature of an option is:
+`Option(name, default_value, description)`.
-Gitlint supports a variety of different option types, all can be imported from ```gitlint.options```:
+Gitlint supports a variety of different option types, all can be imported from `gitlint.options`:
-Option Class | Use for
-----------------|--------------
-StrOption | Strings
-IntOption | Integers. ```IntOption``` takes an optional ```allow_negative``` parameter if you want to allow negative integers.
-BoolOption | Booleans. Valid values: `true`, `false`. Case-insensitive.
-ListOption | List of strings. Comma separated.
-PathOption | Directory or file path. Takes an optional ```type``` parameter for specifying path type (```file```, ```dir``` (=default) or ```both```).
+| Option Class | Use for |
+| ------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
+| `StrOption ` | Strings |
+| `IntOption` | Integers. `IntOption` takes an optional `allow_negative` parameter if you want to allow negative integers. |
+| `BoolOption` | Booleans. Valid values: `true`, `false`. Case-insensitive. |
+| `ListOption` | List of strings. Comma separated. |
+| `PathOption` | Directory or file path. Takes an optional `type` parameter for specifying path type (`file`, `dir` (=default) or `both`). |
+| `RegexOption` | String representing a [Python-style regex](https://docs.python.org/library/re.html) - compiled and validated before rules are applied. |
!!! note
Gitlint currently does not support options for all possible types (e.g. float, list of int, etc).
[We could use a hand getting those implemented](contributing.md)!
-# Rule requirements ##
+## Configuration Rules
+
+_Introduced in gitlint v0.14.0_
+
+Configuration rules are special rules that are applied once per commit and *BEFORE* any other rules are run.
+Configuration rules are meant to dynamically change gitlint's configuration and/or the commit that is about to be
+linted.
+A typically use-case for this is when you want to modifying gitlint's behavior for all rules against a commit matching
+specific circumstances.
+
+!!! warning
+ Configuration rules can drastically change the way gitlint behaves and are typically only needed for more advanced
+ use-cases. We recommend you double check:
+
+ 1. Whether gitlint already supports your use-case out-of-the-box (special call-out for [ignore rules](rules.md#i1-ignore-by-title) which allow you to ignore (parts) of your commit message).
+ 2. Whether there's a [Contrib Rule](contrib_rules.md) that implements your use-case.
+ 3. Whether you can implement your use-case using a regular Commit or Line user-defined rule (see above).
+
+
+As with other user-defined rules, the easiest way to get started is by copying [`my_configuration.py` from the examples directory](https://github.com/jorisroovers/gitlint/tree/main/examples/my_configuration_rules.py) and modifying it to fit your need.
+
+```python
+# -*- coding: utf-8 -*-
+from gitlint.rules import ConfigurationRule
+from gitlint.options import IntOption
+
+class ReleaseConfigurationRule(ConfigurationRule):
+ """
+ This rule will modify gitlint's behavior for Release Commits.
+
+ This example might not be the most realistic for a real-world scenario,
+ but is meant to give an overview of what's possible.
+ """
+
+ # A rule MUST have a human friendly name
+ name = "release-configuration-rule"
+
+ # A rule MUST have a *unique* id, we recommend starting with UCR
+ # (for User-defined Configuration-Rule), but this can really be anything.
+ id = "UCR1"
+
+ # A rule MAY have an option_spec if its behavior should be configurable.
+ options_spec = [IntOption('custom-verbosity', 2, "Gitlint verbosity for release commits")]
+
+ def apply(self, config, commit):
+ self.log.debug("ReleaseConfigurationRule: This will be visible when running `gitlint --debug`")
+
+ # If the commit title starts with 'Release', we want to modify
+ # how all subsequent rules interpret that commit
+ if commit.message.title.startswith("Release"):
+
+ # If your Release commit messages are auto-generated, the
+ # body might contain trailing whitespace. Let's ignore that
+ config.ignore.append("body-trailing-whitespace")
+
+ # Similarly, the body lines might exceed 80 chars,
+ # let's set gitlint's limit to 200
+ # To set rule options use:
+ # config.set_rule_option(<rule-name>, <rule-option>, <value>)
+ config.set_rule_option("body-max-line-length", "line-length", 200)
+
+ # For kicks, let's set gitlint's verbosity to 2
+ # To set general options use
+ # config.set_general_option(<general-option>, <value>)
+ config.set_general_option("verbosity", 2)
+ # We can also use custom options to make this configurable
+ config.set_general_option("verbosity", self.options['custom-verbosity'].value)
+
+ # Strip any lines starting with $ from the commit message
+ # (this only affects how gitlint sees your commit message, it does
+ # NOT modify your actual commit in git)
+ commit.message.body = [line for line in commit.message.body if not line.startswith("$")]
+
+ # You can add any extra properties you want to the commit object,
+ # these will be available later on in all rules.
+ commit.my_property = "This is my property"
+```
+
+For all available properties and methods on the `config` object, have a look at the
+[LintConfig class](https://github.com/jorisroovers/gitlint/blob/main/gitlint-core/gitlint/config.py). Please do not use any
+properties or methods starting with an underscore, as those are subject to change.
+
+
+## Rule requirements
As long as you stick with simple rules that are similar to the sample user-defined rules (see the
-[examples](https://github.com/jorisroovers/gitlint/blob/master/examples/my_commit_rules.py) directory), gitlint
+[examples](https://github.com/jorisroovers/gitlint/blob/main/examples/my_commit_rules.py) directory), gitlint
should be able to discover and execute them. While clearly you can run any python code you want in your rules,
you might run into some issues if you don't follow the conventions that gitlint requires.
-While the [rule finding source-code](https://github.com/jorisroovers/gitlint/blob/master/gitlint/rule_finder.py) is the
+While the [rule finding source-code](https://github.com/jorisroovers/gitlint/blob/main/gitlint-core/gitlint/rule_finder.py) is the
ultimate source of truth, here are some of the requirements that gitlint enforces.
-## Rule class requirements ###
+### Rule class requirements
-- Rules **must** extend from ```LineRule``` or ```CommitRule```
-- Rule classes **must** have ```id``` and ```name``` string attributes. The ```options_spec``` is optional,
+- Rules **must** extend from `LineRule`, `CommitRule` or `ConfigurationRule`
+- Rule classes **must** have `id` and `name` string attributes. The `options_spec` is optional,
but if set, it **must** be a list of gitlint Options.
-- 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.
-- LineRule classes **must** have a ```target``` class attributes that is set to either ```CommitMessageTitle``` or ```CommitMessageBody```.
-- User Rule id's **cannot** start with ```R```, ```T```, ```B``` or ```M``` as these rule ids are reserved for gitlint itself.
-- Rules **should** have a case-insensitive unique id as only one rule can exist with a given id. While gitlint does not enforce this, having multiple rules with
- the same id might lead to unexpected or undeterministic behavior.
-
-## extra-path requirements ###
-- If ```extra-path``` is a directory, it does **not** need to be a proper python package, i.e. it doesn't require an ```__init__.py``` file.
-- Python files containing user-defined rules must have a ```.py``` extension. Files with a different extension will be ignored.
-- The ```extra-path``` will be searched non-recursively, i.e. all rule classes must be present at the top level ```extra-path``` directory.
-- User rule classes must be defined in the modules that are part of ```extra-path```, rules that are imported from outside the ```extra-path``` will be ignored.
+- `CommitRule` and `LineRule` 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.
+- `ConfigurationRule` classes **must** have an `apply` method that take `config` and `commit` as first and second parameters.
+- LineRule classes **must** have a `target` class attributes that is set to either `CommitMessageTitle` or `CommitMessageBody`.
+- User Rule id's **cannot** start with `R`, `T`, `B`, `M` or `I` as these rule ids are reserved for gitlint itself.
+- Rules **should** have a case-insensitive unique id as only one rule can exist with a given id. While gitlint does not
+ enforce this, having multiple rules with the same id might lead to unexpected or undeterministic behavior.
+
+### extra-path requirements
+- If `extra-path` is a directory, it does **not** need to be a proper python package, i.e. it doesn't require an `__init__.py` file.
+- Python files containing user-defined rules must have a `.py` extension. Files with a different extension will be ignored.
+- The `extra-path` will be searched non-recursively, i.e. all rule classes must be present at the top level `extra-path` directory.
+- User rule classes must be defined in the modules that are part of `extra-path`, rules that are imported from outside the `extra-path` will be ignored.