-
Notifications
You must be signed in to change notification settings - Fork 0
feat: implement issue #538 — Title: pr-review-mention: kill the self-trigger — bot's own mention-ack re-fires the listener #544
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| # Quality gate for the reusable pr-review-mention workflow. | ||
| # | ||
| # Triggered on any PR that touches: | ||
| # - .github/workflows/pr-review-mention*.yml | ||
| # - test/workflows/pr-review-mention/** | ||
| # - standards/workflows/pr-review-mention.yml | ||
| # | ||
| # Gate (must pass before merge): | ||
| # 1. bats — contract tests for the self-trigger guard and ack text (#538) | ||
| # | ||
| # Standard: this workflow pins the anti-self-trigger contract from issue #538 | ||
| # (the org-repo half of the #860 mention-ack runaway). | ||
|
|
||
| name: PR Review Mention Tests | ||
|
|
||
| on: | ||
| pull_request: | ||
| paths: | ||
| - '.github/workflows/pr-review-mention*.yml' | ||
| - 'test/workflows/pr-review-mention/**' | ||
| - 'standards/workflows/pr-review-mention.yml' | ||
| push: | ||
| branches: | ||
| - main | ||
| paths: | ||
| - '.github/workflows/pr-review-mention*.yml' | ||
| - 'test/workflows/pr-review-mention/**' | ||
| - 'standards/workflows/pr-review-mention.yml' | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| concurrency: | ||
| group: pr-review-mention-tests-${{ github.ref }} | ||
| cancel-in-progress: true | ||
|
|
||
| jobs: | ||
| test: | ||
| name: bats | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 10 | ||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | ||
| with: | ||
| fetch-depth: 1 | ||
|
|
||
| - name: Install bats | ||
| run: | | ||
| set -euo pipefail | ||
| sudo apt-get update -qq | ||
| sudo apt-get install -y --no-install-recommends bats | ||
|
|
||
| - name: Run bats suite | ||
| run: bats --print-output-on-failure test/workflows/pr-review-mention/ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| # Common test helpers for the pr-review-mention bats suite. | ||
|
|
||
| # Repo root, regardless of where bats is invoked from. | ||
| TT_REPO_ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../../../.." && pwd)" | ||
| export TT_REPO_ROOT | ||
|
|
||
| # The reusable workflow that owns all mention-dispatch logic (the file under test). | ||
| TT_REUSABLE="${TT_REPO_ROOT}/.github/workflows/pr-review-mention-reusable.yml" | ||
| export TT_REUSABLE | ||
|
|
||
| # Print the job-level `if:` guard block: everything from the `if: |` line up to | ||
| # (but not including) the `steps:` key of the handle-mention job. | ||
| prm_if_guard() { | ||
| awk ' | ||
| /^[[:space:]]*if:[[:space:]]*\|/ { grab=1; next } | ||
| grab && /^[[:space:]]*steps:[[:space:]]*$/ { exit } | ||
| grab { print } | ||
| ' "$TT_REUSABLE" | ||
| } | ||
|
|
||
| # Print the body of the "Post acknowledgement comment" step: everything from that | ||
| # step's `- name:` line up to (but not including) the next `- name:` line. | ||
| prm_ack_step() { | ||
| awk ' | ||
| /^[[:space:]]*-[[:space:]]*name:[[:space:]]*Post acknowledgement comment/ { grab=1; print; next } | ||
| grab && /^[[:space:]]*-[[:space:]]*name:/ { exit } | ||
| grab { print } | ||
| ' "$TT_REUSABLE" | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| #!/usr/bin/env bats | ||
| # Contract tests for .github/workflows/pr-review-mention-reusable.yml | ||
| # | ||
| # Pins issue #538: the mention listener must never trigger on its own work. | ||
| # The pr-review ack comment is authored by donpetry-bot and carries a | ||
| # `<!-- pr-review-agent ... -->` marker; either property must keep the job's | ||
| # `if:` gate (and its secrets) from ever starting. The ack must also fire no | ||
| # mention webhook (#860 runaway: 1,481 byte-identical acks at ~9s cadence). | ||
|
|
||
| load 'helpers/setup' | ||
|
|
||
| @test "reusable workflow file exists" { | ||
| [ -f "$TT_REUSABLE" ] | ||
| } | ||
|
|
||
| # ── Acceptance 1: bot-authored / marker comments never re-trigger ───────────── | ||
|
|
||
| @test "if-guard excludes comments authored by the bot itself" { | ||
| run prm_if_guard | ||
| [ "$status" -eq 0 ] | ||
| [[ "$output" == *"github.event.comment.user.login != 'donpetry-bot'"* ]] | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The assertion uses strict string matching with single quotes ( Using a regular expression match ( |
||
| } | ||
|
|
||
| @test "if-guard excludes comments carrying a pr-review-agent marker" { | ||
| run prm_if_guard | ||
| [ "$status" -eq 0 ] | ||
| [[ "$output" == *"!contains(github.event.comment.body, '<!-- pr-review-agent')"* ]] | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar to the previous test, using strict string matching with single quotes makes the test fragile to quote style changes or whitespace adjustments. Using a regular expression match ( |
||
| } | ||
|
|
||
| @test "if-guard still requires an @donpetry-bot mention to fire (trigger preserved)" { | ||
| run prm_if_guard | ||
| [ "$status" -eq 0 ] | ||
| [[ "$output" == *"contains(github.event.comment.body, '@donpetry-bot')"* ]] | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| } | ||
|
|
||
| @test "if-guard still gates on trusted author_association (trust gate preserved)" { | ||
| run prm_if_guard | ||
| [ "$status" -eq 0 ] | ||
| [[ "$output" == *'["OWNER","MEMBER","COLLABORATOR"]'* ]] | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The strict string match for the JSON array |
||
| } | ||
|
|
||
| # ── Acceptance 2: the ack comment fires no mention webhook ──────────────────── | ||
|
|
||
| @test "ack step never @-mentions any user (no mention webhook)" { | ||
| run prm_ack_step | ||
| [ "$status" -eq 0 ] | ||
| # A mention webhook fires only on a literal `@handle`. The ack must reference | ||
| # the actor as plain text, so no `@$` / `@${` interpolation may remain. | ||
| [[ "$output" != *'@$'* ]] | ||
| } | ||
|
|
||
| @test "ack step never literally @-mentions donpetry-bot" { | ||
| run prm_ack_step | ||
| [ "$status" -eq 0 ] | ||
| [[ "$output" != *"@donpetry-bot"* ]] | ||
| } | ||
|
|
||
| @test "ack step still tags its comment with the pr-review-agent marker" { | ||
| run prm_ack_step | ||
| [ "$status" -eq 0 ] | ||
| [[ "$output" == *"<!-- pr-review-agent mention-ack -->"* ]] | ||
| } | ||
|
|
||
| @test "ack step still names the actor in the acknowledgement (plain text)" { | ||
| run prm_ack_step | ||
| [ "$status" -eq 0 ] | ||
| [[ "$output" == *'${ACTOR}'* ]] | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current
awkparser is tightly coupled to the block-scalar syntaxif: |. If the workflow is ever refactored to use a single-lineif:statement or a different block-scalar indicator like>, this helper will fail to extract the guard condition.We can make the parser more robust by:
|and>block-scalar indicators.if:statements by stripping theif:prefix and printing the condition directly.