From 8dbe74654f575c69cb02f481fb6569bf97dea1cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= Date: Sun, 26 Jul 2020 10:47:43 +0200 Subject: [PATCH 1/2] feat: add author and author_email to git commit Extra useful information for hooks Closes #188 --- commitizen/git.py | 17 +++-- tests/test_changelog.py | 143 ++++++++++++++++++++++++++++++++++++++-- tests/test_git.py | 20 ++++++ 3 files changed, 171 insertions(+), 9 deletions(-) diff --git a/commitizen/git.py b/commitizen/git.py index ac33181ce6..66b902950f 100644 --- a/commitizen/git.py +++ b/commitizen/git.py @@ -18,10 +18,14 @@ def __eq__(self, other) -> bool: class GitCommit(GitObject): - def __init__(self, rev, title, body=""): + def __init__( + self, rev, title, body: str = "", author: str = "", author_email: str = "" + ): self.rev = rev.strip() self.title = title.strip() self.body = body.strip() + self.author = author.strip() + self.author_email = author_email.strip() @property def message(self): @@ -59,7 +63,7 @@ def get_commits( start: Optional[str] = None, end: str = "HEAD", *, - log_format: str = "%H%n%s%n%b", + log_format: str = "%H%n%s%n%an%n%ae%n%b", delimiter: str = "----------commit-delimiter----------", args: str = "", ) -> List[GitCommit]: @@ -79,11 +83,14 @@ def get_commits( rev_and_commit = rev_and_commit.strip() if not rev_and_commit: continue - rev, title, *body_list = rev_and_commit.split("\n") - + rev, title, author, author_email, *body_list = rev_and_commit.split("\n") if rev_and_commit: git_commit = GitCommit( - rev=rev.strip(), title=title.strip(), body="\n".join(body_list).strip() + rev=rev.strip(), + title=title.strip(), + body="\n".join(body_list).strip(), + author=author, + author_email=author_email, ) git_commits.append(git_commit) return git_commits diff --git a/tests/test_changelog.py b/tests/test_changelog.py index 9675802e43..b1dc1dc0e7 100644 --- a/tests/test_changelog.py +++ b/tests/test_changelog.py @@ -7,316 +7,442 @@ "rev": "141ee441c9c9da0809c554103a558eb17c30ed17", "title": "bump: version 1.1.1 → 1.2.0", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "6c4948501031b7d6405b54b21d3d635827f9421b", "title": "docs: how to create custom bumps", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "ddd220ad515502200fe2dde443614c1075d26238", "title": "feat: custom cz plugins now support bumping version", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "ad17acff2e3a2e141cbc3c6efd7705e4e6de9bfc", "title": "docs: added bump gif", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "56c8a8da84e42b526bcbe130bd194306f7c7e813", "title": "bump: version 1.1.0 → 1.1.1", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "74c6134b1b2e6bb8b07ed53410faabe99b204f36", "title": "refactor: changed stdout statements", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "cbc7b5f22c4e74deff4bc92d14e19bd93524711e", "title": "fix(bump): commit message now fits better with semver", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "1ba46f2a63cb9d6e7472eaece21528c8cd28b118", "title": "fix: conventional commit 'breaking change' in body instead of title", "body": "closes #16", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "c35dbffd1bb98bb0b3d1593797e79d1c3366af8f", "title": "refactor(schema): command logic removed from commitizen base", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "25313397a4ac3dc5b5c986017bee2a614399509d", "title": "refactor(info): command logic removed from commitizen base", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "d2f13ac41b4e48995b3b619d931c82451886e6ff", "title": "refactor(example): command logic removed from commitizen base", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "d839e317e5b26671b010584ad8cc6bf362400fa1", "title": "refactor(commit): moved most of the commit logic to the commit command", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "12d0e65beda969f7983c444ceedc2a01584f4e08", "title": "docs(README): updated documentation url)", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "fb4c85abe51c228e50773e424cbd885a8b6c610d", "title": "docs: mkdocs documentation", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "17efb44d2cd16f6621413691a543e467c7d2dda6", "title": "Bump version 1.0.0 → 1.1.0", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "6012d9eecfce8163d75c8fff179788e9ad5347da", "title": "test: fixed issues with conf", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "0c7fb0ca0168864dfc55d83c210da57771a18319", "title": "docs(README): some new information about bump", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "cb1dd2019d522644da5bdc2594dd6dee17122d7f", "title": "feat: new working bump command", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "9c7450f85df6bf6be508e79abf00855a30c3c73c", "title": "feat: create version tag", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "9f3af3772baab167e3fd8775d37f041440184251", "title": "docs: added new changelog", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "b0d6a3defbfde14e676e7eb34946409297d0221b", "title": "feat: update given files with new version", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "d630d07d912e420f0880551f3ac94e933f9d3beb", "title": "fix: removed all from commit", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "1792b8980c58787906dbe6836f93f31971b1ec2d", "title": "feat(config): new set key, used to set version to cfg", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "52def1ea3555185ba4b936b463311949907e31ec", "title": "feat: support for pyproject.toml", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "3127e05077288a5e2b62893345590bf1096141b7", "title": "feat: first semantic version bump implementation", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "fd480ed90a80a6ffa540549408403d5b60d0e90c", "title": "fix: fix config file not working", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "e4840a059731c0bf488381ffc77e989e85dd81ad", "title": "refactor: added commands folder, better integration with decli", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "aa44a92d68014d0da98965c0c2cb8c07957d4362", "title": "Bump version: 1.0.0b2 → 1.0.0", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "58bb709765380dbd46b74ce6e8978515764eb955", "title": "docs(README): new badges", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "97afb0bb48e72b6feca793091a8a23c706693257", "title": "Merge pull request #10 from Woile/feat/decli", "body": "Feat/decli", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "9cecb9224aa7fa68d4afeac37eba2a25770ef251", "title": "style: black to files", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "f5781d1a2954d71c14ade2a6a1a95b91310b2577", "title": "ci: added travis", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "80105fb3c6d45369bc0cbf787bd329fba603864c", "title": "refactor: removed delegator, added decli and many tests", "body": "BREAKING CHANGE: API is stable", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "a96008496ffefb6b1dd9b251cb479eac6a0487f7", "title": "docs: updated test command", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "aab33d13110f26604fb786878856ec0b9e5fc32b", "title": "Bump version: 1.0.0b1 → 1.0.0b2", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "b73791563d2f218806786090fb49ef70faa51a3a", "title": "docs(README): updated to reflect current state", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "7aa06a454fb717408b3657faa590731fb4ab3719", "title": "Merge pull request #9 from Woile/dev", "body": "feat: py3 only, tests and conventional commits 1.0", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "7c7e96b723c2aaa1aec3a52561f680adf0b60e97", "title": "Bump version: 0.9.11 → 1.0.0b1", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "ed830019581c83ba633bfd734720e6758eca6061", "title": "feat: py3 only, tests and conventional commits 1.0", "body": "more tests\npyproject instead of Pipfile\nquestionary instead of whaaaaat (promptkit 2.0.0 support)", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "c52eca6f74f844ab3ffbde61d98ef96071e132b7", "title": "Bump version: 0.9.10 → 0.9.11", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "0326652b2657083929507ee66d4d1a0899e861ba", "title": "fix(config): load config reads in order without failing if there is no commitizen section", "body": "Closes #8", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "b3f89892222340150e32631ae6b7aab65230036f", "title": "Bump version: 0.9.9 → 0.9.10", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "5e837bf8ef0735193597372cd2d85e31a8f715b9", "title": "fix: parse scope (this is my punishment for not having tests)", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "684e0259cc95c7c5e94854608cd3dcebbd53219e", "title": "Bump version: 0.9.8 → 0.9.9", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "ca38eac6ff09870851b5c76a6ff0a2a8e5ecda15", "title": "fix: parse scope empty", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "64168f18d4628718c49689ee16430549e96c5d4b", "title": "Bump version: 0.9.7 → 0.9.8", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "9d4def716ef235a1fa5ae61614366423fbc8256f", "title": "fix(scope): parse correctly again", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "33b0bf1a0a4dc60aac45ed47476d2e5473add09e", "title": "Bump version: 0.9.6 → 0.9.7", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "696885e891ec35775daeb5fec3ba2ab92c2629e1", "title": "fix(scope): parse correctly", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "bef4a86761a3bda309c962bae5d22ce9b57119e4", "title": "Bump version: 0.9.5 → 0.9.6", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "72472efb80f08ee3fd844660afa012c8cb256e4b", "title": "refactor(conventionalCommit): moved filters to questions instead of message", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "b5561ce0ab3b56bb87712c8f90bcf37cf2474f1b", "title": "fix(manifest): included missing files", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "3e31714dc737029d96898f412e4ecd2be1bcd0ce", "title": "Bump version: 0.9.4 → 0.9.5", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "9df721e06595fdd216884c36a28770438b4f4a39", "title": "fix(config): home path for python versions between 3.0 and 3.5", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "0cf6ada372470c8d09e6c9e68ebf94bbd5a1656f", "title": "Bump version: 0.9.3 → 0.9.4", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "973c6b3e100f6f69a3fe48bd8ee55c135b96c318", "title": "feat(cli): added version", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "dacc86159b260ee98eb5f57941c99ba731a01399", "title": "Bump version: 0.9.2 → 0.9.3", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "4368f3c3cbfd4a1ced339212230d854bc5bab496", "title": "feat(committer): conventional commit is a bit more intelligent now", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "da94133288727d35dae9b91866a25045038f2d38", "title": "docs(README): motivation", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "1541f54503d2e1cf39bd777c0ca5ab5eb78772ba", "title": "Bump version: 0.9.1 → 0.9.2", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "ddc855a637b7879108308b8dbd85a0fd27c7e0e7", "title": "refactor: renamed conventional_changelog to conventional_commits, not backward compatible", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "46e9032e18a819e466618c7a014bcb0e9981af9e", "title": "Bump version: 0.9.0 → 0.9.1", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "0fef73cd7dc77a25b82e197e7c1d3144a58c1350", "title": "fix(setup.py): future is now required for every python version", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, ] @@ -345,7 +471,13 @@ @pytest.fixture # type: ignore def gitcommits() -> list: commits = [ - git.GitCommit(commit["rev"], commit["title"], commit["body"]) + git.GitCommit( + commit["rev"], + commit["title"], + commit["body"], + commit["author"], + commit["author_email"], + ) for commit in COMMITS_DATA ] return commits @@ -716,8 +848,10 @@ def test_render_changelog_with_change_type(gitcommits, tags): def test_render_changelog_with_changelog_message_builder_hook(gitcommits, tags): - def changelog_message_builder_hook(message: dict, _) -> dict: - message["message"] = f"{message['message']} [link](github.com/232323232)" + def changelog_message_builder_hook(message: dict, commit: git.GitCommit) -> dict: + message[ + "message" + ] = f"{message['message']} [link](github.com/232323232) {commit.author} {commit.author_email}" return message parser = defaults.commit_parser @@ -730,4 +864,5 @@ def changelog_message_builder_hook(message: dict, _) -> dict: changelog_message_builder_hook=changelog_message_builder_hook, ) result = changelog.render_changelog(tree) - assert "[link](github.com/232323232)" in result + + assert "[link](github.com/232323232) Commitizen author@cz.dev" in result diff --git a/tests/test_git.py b/tests/test_git.py index 3a6638b329..0fa22df12e 100644 --- a/tests/test_git.py +++ b/tests/test_git.py @@ -1,4 +1,7 @@ +import pytest + from commitizen import git +from tests.utils import create_file_and_commit class FakeCommand: @@ -54,3 +57,20 @@ def test_git_message_with_empty_body(): commit = git.GitCommit("test_rev", "Some Title", body="") assert commit.message == commit_title + + +@pytest.mark.usefixtures("tmp_commitizen_project") +def test_get_commits(): + create_file_and_commit("feat(users): add username") + create_file_and_commit("fix: username exception") + commits = git.get_commits() + assert len(commits) == 2 + + +@pytest.mark.usefixtures("tmp_commitizen_project") +def test_get_commits_author_and_email(): + create_file_and_commit("fix: username exception") + commit = git.get_commits()[0] + + assert commit.author is not "" + assert "@" in commit.author_email From 8560400e0f15d29781a09ba0699a668ccb583fa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= Date: Sun, 26 Jul 2020 10:52:00 +0200 Subject: [PATCH 2/2] docs: add author and author_email example --- docs/customization.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/customization.md b/docs/customization.md index 20f9ffb9fe..0602b9cecb 100644 --- a/docs/customization.md +++ b/docs/customization.md @@ -60,14 +60,14 @@ message = "Do you want to add body message in commit?" #### Detailed `questions` content -| Parameter | Type | Default | Description | -| --------- | ------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `type` | `str` | `None` | The type of questions. Valid type: `list`, `input` and etc. [See More](https://github.com/tmbo/questionary#different-question-types) | -| `name` | `str` | `None` | The key for the value answered by user. It's used in `message_template` | -| `message` | `str` | `None` | Detail description for the question. | +| Parameter | Type | Default | Description | +| --------- | ------ | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | +| `type` | `str` | `None` | The type of questions. Valid type: `list`, `input` and etc. [See More](https://github.com/tmbo/questionary#different-question-types) | +| `name` | `str` | `None` | The key for the value answered by user. It's used in `message_template` | +| `message` | `str` | `None` | Detail description for the question. | | `choices` | `list` | `None` | (OPTIONAL) The choices when `type = list`. Either use a list of values or a list of dicitionaries with `name` and `value` keys. See examples above. | -| `default` | `Any` | `None` | (OPTIONAL) The default value for this question. | -| `filter` | `str` | `None` | (Optional) Validator for user's answer. **(Work in Progress)** | +| `default` | `Any` | `None` | (OPTIONAL) The default value for this question. | +| `filter` | `str` | `None` | (Optional) Validator for user's answer. **(Work in Progress)** | ## 2. Customize through customizing a class @@ -206,13 +206,13 @@ cz -n cz_strange bump The changelog generator should just work in a very basic manner without touching anything. You can customize it of course, and this are the variables you need to add to your custom `BaseCommitizen`. -| Parameter | Type | Required | Description | -| ------------------- | ------------------------------------------------------------------------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `commit_parser` | `str` | NO | Regex which should provide the variables explained in the [changelog description][changelog-des] | -| `changelog_pattern` | `str` | NO | Regex to validate the commits, this is useful to skip commits that don't meet your rulling standards like a Merge. Usually the same as bump_pattern | -| `change_type_map` | `dict` | NO | Convert the title of the change type that will appear in the changelog, if a value is not found, the original will be provided | -| `changelog_message_builder_hook` | `method: (dict, git.GitCommit) -> dict` | NO | Customize with extra information your message output, like adding links, this function is executed per parsed commit. | -| `changelog_hook` | `method: (full_changelog: str, partial_changelog: Optional[str]) -> str` | NO | Receives the whole and partial (if used incremental) changelog. Useful to send slack messages or notify a compliance department. Must return the full_changelog | +| Parameter | Type | Required | Description | +| -------------------------------- | ------------------------------------------------------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `commit_parser` | `str` | NO | Regex which should provide the variables explained in the [changelog description][changelog-des] | +| `changelog_pattern` | `str` | NO | Regex to validate the commits, this is useful to skip commits that don't meet your rulling standards like a Merge. Usually the same as bump_pattern | +| `change_type_map` | `dict` | NO | Convert the title of the change type that will appear in the changelog, if a value is not found, the original will be provided | +| `changelog_message_builder_hook` | `method: (dict, git.GitCommit) -> dict` | NO | Customize with extra information your message output, like adding links, this function is executed per parsed commit. Each GitCommit contains the following attrs: `rev`, `title`, `body`, `author`, `author_email` | +| `changelog_hook` | `method: (full_changelog: str, partial_changelog: Optional[str]) -> str` | NO | Receives the whole and partial (if used incremental) changelog. Useful to send slack messages or notify a compliance department. Must return the full_changelog | ```python from commitizen.cz.base import BaseCommitizen @@ -232,7 +232,7 @@ class StrangeCommitizen(BaseCommitizen): def changelog_message_builder_hook(self, parsed_message: dict, commit: git.GitCommit) -> dict: rev = commit.rev m = parsed_message["message"] - parsed_message["message"] = f"{m} {rev}" + parsed_message["message"] = f"{m} {rev} [{commit.author}]({commit.author_email})" return parsed_message def changelog_hook(self, full_changelog: str, partial_changelog: Optional[str]) -> str: