Skip to content

feat(parser-angular): add scope filtering option to Angular commit pa… #1216

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions src/semantic_release/commit_parser/angular.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ class AngularParserOptions(ParserOptions):
one of these prefixes, it will not be considered a valid commit message.
"""

allowed_scopes: Tuple[str, ...] = ()
"""If set, only commits with a matching scope will be considered."""

default_bump_level: LevelBump = LevelBump.NO_RELEASE
"""The minimum bump level to apply to valid commit message."""

Expand Down Expand Up @@ -335,10 +338,28 @@ def is_merge_commit(commit: Commit) -> bool:
return len(commit.parents) > 1

def parse_commit(self, commit: Commit) -> ParseResult:
if not (parsed_msg_result := self.parse_message(force_str(commit.message))):
parsed_msg_result = self.parse_message(force_str(commit.message))

if not parsed_msg_result:
return _logged_parse_error(
commit, f"Unable to parse commit message: {commit.message!r}"
)

# Check if we have defined allowed scopes
has_allowed_scopes = bool(self.options.allowed_scopes)
has_scope = bool(parsed_msg_result.scope)
is_scope_allowed = (
has_scope and parsed_msg_result.scope in self.options.allowed_scopes
)

# If no allowed_scopes are defined, skip filtering
if not has_allowed_scopes:
return ParsedCommit.from_parsed_message_result(commit, parsed_msg_result)

# If allowed_scopes are defined, enforce filtering
if not has_scope or not is_scope_allowed:
return _logged_parse_error(
commit,
f"Unable to parse commit message: {commit.message!r}",
commit, f"Skipping commit due to scope filtering: {commit.message!r}"
)

return ParsedCommit.from_parsed_message_result(commit, parsed_msg_result)
Expand Down
31 changes: 31 additions & 0 deletions tests/unit/semantic_release/commit_parser/test_conventional.py
Original file line number Diff line number Diff line change
Expand Up @@ -1246,3 +1246,34 @@ def test_parser_ignore_merge_commit(

assert isinstance(parsed_result, ParseError)
assert "Ignoring merge commit" in parsed_result.error

@pytest.mark.parametrize(
"commit_message, allowed_scopes, expected_result",
[
("feat(pkg1): add feature A", ("pkg1",), True),
("fix(pkg2): fix something", ("pkg1",), False),
("chore(pkg3): maintenance task", ("pkg3",), True),
("docs(pkg1): update documentation", ("pkg1", "pkg3"), True),
("feat(pkg4): add feature B", (), True), # Empty tuple means no scope restriction
("fix: global fix", ("pkg1",), False), # No scope in message, should not pass
],
)
def test_parser_scope_filtering(make_commit_obj: MakeCommitObjFn, commit_message, allowed_scopes, expected_result):
"""Tests whether ConventionalCommitParser correctly filters commits based on the allowed_scopes option."""
parser = ConventionalCommitParser(
options=ConventionalCommitParserOptions(allowed_scopes=allowed_scopes)
)

parsed_results = parser.parse(make_commit_obj(commit_message))

# Ensure that `parsed_results` is a list and extract the first element (if any)
assert isinstance(parsed_results, list), f"Expected list but got {type(parsed_results)}"
assert len(parsed_results) > 0, "Expected at least one parsed result"

result = parsed_results[0] # Extract the first parsed commit or error

if expected_result:
assert isinstance(result, ParsedCommit), f"Expected ParsedCommit but got {result}"
else:
assert isinstance(result, ParseError), f"Expected ParseError but got {result}"
assert "Skipping commit due to scope filtering" in result.error