diff options
-rw-r--r-- | docs/user_defined_rules.md | 2 | ||||
-rw-r--r-- | gitlint/git.py | 21 | ||||
-rw-r--r-- | gitlint/tests/test_cli.py | 2 | ||||
-rw-r--r-- | gitlint/tests/test_git.py | 18 | ||||
-rw-r--r-- | qa/expected/debug_output1 | 2 | ||||
-rw-r--r-- | requirements.txt | 1 | ||||
-rw-r--r-- | setup.py | 1 |
7 files changed, 39 insertions, 8 deletions
diff --git a/docs/user_defined_rules.md b/docs/user_defined_rules.md index 1630104..6a142e7 100644 --- a/docs/user_defined_rules.md +++ b/docs/user_defined_rules.md @@ -169,7 +169,7 @@ commit.message.title | string | Title/subject of the commit message: commit.message.body | list of 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 | string | TODO: parse to date obj +commit.date | datetime | Python ```datetime``` object representing the time of commit commit.context | object | Object pointing to the bigger git context that the commit is part of commit.context.commits | list of commit | List of commits in the git context. Note that this might only be the subset of commits that gitlint is acting on, not all commits in the repo. diff --git a/gitlint/git.py b/gitlint/git.py index 923d6c3..a0de1b8 100644 --- a/gitlint/git.py +++ b/gitlint/git.py @@ -1,3 +1,4 @@ +import arrow import sh # import exceptions separately, this makes it a little easier to mock them out in the unit tests from sh import CommandNotFound, ErrorReturnCode @@ -37,6 +38,10 @@ class GitCommitMessage(object): def __repr__(self): return self.__str__() # pragma: no cover + def __eq__(self, other): + return self.original == other.original and self.full == other.full and \ + self.title == other.title and self.body == other.body # noqa + class GitCommit(object): """ Class representing a git commit. @@ -72,6 +77,11 @@ class GitCommit(object): def __repr__(self): return self.__str__() # pragma: no cover + def __eq__(self, other): + # skip checking the context as context refers back to this obj, this will trigger a cyclic dependency + return self.message == other.message and self.author_name == other.author_name and \ + self.author_email == other.autor_email and self.date == other.date # noqa + class GitContext(object): """ Class representing the git context in which gitlint is operating: a data object storing information about @@ -114,7 +124,8 @@ class GitContext(object): commit_msg = sh.git.log("-1", "--pretty=%B", **sh_special_args) commit_author_name = sh.git.log("-1", "--pretty=%aN", **sh_special_args) commit_author_email = sh.git.log("-1", "--pretty=%aE", **sh_special_args) - commit_date = sh.git.log("-1", "--pretty=%aD", **sh_special_args) + # %aI -> ISO 8601-like format, while %aI is strict ISO 8601, it seems to be less widely supporte + commit_date_str = sh.git.log("-1", "--pretty=%ai", **sh_special_args) commit_parents = sh.git.log("-1", "--pretty=%P", **sh_special_args).split(" ") commit_is_merge_commit = len(commit_parents) > 1 @@ -132,6 +143,11 @@ class GitContext(object): error_msg = "An error occurred while executing '{0}': {1}".format(e.full_cmd, error_msg) raise GitContextError(error_msg) + # "YYYY-MM-DD HH:mm:ss Z" -> ISO 8601-like format + # Use arrow for datetime parsing, because apparently python is quirky around ISO-8601 dates: + # http://stackoverflow.com/a/30696682/381010 + commit_date = arrow.get(str(commit_date_str), "YYYY-MM-DD HH:mm:ss Z").datetime + # Create Git commit object with the retrieved info changed_files = [changed_file for changed_file in changed_files_str.strip().split("\n")] commit_msg_obj = GitCommitMessage.from_full_message(commit_msg) @@ -143,3 +159,6 @@ class GitContext(object): context.commits.append(commit) return context + + def __eq__(self, other): + return self.commits == other.commits diff --git a/gitlint/tests/test_cli.py b/gitlint/tests/test_cli.py index 20f15c4..bff7bf1 100644 --- a/gitlint/tests/test_cli.py +++ b/gitlint/tests/test_cli.py @@ -37,7 +37,7 @@ class CLITests(BaseTestCase): def git_log_side_effect(*args, **_kwargs): return_values = {'--pretty=%B': "commit-title\n\ncommit-body", '--pretty=%aN': "test author", - '--pretty=%aE': "test-email@foo.com", '--pretty=%aD': "Mon Feb 29 22:19:39 2016 +0100", + '--pretty=%aE': "test-email@foo.com", '--pretty=%ai': "2016-12-03 15:28:15 01:00", '--pretty=%P': "abc"} return return_values[args[1]] diff --git a/gitlint/tests/test_git.py b/gitlint/tests/test_git.py index 91062ff..ab0a68d 100644 --- a/gitlint/tests/test_git.py +++ b/gitlint/tests/test_git.py @@ -1,3 +1,5 @@ +import datetime +import dateutil from mock import patch, call from sh import ErrorReturnCode, CommandNotFound @@ -10,7 +12,7 @@ class GitTests(BaseTestCase): def test_get_latest_commit(self, sh): def git_log_side_effect(*args, **_kwargs): return_values = {'--pretty=%B': "commit-title\n\ncommit-body", '--pretty=%aN': "test author", - '--pretty=%aE': "test-email@foo.com", '--pretty=%aD': "Mon Feb 29 22:19:39 2016 +0100", + '--pretty=%aE': "test-email@foo.com", '--pretty=%ai': "2016-12-03 15:28:15 01:00", '--pretty=%P': "abc"} return return_values[args[1]] @@ -26,7 +28,7 @@ class GitTests(BaseTestCase): expected_calls = [call('-1', '--pretty=%B', _cwd='fake/path', _tty_out=False), call('-1', '--pretty=%aN', _cwd='fake/path', _tty_out=False), call('-1', '--pretty=%aE', _cwd='fake/path', _tty_out=False), - call('-1', '--pretty=%aD', _cwd='fake/path', _tty_out=False), + call('-1', '--pretty=%ai', _cwd='fake/path', _tty_out=False), call('-1', '--pretty=%P', _cwd='fake/path', _tty_out=False)] self.assertListEqual(sh.git.log.mock_calls, expected_calls) @@ -36,6 +38,8 @@ class GitTests(BaseTestCase): self.assertEqual(last_commit.message.body, ["", "commit-body"]) self.assertEqual(last_commit.author_name, "test author") self.assertEqual(last_commit.author_email, "test-email@foo.com") + self.assertEqual(last_commit.date, datetime.datetime(2016, 12, 3, 15, 28, 15, + tzinfo=dateutil.tz.tzoffset("+0100", 3600))) self.assertListEqual(last_commit.parents, ["abc"]) self.assertFalse(last_commit.is_merge_commit) @@ -48,7 +52,7 @@ class GitTests(BaseTestCase): def test_get_latest_commit_merge_commit(self, sh): def git_log_side_effect(*args, **_kwargs): return_values = {'--pretty=%B': "Merge \"foo bar commit\"", '--pretty=%aN': "test author", - '--pretty=%aE': "test-email@foo.com", '--pretty=%aD': "Mon Feb 29 22:19:39 2016 +0100", + '--pretty=%aE': "test-email@foo.com", '--pretty=%ai': "2016-12-03 15:28:15 01:00", '--pretty=%P': "abc def"} return return_values[args[1]] @@ -64,7 +68,7 @@ class GitTests(BaseTestCase): expected_calls = [call('-1', '--pretty=%B', _cwd='fake/path', _tty_out=False), call('-1', '--pretty=%aN', _cwd='fake/path', _tty_out=False), call('-1', '--pretty=%aE', _cwd='fake/path', _tty_out=False), - call('-1', '--pretty=%aD', _cwd='fake/path', _tty_out=False), + call('-1', '--pretty=%ai', _cwd='fake/path', _tty_out=False), call('-1', '--pretty=%P', _cwd='fake/path', _tty_out=False)] self.assertListEqual(sh.git.log.mock_calls, expected_calls) @@ -74,6 +78,8 @@ class GitTests(BaseTestCase): self.assertEqual(last_commit.message.body, []) self.assertEqual(last_commit.author_name, "test author") self.assertEqual(last_commit.author_email, "test-email@foo.com") + self.assertEqual(last_commit.date, datetime.datetime(2016, 12, 3, 15, 28, 15, + tzinfo=dateutil.tz.tzoffset("+0100", 3600))) self.assertListEqual(last_commit.parents, ["abc", "def"]) self.assertTrue(last_commit.is_merge_commit) @@ -134,6 +140,7 @@ class GitTests(BaseTestCase): self.assertEqual(gitcontext.commits[-1].message.original, expected_original) self.assertEqual(gitcontext.commits[-1].author_name, None) self.assertEqual(gitcontext.commits[-1].author_email, None) + self.assertEqual(gitcontext.commits[-1].date, None) self.assertListEqual(gitcontext.commits[-1].parents, []) self.assertFalse(gitcontext.commits[-1].is_merge_commit) self.assertEqual(len(gitcontext.commits), 1) @@ -160,6 +167,7 @@ class GitTests(BaseTestCase): self.assertEqual(gitcontext.commits[-1].message.original, "") self.assertEqual(gitcontext.commits[-1].author_name, None) self.assertEqual(gitcontext.commits[-1].author_email, None) + self.assertEqual(gitcontext.commits[-1].date, None) self.assertListEqual(gitcontext.commits[-1].parents, []) self.assertFalse(gitcontext.commits[-1].is_merge_commit) self.assertEqual(len(gitcontext.commits), 1) @@ -173,6 +181,7 @@ class GitTests(BaseTestCase): self.assertEqual(gitcontext.commits[-1].message.original, "Title\n\nBody 1\n#Comment\nBody 2") self.assertEqual(gitcontext.commits[-1].author_name, None) self.assertEqual(gitcontext.commits[-1].author_email, None) + self.assertEqual(gitcontext.commits[-1].date, None) self.assertListEqual(gitcontext.commits[-1].parents, []) self.assertFalse(gitcontext.commits[-1].is_merge_commit) self.assertEqual(len(gitcontext.commits), 1) @@ -187,6 +196,7 @@ class GitTests(BaseTestCase): self.assertEqual(gitcontext.commits[-1].message.original, commit_msg) self.assertEqual(gitcontext.commits[-1].author_name, None) self.assertEqual(gitcontext.commits[-1].author_email, None) + self.assertEqual(gitcontext.commits[-1].date, None) self.assertListEqual(gitcontext.commits[-1].parents, []) self.assertTrue(gitcontext.commits[-1].is_merge_commit) self.assertEqual(len(gitcontext.commits), 1) diff --git a/qa/expected/debug_output1 b/qa/expected/debug_output1 index e9ac180..1867b4e 100644 --- a/qa/expected/debug_output1 +++ b/qa/expected/debug_output1 @@ -1,5 +1,5 @@ [GENERAL] -config path: /vagrant/qa/samples/config/gitlintconfig +config path: {config_path} extra path: None ignore merge commits: True verbosity: 2 diff --git a/requirements.txt b/requirements.txt index 830b530..df05267 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,5 +2,6 @@ setuptools wheel==0.24.0 Click==6.6 sh==1.11 +arrow==0.10.0 ordereddict==1.1 importlib==1.0.3; python_version < '2.7'
\ No newline at end of file @@ -59,6 +59,7 @@ setup( install_requires=[ 'Click==6.6', 'sh==1.11', + 'arrow==0.10.0', 'ordereddict==1.1', ], extras_require={ |