Skip to content

Commit 6830e0d

Browse files
committed
refactor: keep only the AI rules in the Action, no new CLI flag
message-ai-attribution now runs the usual --message check and keeps CC013 to CC017 from its result, so it works with the commit-check already pinned (2.20.2) and needs no --message-ai-attribution in the CLI. Under ai_attribution = "ignore" the scope reads as skipped.
1 parent a5e437f commit 6830e0d

2 files changed

Lines changed: 62 additions & 20 deletions

File tree

‎main.py‎

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -91,16 +91,8 @@ def _reconfigure_io() -> None:
9191
MESSAGE_AI_ATTRIBUTION_ENABLED = env_flag("MESSAGE_AI_ATTRIBUTION")
9292

9393

94-
def message_check_args() -> list[str]:
95-
"""The CLI flag each commit message is checked with.
96-
97-
``message-ai-attribution: true`` narrows the check to the AI rules (CC013
98-
to CC017), whatever ``message`` says: ``message`` defaults to true, so
99-
asking for the AI rules alone must not need it turned off as well.
100-
"""
101-
if MESSAGE_AI_ATTRIBUTION_ENABLED:
102-
return ["--message-ai-attribution"]
103-
return ["--message"]
94+
#: The AI attribution rules: what ``message-ai-attribution: true`` keeps.
95+
AI_RULE_IDS = frozenset({"CC013", "CC014", "CC015", "CC016", "CC017"})
10496

10597

10698
#: The label ``ai-label: true`` puts on a pull request that an AI tool wrote.
@@ -476,6 +468,22 @@ def skip_when_no_ai_rule_ran(scope: ScopeResult) -> ScopeResult:
476468
return scope
477469

478470

471+
def keep_ai_rules(scope: ScopeResult) -> ScopeResult:
472+
"""Narrow a commit message scope to the AI rules (CC013 to CC017).
473+
474+
``message-ai-attribution: true`` does this whatever ``message`` says:
475+
``message`` defaults to true, so asking for the AI rules alone must not
476+
need it turned off as well. The CLI runs every message rule and the
477+
format rules' verdicts are dropped here, so the CLI needs no flag of
478+
its own for it. A scope left with no rule, under the default
479+
``ai_attribution = "ignore"``, is reported as skipped.
480+
"""
481+
if not MESSAGE_AI_ATTRIBUTION_ENABLED or scope.raw_text:
482+
return scope
483+
scope.checks = [c for c in scope.checks if c.get("rule_id") in AI_RULE_IDS]
484+
return skip_when_no_ai_rule_ran(scope)
485+
486+
479487
def get_pr_title() -> str | None:
480488
"""Read PR title from GitHub event payload."""
481489
if not is_pr_event():
@@ -834,7 +842,9 @@ def run_pr_message_checks(pr_commits: list[Commit]) -> list[ScopeResult]:
834842
names = ("GIT_AUTHOR_NAME", "GIT_AUTHOR_EMAIL")
835843
env = {key: value for key, value in zip(names, author) if value} or None
836844
results.append(
837-
check_scope(label, message_check_args(), input_text=msg, sha=sha, env=env)
845+
keep_ai_rules(
846+
check_scope(label, ["--message"], input_text=msg, sha=sha, env=env)
847+
)
838848
)
839849
return results
840850

@@ -925,7 +935,7 @@ def run_commit_check() -> tuple[int, list[ScopeResult]]:
925935
# Outside a PR, check the HEAD commit message directly.
926936
if "--message" in args:
927937
results.append(
928-
check_scope("Commit message", message_check_args(), sha=head_sha())
938+
keep_ai_rules(check_scope("Commit message", ["--message"], sha=head_sha()))
929939
)
930940
args = [a for a in args if a != "--message"]
931941
rev = None

‎main_test.py‎

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -423,19 +423,53 @@ def test_a_commit_in_the_clone_carries_its_own_author(self):
423423
self.assertEqual(env["GIT_AUTHOR_EMAIL"], "bot@renovateapp.com")
424424

425425
def test_message_ai_attribution_checks_only_the_ai_rules(self):
426-
"""The commit still goes in with its author, so CC017 judges it."""
426+
"""The format rules' verdicts are dropped; the commit still goes in
427+
with its author, so CC017 judges it."""
427428
self.local_author.return_value = ("Jane Dev", "jane@example.com")
428-
mock_result = MagicMock(returncode=0, stdout=json_output(make_check("message")))
429+
output = json_output(
430+
make_check("message", status="fail"),
431+
make_check("ai_author", status="fail", rule_id="CC017"),
432+
make_check("ai_co_author", rule_id="CC015"),
433+
)
434+
mock_result = MagicMock(returncode=1, stdout=output)
429435
with (
430436
patch("main.MESSAGE_AI_ATTRIBUTION_ENABLED", True),
431437
patch("main.subprocess.run", return_value=mock_result) as mock_run,
432438
):
433-
main.run_pr_message_checks([(SHA_A, "WIP")])
439+
[scope] = main.run_pr_message_checks([(SHA_A, "WIP")])
434440
self.assertEqual(
435-
mock_run.call_args[0][0],
436-
["commit-check", "--format", "json", "--message-ai-attribution"],
441+
mock_run.call_args[0][0], ["commit-check", "--format", "json", "--message"]
437442
)
438443
self.assertEqual(mock_run.call_args[1]["env"]["GIT_AUTHOR_NAME"], "Jane Dev")
444+
self.assertEqual([c["rule_id"] for c in scope.checks], ["CC017", "CC015"])
445+
self.assertEqual(scope.status, "fail")
446+
447+
def test_message_ai_attribution_passes_a_badly_formatted_message(self):
448+
mock_result = MagicMock(
449+
returncode=1,
450+
stdout=json_output(
451+
make_check("message", status="fail"),
452+
make_check("subject_min_length", status="fail", rule_id="CC005"),
453+
make_check("ai_attribution", rule_id="CC013"),
454+
),
455+
)
456+
with (
457+
patch("main.MESSAGE_AI_ATTRIBUTION_ENABLED", True),
458+
patch("main.subprocess.run", return_value=mock_result),
459+
):
460+
[scope] = main.run_pr_message_checks([(SHA_A, "WIP")])
461+
self.assertEqual(scope.status, "pass")
462+
463+
def test_message_ai_attribution_under_ignore_is_skipped(self):
464+
"""No AI rule ran: say so rather than report a pass."""
465+
mock_result = MagicMock(returncode=0, stdout=json_output(make_check("message")))
466+
with (
467+
patch("main.MESSAGE_AI_ATTRIBUTION_ENABLED", True),
468+
patch("main.subprocess.run", return_value=mock_result),
469+
):
470+
[scope] = main.run_pr_message_checks([(SHA_A, "feat: x")])
471+
self.assertEqual(scope.status, "skip")
472+
self.assertEqual(scope.checks[0]["reason"], main.AI_POLICY_IGNORED)
439473

440474
def test_a_blank_author_field_is_left_to_git(self):
441475
self.local_author.return_value = ("Renovate Bot", "")
@@ -1009,9 +1043,7 @@ def test_message_ai_attribution_narrows_the_head_check(self):
10091043
patch("main.run_other_checks", return_value=[]),
10101044
):
10111045
main.run_commit_check()
1012-
mock_scope.assert_called_once_with(
1013-
"Commit message", ["--message-ai-attribution"], sha=SHA_A
1014-
)
1046+
mock_scope.assert_called_once_with("Commit message", ["--message"], sha=SHA_A)
10151047

10161048
def test_message_flag_removed_before_other_checks_in_pr(self):
10171049
captured_args = []

0 commit comments

Comments
 (0)