Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Customizing through a python class

The basic steps are:

  1. Inheriting fromBaseCommitizen.
  2. Give a name to your rules.
  3. Create a Python package using properbuild backend
  4. Expose the class as acommitizen.plugin entrypoint.

Check anexample on how to configureBaseCommitizen.

You can also automate the steps above throughcookiecutter.

cookiecuttergh:commitizen-tools/commitizen_cz_template

Seecommitizen_cz_template for details.

SeeThird-party plugins for more details on how to create a third-party Commitizen plugin.

Custom commit rules

Create a Python module, for examplecz_jira.py.

Inherit fromBaseCommitizen, and you must definequestions andmessage. The others are optional.

cz_jira.py
fromcommitizen.cz.baseimportBaseCommitizenfromcommitizen.defaultsimportQuestionsclassJiraCz(BaseCommitizen):# Questions = Iterable[MutableMapping[str, Any]]# It expects a list with dictionaries.defquestions(self)->Questions:"""Questions regarding the commit message."""questions=[{"type":"input","name":"title","message":"Commit title"},{"type":"input","name":"issue","message":"Jira Issue number:"},]returnquestionsdefmessage(self,answers:dict)->str:"""Generate the message with the given answers."""returnf"answers['title'] (#answers['issue'])"defexample(self)->str:"""Provide an example to help understand the style (OPTIONAL)        Used by `cz example`.        """return"Problem with user (#321)"defschema(self)->str:"""Show the schema used (OPTIONAL)        Used by `cz schema`.        """return"<title> (<issue>)"definfo(self)->str:"""Explanation of the commit rules. (OPTIONAL)        Used by `cz info`.        """return"We use this because is useful"

The next file required issetup.py modified from flask version.

setup.py
fromsetuptoolsimportsetupsetup(name="JiraCommitizen",version="0.1.0",py_modules=["cz_jira"],license="MIT",long_description="this is a long description",install_requires=["commitizen"],entry_points={"commitizen.plugin":["cz_jira = cz_jira:JiraCz"]},)

So in the end, we would have

.├── cz_jira.py└── setup.py

And that's it. You can install it without uploading to PyPI by simplydoingpip install .

Custom bump rules

You need to define 2 parameters inside your customBaseCommitizen.

ParameterTypeDefaultDescription
bump_patternstrNoneRegex to extract information from commit (subject and body)
bump_mapdictNoneDictionary mapping the extracted information to aSemVer increment type (MAJOR,MINOR,PATCH)

Let's see an example.

cz_strange.py
fromcommitizen.cz.baseimportBaseCommitizenclassStrangeCommitizen(BaseCommitizen):bump_pattern=r"^(break|new|fix|hotfix)"bump_map={"break":"MAJOR","new":"MINOR","fix":"PATCH","hotfix":"PATCH"}

That's it, your Commitizen now supports custom rules, and you can run.

cz-ncz_strangebump

Custom commit validation and error message

The commit message validation can be customized by overriding thevalidate_commit_message andformat_error_messagemethods fromBaseCommitizen. This allows for a more detailed feedback to the user where the error originates from.

importrefromcommitizen.cz.baseimportBaseCommitizen,ValidationResultfromcommitizenimportgitclassCustomValidationCz(BaseCommitizen):defvalidate_commit_message(self,*,commit_msg:str,pattern:str|None,allow_abort:bool,allowed_prefixes:list[str],max_msg_length:int,)->ValidationResult:"""Validate commit message against the pattern."""ifnotcommit_msg:returnallow_abort,[]ifallow_abortelse[f"commit message is empty"]ifpatternisNone:returnTrue,[]ifany(map(commit_msg.startswith,allowed_prefixes)):returnTrue,[]ifmax_msg_length:msg_len=len(commit_msg.partition("\n")[0].strip())ifmsg_len>max_msg_length:returnFalse,[f"commit message is too long. Max length is{max_msg_length}"]pattern_match=re.match(pattern,commit_msg)ifpattern_match:returnTrue,[]else:# Perform additional validation of the commit message format# and add custom error messages as neededreturnFalse,["commit message does not match the pattern"]defformat_exception_message(self,ill_formatted_commits:list[tuple[git.GitCommit,list]])->str:"""Format commit errors."""displayed_msgs_content="\n".join((f'commit "{commit.rev}": "{commit.message}"'f"errors:\n""\n".join((f"-{error}"forerrorinerrors)))forcommit,errorsinill_formatted_commits)return("commit validation: failed!\n""please enter a commit message in the commitizen format.\n"f"{displayed_msgs_content}\n"f"pattern:{self.schema_pattern()}")

Custom changelog generator

The changelog generator should just work in a very basic manner without touching anything.You can customize it of course, and the following variables are the ones you need to add to your customBaseCommitizen.

ParameterTypeRequiredDescription
commit_parserstrNORegex which should provide the variables explained in the [changelog description][changelog-des]
changelog_patternstrNORegex to validate the commits, this is useful to skip commits that don't meet your ruling standards like a Merge. Usually the same as bump_pattern
change_type_mapdictNOConvert 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_hookmethod: (dict, git.GitCommit) -> dict | list | NoneNOCustomize 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. Returning a falsy value ignore the commit.
changelog_hookmethod: (full_changelog: str, partial_changelog: Optional[str]) -> strNOReceives the whole and partial (if used incremental) changelog. Useful to send slack messages or notify a compliance department. Must return the full_changelog
changelog_release_hookmethod: (release: dict, tag: git.GitTag) -> dictNOReceives each generated changelog release and its associated tag. Useful to enrich releases before they are rendered. Must return the update release
cz_strange.py
fromcommitizen.cz.baseimportBaseCommitizenimportchatimportcomplianceclassStrangeCommitizen(BaseCommitizen):changelog_pattern=r"^(break|new|fix|hotfix)"commit_parser=r"^(?P<change_type>feat|fix|refactor|perf|BREAKING CHANGE)(?:\((?P<scope>[^()\r\n]*)\)|\()?(?P<breaking>!)?:\s(?P<message>.*)?"change_type_map={"feat":"Features","fix":"Bug Fixes","refactor":"Code Refactor","perf":"Performance improvements",}defchangelog_message_builder_hook(self,parsed_message:dict,commit:git.GitCommit)->dict|list|None:rev=commit.revm=parsed_message["message"]parsed_message["message"]=f"{m}{rev} [{commit.author}]({commit.author_email})"returnparsed_messagedefchangelog_release_hook(self,release:dict,tag:git.GitTag)->dict:release["author"]=tag.authorreturnreleasedefchangelog_hook(self,full_changelog:str,partial_changelog:Optional[str])->str:"""Executed at the end of the changelog generation        full_changelog: it's the output about to being written into the file        partial_changelog: it's the new stuff, this is useful to send slack messages or                           similar        Return:            the new updated full_changelog        """ifpartial_changelog:chat.room("#committers").notify(partial_changelog)iffull_changelog:compliance.send(full_changelog)full_changelog.replace(" fix "," **fix** ")returnfull_changelog

Raise Customize Exception

If you wantcommitizen to catch your exception and print the message, you'll have to inheritCzException.

fromcommitizen.cz.exceptionimportCzExceptionclassNoSubjectProvidedException(CzException):...

Migrating from legacy plugin format

Commitizen migrated to a new plugin format relying onimportlib.metadata.EntryPoint.Migration should be straight-forward for legacy plugins:

  • Remove thediscover_this line from your plugin module
  • Expose the plugin class under as acommitizen.plugin entrypoint.

The name of the plugin is now determined by the name of the entrypoint.

Example

If you were having aCzPlugin class in acz_plugin.py module like this:

fromcommitizen.cz.baseimportBaseCommitizenclassPluginCz(BaseCommitizen):...discover_this=PluginCz

Then remove thediscover_this line:

fromcommitizen.cz.baseimportBaseCommitizenclassPluginCz(BaseCommitizen):...

and expose the class as entrypoint in yoursetuptools:

fromsetuptoolsimportsetupsetup(name="MyPlugin",version="0.1.0",py_modules=["cz_plugin"],entry_points={"commitizen.plugin":["plugin = cz_plugin:PluginCz"]},...,)

Then your plugin will be available under the nameplugin.


[8]ページ先頭

©2009-2025 Movatter.jp