11import os
2- from typing import TypedDict
2+ from collections .abc import Iterable
3+ from typing import TYPE_CHECKING , TypedDict
34
45from commitizen import defaults
6+ from commitizen .config import BaseConfig
57from commitizen .cz .base import BaseCommitizen
68from commitizen .cz .utils import multiple_line_breaker , required_validator
79from commitizen .question import CzQuestion
810
11+ if TYPE_CHECKING :
12+ from jinja2 import Template
13+ else :
14+ try :
15+ from jinja2 import Template
16+ except ImportError :
17+ from string import Template
18+
919__all__ = ["ConventionalCommitsCz" ]
1020
1121
@@ -39,8 +49,31 @@ class ConventionalCommitsCz(BaseCommitizen):
3949 }
4050 changelog_pattern = defaults .BUMP_PATTERN
4151
42- def questions (self ) -> list [CzQuestion ]:
43- return [
52+ def __init__ (self , config : BaseConfig ) -> None :
53+ super ().__init__ (config )
54+
55+ self .custom_settings : defaults .CzSettings = self .config .settings .get (
56+ "customize" , {}
57+ )
58+
59+ if self .custom_settings :
60+ for attr_name in [
61+ "bump_pattern" ,
62+ "bump_map" ,
63+ "bump_map_major_version_zero" ,
64+ "change_type_order" ,
65+ "commit_parser" ,
66+ "change_type_map" ,
67+ ]:
68+ if value := self .custom_settings .get (attr_name ):
69+ setattr (self , attr_name , value )
70+
71+ self .changelog_pattern = (
72+ self .custom_settings .get ("changelog_pattern" ) or self .bump_pattern
73+ )
74+
75+ def questions (self ) -> Iterable [CzQuestion ]:
76+ return self .custom_settings .get ("questions" ) or [
4477 {
4578 "type" : "list" ,
4679 "name" : "prefix" ,
@@ -147,6 +180,12 @@ def questions(self) -> list[CzQuestion]:
147180 ]
148181
149182 def message (self , answers : ConventionalCommitsAnswers ) -> str : # type: ignore[override]
183+ if _message_template := self .custom_settings .get ("message_template" ):
184+ message_template = Template (_message_template )
185+ if getattr (Template , "substitute" , None ):
186+ return message_template .substitute (** answers ) # type: ignore[attr-defined,no-any-return] # pragma: no cover # TODO: check if we can fix this
187+ return message_template .render (** answers )
188+
150189 prefix = answers ["prefix" ]
151190 scope = answers ["scope" ]
152191 subject = answers ["subject" ]
@@ -166,7 +205,7 @@ def message(self, answers: ConventionalCommitsAnswers) -> str: # type: ignore[o
166205 return f"{ prefix } { scope } : { subject } { body } { footer } "
167206
168207 def example (self ) -> str :
169- return (
208+ return self . custom_settings . get ( "example" ) or (
170209 "fix: correct minor typos in code\n "
171210 "\n "
172211 "see the issue for details on the typos fixed\n "
@@ -175,7 +214,7 @@ def example(self) -> str:
175214 )
176215
177216 def schema (self ) -> str :
178- return (
217+ return self . custom_settings . get ( "schema" ) or (
179218 "<type>(<scope>): <subject>\n "
180219 "<BLANK LINE>\n "
181220 "<body>\n "
@@ -184,6 +223,8 @@ def schema(self) -> str:
184223 )
185224
186225 def schema_pattern (self ) -> str :
226+ if schema_pattern := self .custom_settings .get ("schema_pattern" ):
227+ return schema_pattern
187228 change_types = (
188229 "build" ,
189230 "bump" ,
@@ -209,6 +250,11 @@ def schema_pattern(self) -> str:
209250 )
210251
211252 def info (self ) -> str :
253+ if info_path := self .custom_settings .get ("info_path" ):
254+ with open (info_path , encoding = self .config .settings ["encoding" ]) as f :
255+ return f .read ()
256+ if info := self .custom_settings .get ("info" ):
257+ return info
212258 dir_path = os .path .dirname (os .path .realpath (__file__ ))
213259 filepath = os .path .join (dir_path , "conventional_commits_info.txt" )
214260 with open (filepath , encoding = self .config .settings ["encoding" ]) as f :
0 commit comments