summaryrefslogtreecommitdiffstats
path: root/qa
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2020-11-03 06:07:48 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2020-11-03 06:07:48 +0000
commit85812cd25d9e2f015bb71b26d51458b3718bf6c7 (patch)
tree463ad57ffbe3636e06e9bb36104fbf12938e78c1 /qa
parentReleasing debian version 0.13.1-6. (diff)
downloadgitlint-85812cd25d9e2f015bb71b26d51458b3718bf6c7.tar.xz
gitlint-85812cd25d9e2f015bb71b26d51458b3718bf6c7.zip
Merging upstream version 0.14.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'qa')
-rw-r--r--qa/base.py19
-rw-r--r--qa/expected/test_commits/test_lint_staged_msg_filename_115
-rw-r--r--qa/expected/test_commits/test_lint_staged_stdin_115
-rw-r--r--qa/expected/test_config/test_config_from_env_193
-rw-r--r--qa/expected/test_config/test_config_from_env_283
-rw-r--r--qa/expected/test_config/test_config_from_file_debug_115
-rw-r--r--qa/expected/test_contrib/test_contrib_rules_12
-rw-r--r--qa/expected/test_named_rules/test_named_rule_15
-rw-r--r--qa/expected/test_named_rules/test_named_user_rule_19
-rw-r--r--qa/expected/test_user_defined/test_user_defined_rules_examples_24
-rw-r--r--qa/expected/test_user_defined/test_user_defined_rules_extra_16
-rw-r--r--qa/samples/config/contrib-enabled0
-rw-r--r--qa/samples/config/named-rules8
-rw-r--r--qa/samples/config/named-user-rules15
-rw-r--r--qa/samples/user_rules/extra/extra_rules.py52
-rw-r--r--qa/shell.py7
-rw-r--r--qa/test_config.py43
-rw-r--r--qa/test_gitlint.py22
-rw-r--r--qa/test_hooks.py12
-rw-r--r--qa/test_named_rules.py23
-rw-r--r--qa/test_user_defined.py17
-rw-r--r--qa/utils.py18
22 files changed, 457 insertions, 26 deletions
diff --git a/qa/base.py b/qa/base.py
index 05d85e5..f9e520a 100644
--- a/qa/base.py
+++ b/qa/base.py
@@ -93,6 +93,19 @@ class BaseTestCase(TestCase):
io.open(os.path.join(parent_dir, test_filename), 'a', encoding=DEFAULT_ENCODING).close()
return test_filename
+ @staticmethod
+ def create_environment(envvars=None):
+ """ Creates a copy of the current os.environ and adds/overwrites a given set of variables to it """
+ environment = os.environ.copy()
+ if envvars:
+ environment.update(envvars)
+ return environment
+
+ def create_tmp_git_config(self, contents):
+ """ Creates an environment with the GIT_CONFIG variable set to a file with the given contents. """
+ tmp_config = self.create_tmpfile(contents)
+ return self.create_environment({"GIT_CONFIG": tmp_config})
+
def create_simple_commit(self, message, out=None, ok_code=None, env=None, git_repo=None, tty_in=False):
""" Creates a simple commit with an empty test file.
:param message: Commit message for the commit. """
@@ -103,9 +116,7 @@ class BaseTestCase(TestCase):
# variables can influence how git runs.
# This was needed to fix https://github.com/jorisroovers/gitlint/issues/15 as we need to make sure to use
# the PATH variable that contains the virtualenv's python binary.
- environment = os.environ
- if env:
- environment.update(env)
+ environment = self.create_environment(env)
# Create file and add to git
test_filename = self.create_file(git_repo)
@@ -164,7 +175,7 @@ class BaseTestCase(TestCase):
expected_git_version = git("--version").replace("\n", "")
return {'platform': platform.platform(), 'python_version': sys.version,
'git_version': expected_git_version, 'gitlint_version': expected_gitlint_version,
- 'GITLINT_USE_SH_LIB': BaseTestCase.GITLINT_USE_SH_LIB}
+ 'GITLINT_USE_SH_LIB': BaseTestCase.GITLINT_USE_SH_LIB, 'DEFAULT_ENCODING': DEFAULT_ENCODING}
def get_debug_vars_last_commit(self, git_repo=None):
""" Returns a dict with items related to `gitlint --debug` output for the last commit. """
diff --git a/qa/expected/test_commits/test_lint_staged_msg_filename_1 b/qa/expected/test_commits/test_lint_staged_msg_filename_1
index 878bc4c..eb2682f 100644
--- a/qa/expected/test_commits/test_lint_staged_msg_filename_1
+++ b/qa/expected/test_commits/test_lint_staged_msg_filename_1
@@ -1,9 +1,11 @@
DEBUG: gitlint.cli To report issues, please visit https://github.com/jorisroovers/gitlint/issues
DEBUG: gitlint.cli Platform: {platform}
DEBUG: gitlint.cli Python version: {python_version}
+DEBUG: gitlint.git ('--version',)
DEBUG: gitlint.cli Git version: {git_version}
DEBUG: gitlint.cli Gitlint version: {gitlint_version}
DEBUG: gitlint.cli GITLINT_USE_SH_LIB: {GITLINT_USE_SH_LIB}
+DEBUG: gitlint.cli DEFAULT_ENCODING: {DEFAULT_ENCODING}
DEBUG: gitlint.cli Configuration
config-path: None
[GENERAL]
@@ -26,6 +28,8 @@ target: {target}
I2: ignore-by-body
ignore=all
regex=None
+ I3: ignore-body-lines
+ regex=None
T1: title-max-length
line-length=72
T2: title-trailing-whitespace
@@ -35,7 +39,9 @@ target: {target}
T5: title-must-not-contain-word
words=WIP
T7: title-match-regex
- regex=.*
+ regex=None
+ T8: title-min-length
+ min-length=5
B1: body-max-line-length
line-length=80
B5: body-min-length
@@ -47,13 +53,20 @@ target: {target}
B4: body-first-line-empty
B7: body-changed-file-mention
files=
+ B8: body-match-regex
+ regex=None
M1: author-valid-email
regex=[^@ ]+@[^@ ]+\.[^@ ]+
DEBUG: gitlint.cli Fetching additional meta-data from staged commit
DEBUG: gitlint.cli Using --msg-filename.
+DEBUG: gitlint.git ('config', '--get', 'core.commentchar')
DEBUG: gitlint.cli Linting 1 commit(s)
DEBUG: gitlint.lint Linting commit [SHA UNKNOWN]
+DEBUG: gitlint.git ('config', '--get', 'user.name')
+DEBUG: gitlint.git ('config', '--get', 'user.email')
+DEBUG: gitlint.git ('rev-parse', '--abbrev-ref', 'HEAD')
+DEBUG: gitlint.git ('diff', '--staged', '--name-only', '-r')
DEBUG: gitlint.lint Commit Object
--- Commit Message ----
WIP: from fïle test.
diff --git a/qa/expected/test_commits/test_lint_staged_stdin_1 b/qa/expected/test_commits/test_lint_staged_stdin_1
index 3f178f8..76b5048 100644
--- a/qa/expected/test_commits/test_lint_staged_stdin_1
+++ b/qa/expected/test_commits/test_lint_staged_stdin_1
@@ -1,9 +1,11 @@
DEBUG: gitlint.cli To report issues, please visit https://github.com/jorisroovers/gitlint/issues
DEBUG: gitlint.cli Platform: {platform}
DEBUG: gitlint.cli Python version: {python_version}
+DEBUG: gitlint.git ('--version',)
DEBUG: gitlint.cli Git version: {git_version}
DEBUG: gitlint.cli Gitlint version: {gitlint_version}
DEBUG: gitlint.cli GITLINT_USE_SH_LIB: {GITLINT_USE_SH_LIB}
+DEBUG: gitlint.cli DEFAULT_ENCODING: {DEFAULT_ENCODING}
DEBUG: gitlint.cli Configuration
config-path: None
[GENERAL]
@@ -26,6 +28,8 @@ target: {target}
I2: ignore-by-body
ignore=all
regex=None
+ I3: ignore-body-lines
+ regex=None
T1: title-max-length
line-length=72
T2: title-trailing-whitespace
@@ -35,7 +39,9 @@ target: {target}
T5: title-must-not-contain-word
words=WIP
T7: title-match-regex
- regex=.*
+ regex=None
+ T8: title-min-length
+ min-length=5
B1: body-max-line-length
line-length=80
B5: body-min-length
@@ -47,6 +53,8 @@ target: {target}
B4: body-first-line-empty
B7: body-changed-file-mention
files=
+ B8: body-match-regex
+ regex=None
M1: author-valid-email
regex=[^@ ]+@[^@ ]+\.[^@ ]+
@@ -54,8 +62,13 @@ DEBUG: gitlint.cli Fetching additional meta-data from staged commit
DEBUG: gitlint.cli Stdin data: 'WIP: Pïpe test.
'
DEBUG: gitlint.cli Stdin detected and not ignored. Using as input.
+DEBUG: gitlint.git ('config', '--get', 'core.commentchar')
DEBUG: gitlint.cli Linting 1 commit(s)
DEBUG: gitlint.lint Linting commit [SHA UNKNOWN]
+DEBUG: gitlint.git ('config', '--get', 'user.name')
+DEBUG: gitlint.git ('config', '--get', 'user.email')
+DEBUG: gitlint.git ('rev-parse', '--abbrev-ref', 'HEAD')
+DEBUG: gitlint.git ('diff', '--staged', '--name-only', '-r')
DEBUG: gitlint.lint Commit Object
--- Commit Message ----
WIP: Pïpe test.
diff --git a/qa/expected/test_config/test_config_from_env_1 b/qa/expected/test_config/test_config_from_env_1
new file mode 100644
index 0000000..dd761da
--- /dev/null
+++ b/qa/expected/test_config/test_config_from_env_1
@@ -0,0 +1,93 @@
+DEBUG: gitlint.cli To report issues, please visit https://github.com/jorisroovers/gitlint/issues
+DEBUG: gitlint.cli Platform: {platform}
+DEBUG: gitlint.cli Python version: {python_version}
+DEBUG: gitlint.git ('--version',)
+DEBUG: gitlint.cli Git version: {git_version}
+DEBUG: gitlint.cli Gitlint version: {gitlint_version}
+DEBUG: gitlint.cli GITLINT_USE_SH_LIB: {GITLINT_USE_SH_LIB}
+DEBUG: gitlint.cli DEFAULT_ENCODING: {DEFAULT_ENCODING}
+DEBUG: gitlint.cli Configuration
+config-path: None
+[GENERAL]
+extra-path: None
+contrib: ['CC1', 'CT1']
+ignore: T1,T2
+ignore-merge-commits: True
+ignore-fixup-commits: True
+ignore-squash-commits: True
+ignore-revert-commits: True
+ignore-stdin: True
+staged: False
+verbosity: 2
+debug: True
+target: {target}
+[RULES]
+ I1: ignore-by-title
+ ignore=all
+ regex=None
+ I2: ignore-by-body
+ ignore=all
+ regex=None
+ I3: ignore-body-lines
+ regex=None
+ T1: title-max-length
+ line-length=72
+ T2: title-trailing-whitespace
+ T6: title-leading-whitespace
+ T3: title-trailing-punctuation
+ T4: title-hard-tab
+ T5: title-must-not-contain-word
+ words=WIP
+ T7: title-match-regex
+ regex=None
+ T8: title-min-length
+ min-length=5
+ B1: body-max-line-length
+ line-length=80
+ B5: body-min-length
+ min-length=20
+ B6: body-is-missing
+ ignore-merge-commits=True
+ B2: body-trailing-whitespace
+ B3: body-hard-tab
+ B4: body-first-line-empty
+ B7: body-changed-file-mention
+ files=
+ B8: body-match-regex
+ regex=None
+ M1: author-valid-email
+ regex=[^@ ]+@[^@ ]+\.[^@ ]+
+ CC1: contrib-body-requires-signed-off-by
+ CT1: contrib-title-conventional-commits
+ types=fix,feat,chore,docs,style,refactor,perf,test,revert,ci,build
+
+DEBUG: gitlint.cli No --msg-filename flag, no or empty data passed to stdin. Using the local repo.
+DEBUG: gitlint.git ('rev-list', '{commit_sha}')
+DEBUG: gitlint.cli Linting 1 commit(s)
+DEBUG: gitlint.git ('log', '{commit_sha}', '-1', '--pretty=%aN%x00%aE%x00%ai%x00%P%n%B')
+DEBUG: gitlint.git ('config', '--get', 'core.commentchar')
+DEBUG: gitlint.lint Linting commit {commit_sha}
+DEBUG: gitlint.git ('branch', '--contains', '{commit_sha}')
+DEBUG: gitlint.git ('diff-tree', '--no-commit-id', '--name-only', '-r', '--root', '{commit_sha}')
+DEBUG: gitlint.lint Commit Object
+--- Commit Message ----
+WIP: Thïs is a title thåt is a bit longer.
+Content on the second line
+This line of the body is here because we need it
+
+--- Meta info ---------
+Author: gitlint-test-user <gitlint@test.com>
+Date: {commit_date}
+is-merge-commit: False
+is-fixup-commit: False
+is-squash-commit: False
+is-revert-commit: False
+Branches: ['master']
+Changed Files: {changed_files}
+-----------------------
+1: CC1 Body does not contain a 'Signed-Off-By' line
+1: CT1 Title does not start with one of fix, feat, chore, docs, style, refactor, perf, test, revert, ci, build
+1: T3 Title has trailing punctuation (.)
+1: T5 Title contains the word 'WIP' (case-insensitive)
+2: B4 Second line is not empty
+DEBUG: gitlint.cli Exit Code = 5
diff --git a/qa/expected/test_config/test_config_from_env_2 b/qa/expected/test_config/test_config_from_env_2
new file mode 100644
index 0000000..8d36672
--- /dev/null
+++ b/qa/expected/test_config/test_config_from_env_2
@@ -0,0 +1,83 @@
+DEBUG: gitlint.cli To report issues, please visit https://github.com/jorisroovers/gitlint/issues
+DEBUG: gitlint.cli Platform: {platform}
+DEBUG: gitlint.cli Python version: {python_version}
+DEBUG: gitlint.git ('--version',)
+DEBUG: gitlint.cli Git version: {git_version}
+DEBUG: gitlint.cli Gitlint version: {gitlint_version}
+DEBUG: gitlint.cli GITLINT_USE_SH_LIB: {GITLINT_USE_SH_LIB}
+DEBUG: gitlint.cli DEFAULT_ENCODING: {DEFAULT_ENCODING}
+DEBUG: gitlint.cli Configuration
+config-path: None
+[GENERAL]
+extra-path: None
+contrib: []
+ignore:
+ignore-merge-commits: True
+ignore-fixup-commits: True
+ignore-squash-commits: True
+ignore-revert-commits: True
+ignore-stdin: False
+staged: True
+verbosity: 0
+debug: True
+target: {target}
+[RULES]
+ I1: ignore-by-title
+ ignore=all
+ regex=None
+ I2: ignore-by-body
+ ignore=all
+ regex=None
+ I3: ignore-body-lines
+ regex=None
+ T1: title-max-length
+ line-length=72
+ T2: title-trailing-whitespace
+ T6: title-leading-whitespace
+ T3: title-trailing-punctuation
+ T4: title-hard-tab
+ T5: title-must-not-contain-word
+ words=WIP
+ T7: title-match-regex
+ regex=None
+ T8: title-min-length
+ min-length=5
+ B1: body-max-line-length
+ line-length=80
+ B5: body-min-length
+ min-length=20
+ B6: body-is-missing
+ ignore-merge-commits=True
+ B2: body-trailing-whitespace
+ B3: body-hard-tab
+ B4: body-first-line-empty
+ B7: body-changed-file-mention
+ files=
+ B8: body-match-regex
+ regex=None
+ M1: author-valid-email
+ regex=[^@ ]+@[^@ ]+\.[^@ ]+
+
+DEBUG: gitlint.cli Fetching additional meta-data from staged commit
+DEBUG: gitlint.cli Using --msg-filename.
+DEBUG: gitlint.git ('config', '--get', 'core.commentchar')
+DEBUG: gitlint.cli Linting 1 commit(s)
+DEBUG: gitlint.lint Linting commit [SHA UNKNOWN]
+DEBUG: gitlint.git ('config', '--get', 'user.name')
+DEBUG: gitlint.git ('config', '--get', 'user.email')
+DEBUG: gitlint.git ('rev-parse', '--abbrev-ref', 'HEAD')
+DEBUG: gitlint.git ('diff', '--staged', '--name-only', '-r')
+DEBUG: gitlint.lint Commit Object
+--- Commit Message ----
+WIP: msg-fïlename test.
+--- Meta info ---------
+Author: gitlint-test-user <gitlint@test.com>
+Date: {date}
+is-merge-commit: False
+is-fixup-commit: False
+is-squash-commit: False
+is-revert-commit: False
+Branches: ['master']
+Changed Files: []
+-----------------------
+DEBUG: gitlint.cli Exit Code = 3
diff --git a/qa/expected/test_config/test_config_from_file_debug_1 b/qa/expected/test_config/test_config_from_file_debug_1
index 443ee26..540c3a0 100644
--- a/qa/expected/test_config/test_config_from_file_debug_1
+++ b/qa/expected/test_config/test_config_from_file_debug_1
@@ -1,9 +1,11 @@
DEBUG: gitlint.cli To report issues, please visit https://github.com/jorisroovers/gitlint/issues
DEBUG: gitlint.cli Platform: {platform}
DEBUG: gitlint.cli Python version: {python_version}
+DEBUG: gitlint.git ('--version',)
DEBUG: gitlint.cli Git version: {git_version}
DEBUG: gitlint.cli Gitlint version: {gitlint_version}
DEBUG: gitlint.cli GITLINT_USE_SH_LIB: {GITLINT_USE_SH_LIB}
+DEBUG: gitlint.cli DEFAULT_ENCODING: {DEFAULT_ENCODING}
DEBUG: gitlint.cli Configuration
config-path: {config_path}
[GENERAL]
@@ -26,6 +28,8 @@ target: {target}
I2: ignore-by-body
ignore=all
regex=None
+ I3: ignore-body-lines
+ regex=None
T1: title-max-length
line-length=20
T2: title-trailing-whitespace
@@ -35,7 +39,9 @@ target: {target}
T5: title-must-not-contain-word
words=WIP,thåt
T7: title-match-regex
- regex=.*
+ regex=None
+ T8: title-min-length
+ min-length=5
B1: body-max-line-length
line-length=30
B5: body-min-length
@@ -47,12 +53,19 @@ target: {target}
B4: body-first-line-empty
B7: body-changed-file-mention
files=
+ B8: body-match-regex
+ regex=None
M1: author-valid-email
regex=[^@ ]+@[^@ ]+\.[^@ ]+
DEBUG: gitlint.cli No --msg-filename flag, no or empty data passed to stdin. Using the local repo.
+DEBUG: gitlint.git ('log', '-1', '--pretty=%H')
DEBUG: gitlint.cli Linting 1 commit(s)
+DEBUG: gitlint.git ('log', '{commit_sha}', '-1', '--pretty=%aN%x00%aE%x00%ai%x00%P%n%B')
+DEBUG: gitlint.git ('config', '--get', 'core.commentchar')
DEBUG: gitlint.lint Linting commit {commit_sha}
+DEBUG: gitlint.git ('branch', '--contains', '{commit_sha}')
+DEBUG: gitlint.git ('diff-tree', '--no-commit-id', '--name-only', '-r', '--root', '{commit_sha}')
DEBUG: gitlint.lint Commit Object
--- Commit Message ----
WIP: Thïs is a title thåt is a bit longer.
diff --git a/qa/expected/test_contrib/test_contrib_rules_1 b/qa/expected/test_contrib/test_contrib_rules_1
index 99b33b7..0d333bc 100644
--- a/qa/expected/test_contrib/test_contrib_rules_1
+++ b/qa/expected/test_contrib/test_contrib_rules_1
@@ -1,4 +1,4 @@
1: CC1 Body does not contain a 'Signed-Off-By' line
-1: CT1 Title does not start with one of fix, feat, chore, docs, style, refactor, perf, test, revert: "WIP Thi$ is å title"
+1: CT1 Title does not start with one of fix, feat, chore, docs, style, refactor, perf, test, revert, ci, build: "WIP Thi$ is å title"
1: CT1 Title does not follow ConventionalCommits.org format 'type(optional-scope): description': "WIP Thi$ is å title"
1: T5 Title contains the word 'WIP' (case-insensitive): "WIP Thi$ is å title"
diff --git a/qa/expected/test_named_rules/test_named_rule_1 b/qa/expected/test_named_rules/test_named_rule_1
new file mode 100644
index 0000000..e5a380c
--- /dev/null
+++ b/qa/expected/test_named_rules/test_named_rule_1
@@ -0,0 +1,5 @@
+1: T5 Title contains the word 'WIP' (case-insensitive): "WIP: thåt dûr bår"
+1: T5 Title contains the word 'thåt' (case-insensitive): "WIP: thåt dûr bår"
+1: T5:even$more%wôrds Title contains the word 'bår' (case-insensitive): "WIP: thåt dûr bår"
+1: T5:extra-wôrds Title contains the word 'dûr' (case-insensitive): "WIP: thåt dûr bår"
+3: B5 Body message is too short (18<20): "Sïmple commit body"
diff --git a/qa/expected/test_named_rules/test_named_user_rule_1 b/qa/expected/test_named_rules/test_named_user_rule_1
new file mode 100644
index 0000000..3cd18b4
--- /dev/null
+++ b/qa/expected/test_named_rules/test_named_user_rule_1
@@ -0,0 +1,9 @@
+1: UC4 int-öption: 2
+1: UC4 str-öption: föo
+1: UC4 list-öption: ['foo', 'bar']
+1: UC4:bår int-öption: 2
+1: UC4:bår str-öption: bår
+1: UC4:bår list-öption: ['bar', 'list']
+1: UC4:föo int-öption: 3
+1: UC4:föo str-öption: föo
+1: UC4:föo list-öption: ['foo', 'bar']
diff --git a/qa/expected/test_user_defined/test_user_defined_rules_examples_2 b/qa/expected/test_user_defined/test_user_defined_rules_examples_2
new file mode 100644
index 0000000..31a9280
--- /dev/null
+++ b/qa/expected/test_user_defined/test_user_defined_rules_examples_2
@@ -0,0 +1,4 @@
+1: UC2 Body does not contain a 'Signed-Off-By' line
+1: UC3 Branch name 'master' does not start with one of ['feature/', 'hotfix/', 'release/']
+1: UL1 Title contains the special character '$'
+2: B4 Second line is not empty
diff --git a/qa/expected/test_user_defined/test_user_defined_rules_extra_1 b/qa/expected/test_user_defined/test_user_defined_rules_extra_1
index 65f3507..1f48fad 100644
--- a/qa/expected/test_user_defined/test_user_defined_rules_extra_1
+++ b/qa/expected/test_user_defined/test_user_defined_rules_extra_1
@@ -2,4 +2,8 @@
1: UC1 GitContext.current_branch: master
1: UC1 GitContext.commentchar: #
1: UC2 GitCommit.branches: ['master']
-2: B4 Second line is not empty: "Content on the second line"
+1: UC2 GitCommit.custom_prop: foöbar
+1: UC4 int-öption: 2
+1: UC4 str-öption: föo
+1: UC4 list-öption: ['foo', 'bar']
+4: B2 Line has trailing whitespace: "{repo-path} "
diff --git a/qa/samples/config/contrib-enabled b/qa/samples/config/contrib-enabled
deleted file mode 100644
index e69de29..0000000
--- a/qa/samples/config/contrib-enabled
+++ /dev/null
diff --git a/qa/samples/config/named-rules b/qa/samples/config/named-rules
new file mode 100644
index 0000000..f9bbdf5
--- /dev/null
+++ b/qa/samples/config/named-rules
@@ -0,0 +1,8 @@
+[title-must-not-contain-word]
+words=WIP,thåt
+
+[title-must-not-contain-word:extra-wôrds]
+words=hûr,dûr
+
+[title-must-not-contain-word: even$more%wôrds ]
+words=fôo,bår \ No newline at end of file
diff --git a/qa/samples/config/named-user-rules b/qa/samples/config/named-user-rules
new file mode 100644
index 0000000..ed811fb
--- /dev/null
+++ b/qa/samples/config/named-user-rules
@@ -0,0 +1,15 @@
+# Ignore other user-defined rules
+[general]
+ignore=UC1,UC2,UC3,configürable:ignöred
+
+[UC4:föo]
+int-öption=3
+str-öption=föo
+
+[configürable:bår]
+str-öption=bår
+list-öption=bar,list
+
+# The following rule will be ignored
+[configürable:ignöred]
+str-öption=foöbar \ No newline at end of file
diff --git a/qa/samples/user_rules/extra/extra_rules.py b/qa/samples/user_rules/extra/extra_rules.py
index 8109299..6fb985f 100644
--- a/qa/samples/user_rules/extra/extra_rules.py
+++ b/qa/samples/user_rules/extra/extra_rules.py
@@ -1,16 +1,19 @@
-from gitlint.rules import CommitRule, RuleViolation
+# -*- coding: utf-8 -*-
+
+from gitlint.rules import CommitRule, RuleViolation, ConfigurationRule
+from gitlint.options import IntOption, StrOption, ListOption
from gitlint.utils import sstr
class GitContextRule(CommitRule):
""" Rule that tests whether we can correctly access certain gitcontext properties """
- name = "gitcontext"
+ name = u"gïtcontext"
id = "UC1"
def validate(self, commit):
violations = [
- RuleViolation(self.id, "GitContext.current_branch: {0}".format(commit.context.current_branch), line_nr=1),
- RuleViolation(self.id, "GitContext.commentchar: {0}".format(commit.context.commentchar), line_nr=1)
+ RuleViolation(self.id, u"GitContext.current_branch: {0}".format(commit.context.current_branch), line_nr=1),
+ RuleViolation(self.id, u"GitContext.commentchar: {0}".format(commit.context.commentchar), line_nr=1)
]
return violations
@@ -18,12 +21,49 @@ class GitContextRule(CommitRule):
class GitCommitRule(CommitRule):
""" Rule that tests whether we can correctly access certain commit properties """
- name = "gitcommit"
+ name = u"gïtcommit"
id = "UC2"
def validate(self, commit):
violations = [
- RuleViolation(self.id, "GitCommit.branches: {0}".format(sstr(commit.branches)), line_nr=1),
+ RuleViolation(self.id, u"GitCommit.branches: {0}".format(sstr(commit.branches)), line_nr=1),
+ RuleViolation(self.id, u"GitCommit.custom_prop: {0}".format(commit.custom_prop), line_nr=1),
+ ]
+
+ return violations
+
+
+class GitlintConfigurationRule(ConfigurationRule):
+ """ Rule that tests whether we can correctly access the config as well as modify the commit message """
+ name = u"cönfigrule"
+ id = "UC3"
+
+ def apply(self, config, commit):
+ # We add a line to the commit message body that pulls a value from config, this proves we can modify the body
+ # and read the config contents
+ commit.message.body.append("{0} ".format(config.target)) # trailing whitespace deliberate to trigger violation
+
+ # We set a custom property that we access in CommitRule, to prove we can add extra properties to the commit
+ commit.custom_prop = u"foöbar"
+
+ # We also ignore some extra rules, proving that we can modify the config
+ config.ignore.append("B4")
+
+
+class ConfigurableCommitRule(CommitRule):
+ """ Rule that tests that we can add configuration to user-defined rules """
+ name = u"configürable"
+ id = "UC4"
+
+ options_spec = [IntOption(u"int-öption", 2, u"int-öption description"),
+ StrOption(u"str-öption", u"föo", u"int-öption description"),
+ ListOption(u"list-öption", [u"foo", u"bar"], u"list-öption description")]
+
+ def validate(self, _):
+ violations = [
+ RuleViolation(self.id, u"int-öption: {0}".format(self.options[u'int-öption'].value), line_nr=1),
+ RuleViolation(self.id, u"str-öption: {0}".format(self.options[u'str-öption'].value), line_nr=1),
+ RuleViolation(self.id, u"list-öption: {0}".format(sstr(self.options[u'list-öption'].value)), line_nr=1),
]
return violations
diff --git a/qa/shell.py b/qa/shell.py
index 8ba6dc1..43e5bbd 100644
--- a/qa/shell.py
+++ b/qa/shell.py
@@ -3,8 +3,7 @@
# on gitlint internals for our integration testing framework.
import subprocess
-import sys
-from qa.utils import ustr, USE_SH_LIB
+from qa.utils import ustr, USE_SH_LIB, IS_PY2
if USE_SH_LIB:
from sh import git, echo, gitlint # pylint: disable=unused-import,no-name-in-module,import-error
@@ -59,7 +58,7 @@ else:
return ustr(result)
def _exec(*args, **kwargs):
- if sys.version_info[0] == 2:
+ if IS_PY2:
no_command_error = OSError # noqa pylint: disable=undefined-variable,invalid-name
else:
no_command_error = FileNotFoundError # noqa pylint: disable=undefined-variable
@@ -68,6 +67,8 @@ else:
popen_kwargs = {'stdout': pipe, 'stderr': pipe, 'shell': kwargs.get('_tty_out', False)}
if '_cwd' in kwargs:
popen_kwargs['cwd'] = kwargs['_cwd']
+ if '_env' in kwargs:
+ popen_kwargs['env'] = kwargs['_env']
try:
p = subprocess.Popen(args, **popen_kwargs)
diff --git a/qa/test_config.py b/qa/test_config.py
index b893b1d..9415990 100644
--- a/qa/test_config.py
+++ b/qa/test_config.py
@@ -1,8 +1,11 @@
# -*- coding: utf-8 -*-
# pylint: disable=too-many-function-args,unexpected-keyword-arg
+
+import re
+
from qa.shell import gitlint
from qa.base import BaseTestCase
-from qa.utils import sstr
+from qa.utils import sstr, ustr
class ConfigTests(BaseTestCase):
@@ -52,7 +55,7 @@ class ConfigTests(BaseTestCase):
self.assertEqualStdout(output, self.get_expected("test_config/test_config_from_file_1"))
def test_config_from_file_debug(self):
- # Test bot on existing and new repo (we've had a bug in the past that was unique to empty repos)
+ # Test both on existing and new repo (we've had a bug in the past that was unique to empty repos)
repos = [self.tmp_git_repo, self.create_tmp_git_repo()]
for target_repo in repos:
commit_msg = u"WIP: Thïs is a title thåt is a bit longer.\nContent on the second line\n" + \
@@ -65,3 +68,39 @@ class ConfigTests(BaseTestCase):
expected_kwargs.update({'config_path': config_path, 'changed_files': sstr([filename])})
self.assertEqualStdout(output, self.get_expected("test_config/test_config_from_file_debug_1",
expected_kwargs))
+
+ def test_config_from_env(self):
+ """ Test for configuring gitlint from environment variables """
+
+ # We invoke gitlint, configuring it via env variables, we can check whether gitlint picks these up correctly
+ # by comparing the debug output with what we'd expect
+ target_repo = self.create_tmp_git_repo()
+ commit_msg = u"WIP: Thïs is a title thåt is a bit longer.\nContent on the second line\n" + \
+ "This line of the body is here because we need it"
+ filename = self.create_simple_commit(commit_msg, git_repo=target_repo)
+ env = self.create_environment({"GITLINT_DEBUG": "1", "GITLINT_VERBOSITY": "2",
+ "GITLINT_IGNORE": "T1,T2", "GITLINT_CONTRIB": "CC1,CT1",
+ "GITLINT_IGNORE_STDIN": "1", "GITLINT_TARGET": target_repo,
+ "GITLINT_COMMITS": self.get_last_commit_hash(git_repo=target_repo)})
+ output = gitlint(_env=env, _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[5])
+ expected_kwargs = self.get_debug_vars_last_commit(git_repo=target_repo)
+ expected_kwargs.update({'changed_files': sstr([filename])})
+
+ self.assertEqualStdout(output, self.get_expected("test_config/test_config_from_env_1", expected_kwargs))
+
+ # For some env variables, we need a separate test ast they are mutually exclusive with the ones tested above
+ tmp_commit_msg_file = self.create_tmpfile(u"WIP: msg-fïlename test.")
+ env = self.create_environment({"GITLINT_DEBUG": "1", "GITLINT_TARGET": target_repo,
+ "GITLINT_SILENT": "1", "GITLINT_STAGED": "1"})
+
+ output = gitlint("--msg-filename", tmp_commit_msg_file,
+ _env=env, _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[3])
+
+ # Extract date from actual output to insert it into the expected output
+ # We have to do this since there's no way for us to deterministically know that date otherwise
+ p = re.compile("Date: (.*)\n", re.UNICODE | re.MULTILINE)
+ result = p.search(ustr(output.stdout))
+ date = result.group(1).strip()
+ expected_kwargs.update({"date": date})
+
+ self.assertEqualStdout(output, self.get_expected("test_config/test_config_from_env_2", expected_kwargs))
diff --git a/qa/test_gitlint.py b/qa/test_gitlint.py
index 4762721..2e837b9 100644
--- a/qa/test_gitlint.py
+++ b/qa/test_gitlint.py
@@ -157,6 +157,28 @@ class IntegrationTests(BaseTestCase):
self.assertEqualStdout(output, self.get_expected("test_gitlint/test_msg_filename_no_tty_1"))
+ def test_no_git_name_set(self):
+ """ Ensure we print out a helpful message if user.name is not set """
+ tmp_commit_msg_file = self.create_tmpfile(u"WIP: msg-fïlename NO name test.")
+ # Name is checked before email so this isn't strictly
+ # necessary but seems good for consistency.
+ env = self.create_tmp_git_config(u"[user]\n email = test-emåil@foo.com\n")
+ output = gitlint("--staged", "--msg-filename", tmp_commit_msg_file,
+ _ok_code=[self.GIT_CONTEXT_ERROR_CODE],
+ _env=env)
+ expected = u"Missing git configuration: please set user.name\n"
+ self.assertEqualStdout(output, expected)
+
+ def test_no_git_email_set(self):
+ """ Ensure we print out a helpful message if user.email is not set """
+ tmp_commit_msg_file = self.create_tmpfile(u"WIP: msg-fïlename NO email test.")
+ env = self.create_tmp_git_config(u"[user]\n name = test åuthor\n")
+ output = gitlint("--staged", "--msg-filename", tmp_commit_msg_file,
+ _ok_code=[self.GIT_CONTEXT_ERROR_CODE],
+ _env=env)
+ expected = u"Missing git configuration: please set user.email\n"
+ self.assertEqualStdout(output, expected)
+
def test_git_errors(self):
# Repo has no commits: caused by `git log`
empty_git_repo = self.create_tmp_git_repo()
diff --git a/qa/test_hooks.py b/qa/test_hooks.py
index a41580b..7c07a61 100644
--- a/qa/test_hooks.py
+++ b/qa/test_hooks.py
@@ -53,6 +53,18 @@ class HookTests(BaseTestCase):
stdin.put("{0}\n".format(response))
self.response_index = (self.response_index + 1) % len(self.responses)
+ def test_commit_hook_no_violations(self):
+ test_filename = self.create_simple_commit(u"This ïs a title\n\nBody contënt that should work",
+ out=self._interact, tty_in=True)
+
+ short_hash = self.get_last_commit_short_hash()
+ expected_output = ["gitlint: checking commit message...\n",
+ "gitlint: \x1b[32mOK\x1b[0m (no violations in commit message)\n",
+ u"[master %s] This ïs a title\n" % short_hash,
+ " 1 file changed, 0 insertions(+), 0 deletions(-)\n",
+ u" create mode 100644 %s\n" % test_filename]
+ self.assertListEqual(expected_output, self.githook_output)
+
def test_commit_hook_continue(self):
self.responses = ["y"]
test_filename = self.create_simple_commit(u"WIP: This ïs a title.\nContënt on the second line",
diff --git a/qa/test_named_rules.py b/qa/test_named_rules.py
new file mode 100644
index 0000000..6020bbf
--- /dev/null
+++ b/qa/test_named_rules.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+from qa.shell import gitlint
+from qa.base import BaseTestCase
+
+
+class NamedRuleTests(BaseTestCase):
+ """ Integration tests for named rules."""
+
+ def test_named_rule(self):
+ commit_msg = u"WIP: thåt dûr bår\n\nSïmple commit body"
+ self.create_simple_commit(commit_msg)
+ config_path = self.get_sample_path("config/named-rules")
+ output = gitlint("--config", config_path, _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[5])
+ self.assertEqualStdout(output, self.get_expected("test_named_rules/test_named_rule_1"))
+
+ def test_named_user_rule(self):
+ commit_msg = u"Normal cömmit title\n\nSïmple commit message body"
+ self.create_simple_commit(commit_msg)
+ config_path = self.get_sample_path("config/named-user-rules")
+ extra_path = self.get_sample_path("user_rules/extra")
+ output = gitlint("--extra-path", extra_path, "--config", config_path, _cwd=self.tmp_git_repo, _tty_in=True,
+ _ok_code=[9])
+ self.assertEqualStdout(output, self.get_expected("test_named_rules/test_named_user_rule_1"))
diff --git a/qa/test_user_defined.py b/qa/test_user_defined.py
index cf7effd..566d0b2 100644
--- a/qa/test_user_defined.py
+++ b/qa/test_user_defined.py
@@ -7,14 +7,24 @@ from qa.base import BaseTestCase
class UserDefinedRuleTests(BaseTestCase):
""" Integration tests for user-defined rules."""
- def test_user_defined_rules_examples(self):
+ def test_user_defined_rules_examples1(self):
+ """ Test the user defined rules in the top-level `examples/` directory """
extra_path = self.get_example_path()
commit_msg = u"WIP: Thi$ is å title\nContent on the second line"
self.create_simple_commit(commit_msg)
output = gitlint("--extra-path", extra_path, _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[5])
self.assertEqualStdout(output, self.get_expected("test_user_defined/test_user_defined_rules_examples_1"))
+ def test_user_defined_rules_examples2(self):
+ """ Test the user defined rules in the top-level `examples/` directory """
+ extra_path = self.get_example_path()
+ commit_msg = u"Release: Thi$ is å title\nContent on the second line\n$This line is ignored \nThis isn't\t\n"
+ self.create_simple_commit(commit_msg)
+ output = gitlint("--extra-path", extra_path, _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[4])
+ self.assertEqualStdout(output, self.get_expected("test_user_defined/test_user_defined_rules_examples_2"))
+
def test_user_defined_rules_examples_with_config(self):
+ """ Test the user defined rules in the top-level `examples/` directory """
extra_path = self.get_example_path()
commit_msg = u"WIP: Thi$ is å title\nContent on the second line"
self.create_simple_commit(commit_msg)
@@ -27,8 +37,9 @@ class UserDefinedRuleTests(BaseTestCase):
extra_path = self.get_sample_path("user_rules/extra")
commit_msg = u"WIP: Thi$ is å title\nContent on the second line"
self.create_simple_commit(commit_msg)
- output = gitlint("--extra-path", extra_path, _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[5])
- self.assertEqualStdout(output, self.get_expected("test_user_defined/test_user_defined_rules_extra_1"))
+ output = gitlint("--extra-path", extra_path, _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[9])
+ self.assertEqualStdout(output, self.get_expected("test_user_defined/test_user_defined_rules_extra_1",
+ {'repo-path': self.tmp_git_repo}))
def test_invalid_user_defined_rules(self):
extra_path = self.get_sample_path("user_rules/incorrect_linerule")
diff --git a/qa/utils.py b/qa/utils.py
index eb9869a..f44917e 100644
--- a/qa/utils.py
+++ b/qa/utils.py
@@ -16,6 +16,16 @@ def platform_is_windows():
PLATFORM_IS_WINDOWS = platform_is_windows()
########################################################################################################################
+# IS_PY2
+
+
+def is_py2():
+ return sys.version_info[0] == 2
+
+
+IS_PY2 = is_py2()
+
+########################################################################################################################
# USE_SH_LIB
# Determine whether to use the `sh` library
# On windows we won't want to use the sh library since it's not supported - instead we'll use our own shell module.
@@ -68,7 +78,7 @@ DEFAULT_ENCODING = getpreferredencoding()
def ustr(obj):
""" Python 2 and 3 utility method that converts an obj to unicode in python 2 and to a str object in python 3"""
- if sys.version_info[0] == 2:
+ if IS_PY2:
# If we are getting a string, then do an explicit decode
# else, just call the unicode method of the object
if type(obj) in [str, basestring]: # pragma: no cover # noqa
@@ -86,11 +96,13 @@ def sstr(obj):
""" Python 2 and 3 utility method that converts an obj to a DEFAULT_ENCODING encoded string in python 2
and to unicode in python 3.
Especially useful for implementing __str__ methods in python 2: http://stackoverflow.com/a/1307210/381010"""
- if sys.version_info[0] == 2:
- # For lists in python2, remove unicode string representation characters.
+ if IS_PY2:
+ # For lists and tuples in python2, remove unicode string representation characters.
# i.e. ensure lists are printed as ['a', 'b'] and not [u'a', u'b']
if type(obj) in [list]:
return [sstr(item) for item in obj] # pragma: no cover # noqa
+ elif type(obj) in [tuple]:
+ return tuple(sstr(item) for item in obj) # pragma: no cover # noqa
return unicode(obj).encode(DEFAULT_ENCODING) # pragma: no cover # noqa
else: