Source code for semantic_release.cli.changelog_writer

from __future__ import annotations

from logging import getLogger
from os import listdir
from pathlib import Path
from typing import TYPE_CHECKING

# NOTE: use backport with newer API than stdlib
from importlib_resources import files

from semantic_release.changelog.context import (
    ReleaseNotesContext,
    make_changelog_context,
)
from semantic_release.changelog.template import environment, recursive_render
from semantic_release.cli.util import noop_report

if TYPE_CHECKING:
    from jinja2 import Environment

    from semantic_release.changelog.release_history import Release, ReleaseHistory
    from semantic_release.cli.config import RuntimeContext
    from semantic_release.hvcs._base import HvcsBase


log = getLogger(__name__)


[docs] def get_release_notes_template(template_dir: Path) -> str: """Read the project's template for release notes, falling back to the default.""" fname = template_dir / ".release_notes.md.j2" try: return fname.read_text(encoding="utf-8") except FileNotFoundError: return ( files("semantic_release") .joinpath("data/templates/release_notes.md.j2") .read_text(encoding="utf-8") )
[docs] def render_default_changelog_file(template_env: Environment) -> str: changelog_text = ( files("semantic_release") .joinpath("data/templates/CHANGELOG.md.j2") .read_text(encoding="utf-8") ) template = template_env.from_string(changelog_text) return template.render().rstrip()
[docs] def render_release_notes( release_notes_template: str, template_env: Environment, ) -> str: template = template_env.from_string(release_notes_template) return template.render().rstrip()
[docs] def apply_user_changelog_template_directory( template_dir: Path, environment: Environment, destination_dir: Path, noop: bool = False, ) -> list[str]: if noop: noop_report( str.join( " ", [ "would have recursively rendered the template directory", f"{template_dir!r} relative to {destination_dir!r}.", "Paths which would be modified by this operation cannot be", "determined in no-op mode.", ], ) ) return [] return recursive_render( template_dir, environment=environment, _root_dir=destination_dir )
[docs] def write_default_changelog( changelog_file: Path, destination_dir: Path, environment: Environment, noop: bool = False, ) -> str: if noop: noop_report( str.join( " ", [ "would have written your changelog to", str(changelog_file.relative_to(destination_dir)), ], ) ) else: changelog_text = render_default_changelog_file(environment) changelog_file.write_text(f"{changelog_text}\n", encoding="utf-8") return str(changelog_file)
[docs] def write_changelog_files( runtime_ctx: RuntimeContext, release_history: ReleaseHistory, hvcs_client: HvcsBase, noop: bool = False, ) -> list[str]: project_dir = Path(runtime_ctx.repo_dir) template_dir = runtime_ctx.template_dir changelog_context = make_changelog_context( hvcs_client=hvcs_client, release_history=release_history, ) changelog_context.bind_to_environment(runtime_ctx.template_environment) use_user_template_dir = bool( # Directory exists and directory is not empty template_dir.exists() and template_dir.is_dir() and listdir(template_dir) ) if use_user_template_dir: return apply_user_changelog_template_directory( template_dir=template_dir, environment=runtime_ctx.template_environment, destination_dir=project_dir, noop=noop, ) log.info("No contents found in %r, using default changelog template", template_dir) return [ write_default_changelog( changelog_file=runtime_ctx.changelog_file, destination_dir=project_dir, environment=runtime_ctx.template_environment, noop=noop, ) ]
[docs] def generate_release_notes( hvcs_client: HvcsBase, release: Release, template_dir: Path, ) -> str: release_notes_env = ReleaseNotesContext( repo_name=hvcs_client.repo_name, repo_owner=hvcs_client.owner, hvcs_type=hvcs_client.__class__.__name__.lower(), version=release["version"], release=release, filters=(*hvcs_client.get_changelog_context_filters(),), ).bind_to_environment( # Use a new, non-configurable environment for release notes - # not user-configurable at the moment environment(template_dir=template_dir) ) return render_release_notes( release_notes_template=get_release_notes_template(template_dir), template_env=release_notes_env, )