From e27c7da5d4bff7762c59cd906641283d3313eb6d Mon Sep 17 00:00:00 2001 From: codejedi365 Date: Sun, 4 Feb 2024 23:23:03 -0500 Subject: [PATCH] test(unit-changelog): refactor template testing to be fast & simple --- tests/command_line/test_changelog.py | 1 + .../changelog/test_default_changelog.py | 238 +++++++++++------- 2 files changed, 151 insertions(+), 88 deletions(-) diff --git a/tests/command_line/test_changelog.py b/tests/command_line/test_changelog.py index c7cfbf2dd..bcff9d2ae 100644 --- a/tests/command_line/test_changelog.py +++ b/tests/command_line/test_changelog.py @@ -110,6 +110,7 @@ def test_changelog_noop_is_noop( lazy_fixture("repo_w_github_flow_w_feature_release_channel_angular_commits"), lazy_fixture("repo_with_git_flow_angular_commits"), lazy_fixture("repo_with_git_flow_and_release_channels_angular_commits"), + lazy_fixture("repo_with_git_flow_and_release_channels_angular_commits_using_tag_format"), ], ) def test_changelog_content_regenerated( diff --git a/tests/unit/semantic_release/changelog/test_default_changelog.py b/tests/unit/semantic_release/changelog/test_default_changelog.py index 6867ac43d..cc138b0de 100644 --- a/tests/unit/semantic_release/changelog/test_default_changelog.py +++ b/tests/unit/semantic_release/changelog/test_default_changelog.py @@ -1,109 +1,171 @@ -# NOTE: use backport with newer API +from __future__ import annotations + from datetime import datetime +from pathlib import Path +from typing import TYPE_CHECKING + +import pytest +from git import Commit, Object, Repo +# NOTE: use backport with newer API from importlib_resources import files +import semantic_release from semantic_release.changelog.context import make_changelog_context -from semantic_release.changelog.release_history import ReleaseHistory +from semantic_release.changelog.release_history import Release, ReleaseHistory from semantic_release.changelog.template import environment -from semantic_release.hvcs import Github -from semantic_release.version.translator import VersionTranslator - -from tests.const import COMMIT_MESSAGE - -default_changelog_template = ( - files("tests") - .joinpath("unit/semantic_release/changelog/TEST_CHANGELOG.md.j2") - .read_text(encoding="utf-8") -) - -today_as_str = datetime.now().strftime("%Y-%m-%d") - - -def _cm_rstripped(version: str) -> str: - return COMMIT_MESSAGE.format(version=version).rstrip() - - -EXPECTED_CONTENT = f"""\ -# CHANGELOG -## v1.1.0-alpha.3 ({today_as_str}) -### Fix -* fix(feature): add some missing text -### Unknown -* {_cm_rstripped("1.1.0-alpha.3")} -## v1.1.0-alpha.2 ({today_as_str}) -### Feature -* feat(feature): add some more text -### Unknown -* {_cm_rstripped("1.1.0-alpha.2")} -## v1.1.0-alpha.1 ({today_as_str}) -### Feature -* feat(feature): add some more text -### Unknown -* {_cm_rstripped("1.1.0-alpha.1")} -## v1.1.0-rc.2 ({today_as_str}) -### Fix -* fix(dev): add some more text -### Unknown -* {_cm_rstripped("1.1.0-rc.2")} -## v1.1.0-rc.1 ({today_as_str}) -### Feature -* feat(dev): add some more text -### Unknown -* {_cm_rstripped("1.1.0-rc.1")} -## v1.0.0 ({today_as_str}) -### Feature -* feat: add some more text -### Unknown -* {_cm_rstripped("1.0.0")} -## v1.0.0-rc.1 ({today_as_str}) -### Breaking -* feat!: add some more text -### Unknown -* {_cm_rstripped("1.0.0-rc.1")} -## v0.1.1-rc.1 ({today_as_str}) -### Fix -* fix: add some more text -### Unknown -* {_cm_rstripped("0.1.1-rc.1")} -## v0.1.0 ({today_as_str}) -### Unknown -* {_cm_rstripped("0.1.0")} -* Initial commit -""" +from semantic_release.commit_parser import ParsedCommit +from semantic_release.enums import LevelBump +from semantic_release.hvcs import Gitea, Github, Gitlab +from semantic_release.version.translator import Version + +from tests.const import TODAY_DATE_STR + +if TYPE_CHECKING: + from git import Actor + + from semantic_release.hvcs import HvcsBase + + +@pytest.fixture +def default_changelog_template() -> str: + """Retrieve the semantic-release default changelog template.""" + version_notes_template = files(semantic_release.__name__).joinpath( + Path("data", "templates", "CHANGELOG.md.j2") + ) + return version_notes_template.read_text(encoding="utf-8") + + +@pytest.fixture +def artificial_release_history(commit_author: Actor): + version = Version.parse("1.0.0") + + commit_subject = "fix(cli): fix a problem" + + fix_commit = Commit( + Repo("."), + Object.NULL_HEX_SHA[:20].encode("utf-8"), + message=commit_subject, + ) + + fix_commit_parsed = ParsedCommit( + bump=LevelBump.PATCH, + type="fix", + scope="cli", + descriptions=[commit_subject], + breaking_descriptions=[], + commit=fix_commit, + ) + commit_subject = "feat(cli): add a new feature" + feat_commit = Commit( + Repo("."), + Object.NULL_HEX_SHA[:20].encode("utf-8"), + message=commit_subject, + ) + + feat_commit_parsed = ParsedCommit( + bump=LevelBump.MINOR, + type="feat", + scope="cli", + descriptions=[commit_subject], + breaking_descriptions=[], + commit=feat_commit, + ) + + return ReleaseHistory( + unreleased={ + "feature": [feat_commit_parsed], + }, + released={ + version: Release( + tagger=commit_author, + committer=commit_author, + tagged_date=datetime.utcnow(), + elements={ + "feature": [feat_commit_parsed], + "fix": [fix_commit_parsed], + } + ) + } + ) + + +@pytest.mark.parametrize("hvcs_client", [Github, Gitlab, Gitea]) def test_default_changelog_template( - repo_with_git_flow_and_release_channels_angular_commits, default_angular_parser + default_changelog_template: str, + hvcs_client: type[HvcsBase], + example_git_https_url: str, + artificial_release_history: ReleaseHistory, ): - repo = repo_with_git_flow_and_release_channels_angular_commits + version_str = "1.0.0" + version = Version.parse(version_str) + rh = artificial_release_history + rh.unreleased = {} # Wipe out unreleased + + feat_commit_obj = artificial_release_history.released[version]["elements"]["feature"][0] + feat_commit_url = hvcs_client(example_git_https_url).commit_hash_url(feat_commit_obj.commit.hexsha) + feat_description = str.join('\n', feat_commit_obj.descriptions) + + fix_commit_obj = artificial_release_history.released[version]["elements"]["fix"][0] + fix_commit_url = hvcs_client(example_git_https_url).commit_hash_url(fix_commit_obj.commit.hexsha) + fix_description = str.join('\n', fix_commit_obj.descriptions) + + expected_changelog = str.join("\n", [ + "# CHANGELOG", + f"## v{version_str} ({TODAY_DATE_STR})", + "### Feature", + f"* {feat_description} ([`{feat_commit_obj.commit.hexsha[:7]}`]({feat_commit_url}))", + "### Fix", + f"* {fix_description} ([`{fix_commit_obj.commit.hexsha[:7]}`]({fix_commit_url}))", + "", + ]) env = environment(trim_blocks=True, lstrip_blocks=True, keep_trailing_newline=True) - rh = ReleaseHistory.from_git_history( - repo=repo, translator=VersionTranslator(), commit_parser=default_angular_parser - ) context = make_changelog_context( - hvcs_client=Github(remote_url=repo.remote().url), release_history=rh + hvcs_client=hvcs_client(remote_url=example_git_https_url), + release_history=rh, ) context.bind_to_environment(env) - actual_content = env.from_string(default_changelog_template).render() - assert actual_content == EXPECTED_CONTENT + actual_changelog = env.from_string(default_changelog_template).render() + assert expected_changelog == actual_changelog -def test_default_changelog_template_using_tag_format( - repo_with_git_flow_and_release_channels_angular_commits_using_tag_format, - default_angular_parser, +@pytest.mark.parametrize("hvcs_client", [Github, Gitlab, Gitea]) +def test_default_changelog_template_w_unreleased_changes( + default_changelog_template: str, + hvcs_client: type[HvcsBase], + example_git_https_url: str, + artificial_release_history: ReleaseHistory, ): - repo = repo_with_git_flow_and_release_channels_angular_commits_using_tag_format + version_str = "1.0.0" + version = Version.parse(version_str) + + feat_commit_obj = artificial_release_history.released[version]["elements"]["feature"][0] + feat_commit_url = hvcs_client(example_git_https_url).commit_hash_url(feat_commit_obj.commit.hexsha) + feat_description = str.join('\n', feat_commit_obj.descriptions) + + fix_commit_obj = artificial_release_history.released[version]["elements"]["fix"][0] + fix_commit_url = hvcs_client(example_git_https_url).commit_hash_url(fix_commit_obj.commit.hexsha) + fix_description = str.join('\n', fix_commit_obj.descriptions) + + expected_changelog = str.join("\n", [ + "# CHANGELOG", + "## Unreleased", + "### Feature", + f"* {feat_description} ([`{feat_commit_obj.commit.hexsha[:7]}`]({feat_commit_url}))", + f"## v{version_str} ({TODAY_DATE_STR})", + "### Feature", + f"* {feat_description} ([`{feat_commit_obj.commit.hexsha[:7]}`]({feat_commit_url}))", + "### Fix", + f"* {fix_description} ([`{fix_commit_obj.commit.hexsha[:7]}`]({fix_commit_url}))", + "", + ]) env = environment(trim_blocks=True, lstrip_blocks=True, keep_trailing_newline=True) - rh = ReleaseHistory.from_git_history( - repo=repo, - translator=VersionTranslator(tag_format="vpy{version}"), - commit_parser=default_angular_parser, - ) context = make_changelog_context( - hvcs_client=Github(remote_url=repo.remote().url), release_history=rh + hvcs_client=hvcs_client(remote_url=example_git_https_url), + release_history=artificial_release_history, ) context.bind_to_environment(env) - - actual_content = env.from_string(default_changelog_template).render() - assert actual_content == EXPECTED_CONTENT + actual_changelog = env.from_string(default_changelog_template).render() + assert expected_changelog == actual_changelog