diff --git a/.github/scripts/__tests__/bot-comment-handler.test.js b/.github/scripts/__tests__/bot-comment-handler.test.js index 097a8bf7c..59b058940 100644 --- a/.github/scripts/__tests__/bot-comment-handler.test.js +++ b/.github/scripts/__tests__/bot-comment-handler.test.js @@ -30,6 +30,7 @@ test('default bot author allowlist recognizes canonical review bots', () => { 'copilot-pull-request-reviewer', 'copilot-pull-request-reviewer[bot]', 'github-actions[bot]', + 'coderabbitai', 'coderabbitai[bot]', 'chatgpt-codex-connector', 'chatgpt-codex-connector[bot]', diff --git a/.github/scripts/bot-comment-handler.js b/.github/scripts/bot-comment-handler.js index 8e81fe73f..eb619ebf9 100644 --- a/.github/scripts/bot-comment-handler.js +++ b/.github/scripts/bot-comment-handler.js @@ -9,6 +9,7 @@ const DEFAULT_BOT_AUTHORS = Object.freeze([ 'copilot-pull-request-reviewer', 'copilot-pull-request-reviewer[bot]', 'github-actions[bot]', + 'coderabbitai', 'coderabbitai[bot]', 'chatgpt-codex-connector', 'chatgpt-codex-connector[bot]', diff --git a/.github/workflows/reusable-bot-comment-handler.yml b/.github/workflows/reusable-bot-comment-handler.yml index b0dba60b0..4aff0d3bf 100644 --- a/.github/workflows/reusable-bot-comment-handler.yml +++ b/.github/workflows/reusable-bot-comment-handler.yml @@ -40,7 +40,7 @@ on: default: >- Copilot,copilot[bot],copilot-pull-request-reviewer, copilot-pull-request-reviewer[bot], - github-actions[bot],coderabbitai[bot], + github-actions[bot],coderabbitai,coderabbitai[bot], chatgpt-codex-connector,chatgpt-codex-connector[bot] skip_if_human_replied: description: 'Legacy option: skip active threads after any non-bot reply' @@ -72,7 +72,7 @@ on: default: >- Copilot,copilot[bot],copilot-pull-request-reviewer, copilot-pull-request-reviewer[bot], - github-actions[bot],coderabbitai[bot], + github-actions[bot],coderabbitai,coderabbitai[bot], chatgpt-codex-connector,chatgpt-codex-connector[bot] skip_if_human_replied: description: 'Legacy option: skip active threads after any non-bot reply' diff --git a/docs/bot-comment-handler.md b/docs/bot-comment-handler.md index 37d21e7c1..5e8b0a88f 100644 --- a/docs/bot-comment-handler.md +++ b/docs/bot-comment-handler.md @@ -47,7 +47,7 @@ By default, the workflow processes comments from: - `copilot-pull-request-reviewer` - GitHub Copilot pull-request review - `copilot-pull-request-reviewer[bot]` - GitHub Copilot reviewer bot variant - `github-actions[bot]` - GitHub Actions (lint, type check suggestions) -- `coderabbitai[bot]` - CodeRabbit AI review +- `coderabbitai` and `coderabbitai[bot]` - CodeRabbit AI review identities - `chatgpt-codex-connector` - Codex connector review - `chatgpt-codex-connector[bot]` - Codex connector bot identity diff --git a/templates/consumer-repo/.github/scripts/bot-comment-handler.js b/templates/consumer-repo/.github/scripts/bot-comment-handler.js index 8e81fe73f..eb619ebf9 100644 --- a/templates/consumer-repo/.github/scripts/bot-comment-handler.js +++ b/templates/consumer-repo/.github/scripts/bot-comment-handler.js @@ -9,6 +9,7 @@ const DEFAULT_BOT_AUTHORS = Object.freeze([ 'copilot-pull-request-reviewer', 'copilot-pull-request-reviewer[bot]', 'github-actions[bot]', + 'coderabbitai', 'coderabbitai[bot]', 'chatgpt-codex-connector', 'chatgpt-codex-connector[bot]', diff --git a/tests/workflows/test_bot_comment_handler.py b/tests/workflows/test_bot_comment_handler.py index e21359e62..6b6e55c93 100644 --- a/tests/workflows/test_bot_comment_handler.py +++ b/tests/workflows/test_bot_comment_handler.py @@ -9,6 +9,10 @@ def _load_yaml(path: Path) -> dict: return yaml.safe_load(path.read_text(encoding="utf-8")) or {} +def _bot_author_tokens(bot_authors: str) -> set[str]: + return {item.strip() for item in bot_authors.split(",") if item.strip()} + + def test_reusable_bot_comment_handler_ignores_agents_paths() -> None: workflow = _load_yaml(ROOT / ".github/workflows/reusable-bot-comment-handler.yml") triggers = workflow.get("on") or workflow.get(True) or {} @@ -18,12 +22,30 @@ def test_reusable_bot_comment_handler_ignores_agents_paths() -> None: assert ignored_paths is not None assert ".agents/" in ignored_paths.split(",") - bot_authors = inputs.get("bot_authors", {}).get("default", "") + bot_authors = _bot_author_tokens(inputs.get("bot_authors", {}).get("default", "")) assert "copilot-pull-request-reviewer" in bot_authors assert "copilot-pull-request-reviewer[bot]" in bot_authors + assert "coderabbitai" in bot_authors + assert "coderabbitai[bot]" in bot_authors assert "chatgpt-codex-connector[bot]" in bot_authors +def test_reusable_bot_comment_handler_default_bot_authors_include_coderabbit_identities() -> None: + workflow = _load_yaml(ROOT / ".github/workflows/reusable-bot-comment-handler.yml") + triggers = workflow.get("on") or workflow.get(True) or {} + + call_authors = _bot_author_tokens(triggers["workflow_call"]["inputs"]["bot_authors"]["default"]) + dispatch_authors = _bot_author_tokens( + triggers["workflow_dispatch"]["inputs"]["bot_authors"]["default"] + ) + + for identity in ("coderabbitai", "coderabbitai[bot]"): + assert identity in call_authors + assert identity in dispatch_authors + + assert call_authors == dispatch_authors + + def test_canonical_bot_comment_handler_keeps_source_templates_in_scope() -> None: workflow = _load_yaml(ROOT / ".github/workflows/agents-bot-comment-handler.yml") ignored_paths = workflow["jobs"]["handle"]["with"]["ignored_paths"].split(",") @@ -72,6 +94,9 @@ def test_reusable_bot_comment_handler_has_manual_terminal_probe() -> None: assert dispatch_inputs["pr_number"].get("required") is True assert dispatch_inputs["dry_run"].get("default") is True + assert dispatch_inputs["bot_authors"].get("default") == call_inputs["bot_authors"].get( + "default" + ) assert dispatch_inputs["ignored_paths"].get("default") == call_inputs["ignored_paths"].get( "default" ) @@ -421,6 +446,7 @@ def test_template_event_hub_uses_reusable_bot_comment_handler_defaults() -> None == "stranske/Workflows/.github/workflows/reusable-bot-comment-handler.yml@main" ) assert "ignored_paths" not in inputs + assert "bot_authors" not in inputs def test_reusable_bot_comment_handler_dismisses_ignored_reviews() -> None: