Skip to content

Commit f2c24c1

Browse files
committed
feat(template): add changelog --export-template command
1 parent 461d20a commit f2c24c1

File tree

4 files changed

+78
-6
lines changed

4 files changed

+78
-6
lines changed

commitizen/changelog.py

+15-5
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
Environment,
3838
FileSystemLoader,
3939
PackageLoader,
40+
Template,
4041
)
4142

4243
from commitizen import defaults
@@ -147,17 +148,26 @@ def order_changelog_tree(tree: Iterable, change_type_order: List[str]) -> Iterab
147148
return sorted_tree
148149

149150

151+
def get_changelog_template(
152+
loader: Optional[BaseLoader] = None, template: Optional[str] = None
153+
) -> Template:
154+
loader = ChoiceLoader(
155+
[
156+
FileSystemLoader("."),
157+
loader or PackageLoader("commitizen", "templates"),
158+
]
159+
)
160+
env = Environment(loader=loader, trim_blocks=True)
161+
return env.get_template(template or DEFAULT_TEMPLATE)
162+
163+
150164
def render_changelog(
151165
tree: Iterable,
152166
loader: Optional[BaseLoader] = None,
153167
template: Optional[str] = None,
154168
**kwargs,
155169
) -> str:
156-
loader = ChoiceLoader(
157-
[FileSystemLoader("."), loader or PackageLoader("commitizen", "templates")]
158-
)
159-
env = Environment(loader=loader, trim_blocks=True)
160-
jinja_template = env.get_template(template or DEFAULT_TEMPLATE)
170+
jinja_template = get_changelog_template(loader, template or DEFAULT_TEMPLATE)
161171
changelog: str = jinja_template.render(tree=tree, **kwargs)
162172
return changelog
163173

commitizen/cli.py

+5
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,11 @@ def __call__(self, parser, namespace, kwarg, option_string=None):
299299
"If not set, it will generate changelog from the start"
300300
),
301301
},
302+
{
303+
"name": "--export-template",
304+
"default": None,
305+
"help": "Export the changelog template into this file instead of rendering it",
306+
},
302307
*deepcopy(tpl_arguments),
303308
],
304309
},

commitizen/commands/changelog.py

+15-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import os.path
22
from difflib import SequenceMatcher
33
from operator import itemgetter
4+
from pathlib import Path
45
from typing import Callable, Dict, List, Optional
56

67
from commitizen import bump, changelog, defaults, factory, git, out
@@ -49,8 +50,13 @@ def __init__(self, config: BaseConfig, args):
4950
self.tag_format = args.get("tag_format") or self.config.settings.get(
5051
"tag_format"
5152
)
52-
self.template = args.get("template") or self.config.settings.get("template")
53+
self.template = (
54+
args.get("template")
55+
or self.config.settings.get("template")
56+
or self.cz.template
57+
)
5358
self.extras = args.get("extras") or {}
59+
self.export_template_to = args.get("export_template")
5460

5561
def _find_incremental_rev(self, latest_version: str, tags: List[GitTag]) -> str:
5662
"""Try to find the 'start_rev'.
@@ -102,6 +108,11 @@ def write_changelog(
102108
changelog_out = changelog_hook(changelog_out, partial_changelog)
103109
changelog_file.write(changelog_out)
104110

111+
def export_template(self):
112+
tpl = changelog.get_changelog_template(self.cz.template_loader, self.template)
113+
src = Path(tpl.filename)
114+
Path(self.export_template_to).write_text(src.read_text())
115+
105116
def __call__(self):
106117
commit_parser = self.cz.commit_parser
107118
changelog_pattern = self.cz.changelog_pattern
@@ -113,6 +124,9 @@ def __call__(self):
113124
Callable
114125
] = self.cz.changelog_message_builder_hook
115126

127+
if self.export_template_to:
128+
return self.export_template()
129+
116130
if not changelog_pattern or not commit_parser:
117131
raise NoPatternMapError(
118132
f"'{self.config.settings['name']}' rule does not support changelog"

tests/commands/test_changelog_command.py

+43
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44
from textwrap import dedent
55

66
import pytest
7+
from jinja2 import FileSystemLoader
78
from pytest_mock import MockFixture
89

10+
from commitizen import __file__ as commitizen_init
911
from commitizen import cli, git
1012
from commitizen.changelog import DEFAULT_TEMPLATE
1113
from commitizen.commands.changelog import Changelog
@@ -1089,3 +1091,44 @@ def test_changelog_template_extra_quotes(
10891091

10901092
changelog = project_root / "CHANGELOG.md"
10911093
assert changelog.read_text() == "no-quote - single quotes - double quotes"
1094+
1095+
1096+
def test_export_changelog_template_from_default(
1097+
mocker: MockFixture,
1098+
tmp_commitizen_project: Path,
1099+
):
1100+
project_root = Path(tmp_commitizen_project)
1101+
target = project_root / "changelog.jinja"
1102+
src = Path(commitizen_init).parent / "templates" / DEFAULT_TEMPLATE
1103+
1104+
args = ["cz", "changelog", "--export-template", str(target)]
1105+
1106+
mocker.patch.object(sys, "argv", args)
1107+
cli.main()
1108+
1109+
assert target.exists()
1110+
assert target.read_text() == src.read_text()
1111+
1112+
1113+
def test_export_changelog_template_from_plugin(
1114+
mocker: MockFixture,
1115+
tmp_commitizen_project: Path,
1116+
mock_plugin: BaseCommitizen,
1117+
tmp_path: Path,
1118+
):
1119+
project_root = Path(tmp_commitizen_project)
1120+
target = project_root / "changelog.jinja"
1121+
filename = "template.jinja"
1122+
src = tmp_path / filename
1123+
tpl = "I am a custom template"
1124+
src.write_text(tpl)
1125+
mock_plugin.template_loader = FileSystemLoader(tmp_path)
1126+
mock_plugin.template = filename
1127+
1128+
args = ["cz", "changelog", "--export-template", str(target)]
1129+
1130+
mocker.patch.object(sys, "argv", args)
1131+
cli.main()
1132+
1133+
assert target.exists()
1134+
assert target.read_text() == tpl

0 commit comments

Comments
 (0)