diff --git a/src/semantic_release/cli/changelog_writer.py b/src/semantic_release/cli/changelog_writer.py index 65e387896..69a3e9ed6 100644 --- a/src/semantic_release/cli/changelog_writer.py +++ b/src/semantic_release/cli/changelog_writer.py @@ -230,25 +230,28 @@ def generate_release_notes( style: str, mask_initial_release: bool, license_name: str = "", + template_environment: Environment | None = None, ) -> str: users_tpl_file = template_dir / DEFAULT_RELEASE_NOTES_TPL_FILE + has_custom_template = users_tpl_file.is_file() - # Determine if the user has a custom release notes template or we should use - # the default template directory with our default release notes template tpl_dir = ( template_dir - if users_tpl_file.is_file() + if has_custom_template else get_default_tpl_dir( style=style, sub_dir=ChangelogOutputFormat.MARKDOWN.value ) ) release_notes_tpl_file = ( - users_tpl_file.name - if users_tpl_file.is_file() - else DEFAULT_RELEASE_NOTES_TPL_FILE + users_tpl_file.name if has_custom_template else DEFAULT_RELEASE_NOTES_TPL_FILE ) + if has_custom_template and template_environment is not None: + env = template_environment + else: + env = environment(autoescape=False, template_dir=tpl_dir) + release_notes_env = ReleaseNotesContext( repo_name=hvcs_client.repo_name, repo_owner=hvcs_client.owner, @@ -263,11 +266,7 @@ def generate_release_notes( autofit_text_width, sort_numerically, ), - ).bind_to_environment( - # Use a new, non-configurable environment for release notes - - # not user-configurable at the moment - environment(autoescape=False, template_dir=tpl_dir) - ) + ).bind_to_environment(env) # TODO: Remove in v11 release_notes_env.globals["context"] = release_notes_env.globals["ctx"] = { diff --git a/src/semantic_release/cli/commands/changelog.py b/src/semantic_release/cli/commands/changelog.py index 523c1d2a5..af3c4ed6d 100644 --- a/src/semantic_release/cli/commands/changelog.py +++ b/src/semantic_release/cli/commands/changelog.py @@ -161,6 +161,7 @@ def changelog(cli_ctx: CliContextObj, release_tag: str | None) -> None: tag_name=release_tag, project_root=runtime.repo_dir, ), + template_environment=runtime.template_environment, ) try: diff --git a/src/semantic_release/cli/commands/version.py b/src/semantic_release/cli/commands/version.py index 7a6fa26ef..7a1326fb2 100644 --- a/src/semantic_release/cli/commands/version.py +++ b/src/semantic_release/cli/commands/version.py @@ -705,6 +705,7 @@ def version( # noqa: C901 style=runtime.changelog_style, mask_initial_release=runtime.changelog_mask_initial_release, license_name="" if not isinstance(license_cfg, str) else license_cfg, + template_environment=runtime.template_environment, ) # Preparing for committing changes; we always stage files even if we're not committing them in order to support a two-stage commit diff --git a/tests/unit/semantic_release/changelog/test_release_notes.py b/tests/unit/semantic_release/changelog/test_release_notes.py index 02f217bf1..324db98f8 100644 --- a/tests/unit/semantic_release/changelog/test_release_notes.py +++ b/tests/unit/semantic_release/changelog/test_release_notes.py @@ -1046,3 +1046,43 @@ def test_default_release_notes_template_w_multiple_notices( ) assert expected_content == actual_content + + +def test_release_notes_uses_custom_jinja_extension( + example_git_https_url: str, + single_release_history: ReleaseHistory, + example_project_dir: ExProjectDir, + change_to_ex_proj_dir: None, +): + from jinja2.ext import Extension + + from semantic_release.changelog.template import environment + + class CustomExtension(Extension): + def __init__(self, environment): + super().__init__(environment) + environment.filters["shout"] = lambda s: s.upper() + "!" + + version = list(single_release_history.released.keys())[-1] + release = single_release_history.released[version] + example_project_dir.joinpath(".release_notes.md.j2").write_text( + """{{ "hello" | shout }}""" + ) + template_env = environment( + template_dir=example_project_dir, + extensions=[CustomExtension], # type: ignore[list-item] + ) + + expected_content = f"HELLO!{os.linesep}" + + actual_content = generate_release_notes( + hvcs_client=Github(remote_url=example_git_https_url), + release=release, + template_dir=example_project_dir, + history=single_release_history, + style="conventional", + mask_initial_release=False, + template_environment=template_env, + ) + + assert expected_content == actual_content