From 1bd4cc5f3178f026c4528a4040f69723eca2b8a5 Mon Sep 17 00:00:00 2001 From: codejedi365 Date: Fri, 29 Nov 2024 21:49:39 -0700 Subject: [PATCH 1/2] test(parser-custom): add test w/ parser that toggles if a parsed commit is included in changelog --- .../test_changelog_custom_parser.py | 85 +++++++++++++++++++ tests/util.py | 27 +++++- 2 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 tests/e2e/cmd_changelog/test_changelog_custom_parser.py diff --git a/tests/e2e/cmd_changelog/test_changelog_custom_parser.py b/tests/e2e/cmd_changelog/test_changelog_custom_parser.py new file mode 100644 index 000000000..d59044b69 --- /dev/null +++ b/tests/e2e/cmd_changelog/test_changelog_custom_parser.py @@ -0,0 +1,85 @@ +from __future__ import annotations + +import os +from typing import TYPE_CHECKING + +import pytest +from pytest_lazy_fixtures.lazy_fixture import lf as lazy_fixture + +from semantic_release.changelog.context import ChangelogMode +from semantic_release.cli.commands.main import main + +from tests.const import CHANGELOG_SUBCMD, MAIN_PROG_NAME +from tests.fixtures.repos import repo_w_no_tags_angular_commits +from tests.util import ( + CustomAngularParserWithIgnorePatterns, + assert_successful_exit_code, +) + +if TYPE_CHECKING: + from pathlib import Path + + from click.testing import CliRunner + + from tests.fixtures.example_project import UpdatePyprojectTomlFn, UseCustomParserFn + from tests.fixtures.git_repo import BuiltRepoResult, GetCommitDefFn + + +@pytest.mark.parametrize( + "repo_result", [lazy_fixture(repo_w_no_tags_angular_commits.__name__)] +) +def test_changelog_custom_parser_remove_from_changelog( + repo_result: BuiltRepoResult, + cli_runner: CliRunner, + update_pyproject_toml: UpdatePyprojectTomlFn, + use_custom_parser: UseCustomParserFn, + get_commit_def_of_angular_commit: GetCommitDefFn, + changelog_md_file: Path, + default_md_changelog_insertion_flag: str, +): + """ + Given when a changelog filtering custom parser is configured + When provided a commit message that matches the ignore syntax + Then the commit message is not included in the resulting changelog + """ + ignored_commit_def = get_commit_def_of_angular_commit( + "chore: do not include me in the changelog" + ) + + # Because we are in init mode, the insertion flag is not present in the changelog + # we must take it out manually because our repo generation fixture includes it automatically + with changelog_md_file.open(newline=os.linesep) as rfd: + # use os.linesep here because the insertion flag is os-specific + # but convert the content to universal newlines for comparison + expected_changelog_content = ( + rfd.read() + .replace(f"{default_md_changelog_insertion_flag}{os.linesep}", "") + .replace("\r", "") + ) + + # Set the project configurations + update_pyproject_toml( + "tool.semantic_release.changelog.mode", ChangelogMode.INIT.value + ) + use_custom_parser( + f"{CustomAngularParserWithIgnorePatterns.__module__}:{CustomAngularParserWithIgnorePatterns.__name__}" + ) + + # Setup: add the commit to be ignored + repo_result["repo"].git.commit(m=ignored_commit_def["msg"], a=True) + + # Act + cli_cmd = [MAIN_PROG_NAME, CHANGELOG_SUBCMD] + result = cli_runner.invoke(main, cli_cmd[1:]) + + # Take measurement after action + actual_content = changelog_md_file.read_text() + + # Evaluate + assert_successful_exit_code(result, cli_cmd) + + # Verify that the changelog content does not include our commit + assert ignored_commit_def["desc"] not in actual_content + + # Verify that the changelog content has not changed + assert expected_changelog_content == actual_content diff --git a/tests/util.py b/tests/util.py index b49942171..194d1f377 100644 --- a/tests/util.py +++ b/tests/util.py @@ -17,7 +17,13 @@ from semantic_release.changelog.context import ChangelogMode, make_changelog_context from semantic_release.changelog.release_history import ReleaseHistory from semantic_release.commit_parser._base import CommitParser, ParserOptions -from semantic_release.commit_parser.token import ParsedCommit, ParseResult +from semantic_release.commit_parser.angular import AngularCommitParser +from semantic_release.commit_parser.token import ( + ParsedCommit, + ParsedMessageResult, + ParseError, + ParseResult, +) from semantic_release.enums import LevelBump from tests.const import SUCCESS_EXIT_CODE @@ -38,7 +44,6 @@ from git import Commit from semantic_release.cli.config import RuntimeContext - from semantic_release.commit_parser.token import ParseError _R = TypeVar("_R") @@ -277,3 +282,21 @@ def parse(self, commit: Commit) -> ParsedCommit | ParseError: class IncompleteCustomParser(CommitParser): pass + + +class CustomAngularParserWithIgnorePatterns(AngularCommitParser): + def parse(self, commit: Commit) -> ParsedCommit | ParseError: + if not (parse_msg_result := super().parse_message(str(commit.message))): + return ParseError(commit, "Unable to parse commit") + + return ParsedCommit.from_parsed_message_result( + commit, + ParsedMessageResult( + **{ + **parse_msg_result._asdict(), + "include_in_changelog": bool( + not str(commit.message).startswith("chore") + ), + } + ), + ) From 2121cbe1cd3fbc74e24b1545f36acf5790b15f43 Mon Sep 17 00:00:00 2001 From: codejedi365 Date: Sat, 23 Dec 2023 12:20:45 -0500 Subject: [PATCH 2/2] feat(commit-parser): enable parsers to flag commit to be ignored for changelog This adds an attribute to the ParsedCommit object that allows custom parsers to set to false if it is desired to ignore the commit completely from entry into the changelog. Resolves: #778 --- .../changelog/release_history.py | 18 ++++++++++++++++++ src/semantic_release/commit_parser/token.py | 3 +++ 2 files changed, 21 insertions(+) diff --git a/src/semantic_release/changelog/release_history.py b/src/semantic_release/changelog/release_history.py index 518229a1f..961ae074c 100644 --- a/src/semantic_release/changelog/release_history.py +++ b/src/semantic_release/changelog/release_history.py @@ -8,6 +8,7 @@ from git.objects.tag import TagObject from semantic_release.commit_parser import ParseError +from semantic_release.commit_parser.token import ParsedCommit from semantic_release.enums import LevelBump from semantic_release.version.algorithm import tags_and_versions @@ -136,6 +137,23 @@ def from_git_history( ) continue + if ( + isinstance(parse_result, ParsedCommit) + and not parse_result.include_in_changelog + ): + log.info( + str.join( + " ", + [ + "Excluding commit %s (%s) because parser determined", + "it should not included in the changelog", + ], + ), + commit.hexsha[:8], + commit_message.replace("\n", " ")[:20], + ) + continue + if the_version is None: log.info( "[Unreleased] adding '%s' commit(%s) to list", diff --git a/src/semantic_release/commit_parser/token.py b/src/semantic_release/commit_parser/token.py index 8eff9fbb0..db23a1fba 100644 --- a/src/semantic_release/commit_parser/token.py +++ b/src/semantic_release/commit_parser/token.py @@ -18,6 +18,7 @@ class ParsedMessageResult(NamedTuple): descriptions: tuple[str, ...] breaking_descriptions: tuple[str, ...] = () linked_merge_request: str = "" + include_in_changelog: bool = True class ParsedCommit(NamedTuple): @@ -28,6 +29,7 @@ class ParsedCommit(NamedTuple): breaking_descriptions: list[str] commit: Commit linked_merge_request: str = "" + include_in_changelog: bool = True @property def message(self) -> str: @@ -60,6 +62,7 @@ def from_parsed_message_result( breaking_descriptions=list(parsed_message_result.breaking_descriptions), commit=commit, linked_merge_request=parsed_message_result.linked_merge_request, + include_in_changelog=parsed_message_result.include_in_changelog, )