From d9a37e0ad8717a6044c6f77f01f5b063d8f2a3fc Mon Sep 17 00:00:00 2001 From: Joseph <162703152+josephnef@users.noreply.github.com> Date: Mon, 3 Aug 2026 14:23:13 +0300 Subject: [PATCH 1/2] qodo-gate: accept Qodo's update-in-place re-review as current-head evidence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A /review summon after a push does not submit a new review object — Qodo edits its code-review comment and posts a marker comment naming the head sha ('updated up to the latest commit ', observed on #356). The gate now accepts that marker (bot-authored comments only, exact head oid) as the second evidence form beside a head-tied review object. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/qodo-gate.yml | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/.github/workflows/qodo-gate.yml b/.github/workflows/qodo-gate.yml index 9c35103..6d6e9dc 100644 --- a/.github/workflows/qodo-gate.yml +++ b/.github/workflows/qodo-gate.yml @@ -75,16 +75,34 @@ jobs: # reviewed. Stale reviews of a previous push do NOT count — # otherwise any follow-up commit could merge unreviewed, the same # race one push later. Summon a re-review with a `/review` comment. + # + # Two evidence forms, because Qodo re-reviews two ways: a fresh + # review object tied to the head oid (observed on PR open), or an + # in-place UPDATE of its code-review comment plus a marker comment + # "updated up to the latest commit " (observed on /review after + # a push — no new review object is submitted). The fallback accepts + # only the bot's own comments naming the exact head oid. NB comment + # edits cannot retrigger this check against the PR head (an + # issue_comment-triggered run would attach to the default branch), + # so after a summoned re-review, retrigger via a thread reply or a + # Checks-tab re-run. head_oid=$(echo "$json" | jq -r '.data.repository.pullRequest.headRefOid') current=$(echo "$json" | jq --arg b "$BOT" --arg oid "$head_oid" \ '[.data.repository.pullRequest.reviews.nodes[] | select(.author.login == $b) | select(.commit.oid == $oid)] | length') + if [ "$current" -eq 0 ]; then + current=$(gh api "repos/$REPO_OWNER/$REPO_NAME/issues/$PR/comments" \ + --paginate --jq "[.[] + | select(.user.login == \"${BOT}[bot]\") + | select(.body | test(\"up to the latest commit\")) + | select(.body | contains(\"$head_oid\"))] | length") + fi if [ "$current" -eq 0 ]; then echo "FAIL: no Qodo review of the current head ($head_oid) —" - echo "comment /review on the PR to summon one; this check re-runs" - echo "on review submission. (Outage? Apply the skip-qodo-gate" - echo "label.)" + echo "comment /review on the PR to summon one, then re-run this" + echo "check (or reply in a thread) once it answers. (Outage?" + echo "Apply the skip-qodo-gate label.)" exit 1 fi From 52ee466010c4df413260897815b1e027d6079ac0 Mon Sep 17 00:00:00 2001 From: Joseph <162703152+josephnef@users.noreply.github.com> Date: Mon, 3 Aug 2026 14:27:40 +0300 Subject: [PATCH 2/2] qodo-gate: issues:read for the comment fallback + aggregate paginated count MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh api --paginate applies --jq per page, so '| length' emitted one count per page and broke the integer comparison on multi-page comment lists — emit matching ids and count lines instead. The fallback endpoint also needs issues:read on the workflow token. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/qodo-gate.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/qodo-gate.yml b/.github/workflows/qodo-gate.yml index 6d6e9dc..67ddeda 100644 --- a/.github/workflows/qodo-gate.yml +++ b/.github/workflows/qodo-gate.yml @@ -28,6 +28,7 @@ on: permissions: contents: read pull-requests: read + issues: read # the marker-comment fallback reads issues//comments jobs: qodo-gate: @@ -92,11 +93,15 @@ jobs: | select(.author.login == $b) | select(.commit.oid == $oid)] | length') if [ "$current" -eq 0 ]; then + # --paginate applies --jq PER PAGE, so a `| length` there emits + # one count per page ("0\n1"), breaking the integer test below. + # Emit matching comment ids instead and count lines across pages. current=$(gh api "repos/$REPO_OWNER/$REPO_NAME/issues/$PR/comments" \ - --paginate --jq "[.[] + --paginate --jq ".[] | select(.user.login == \"${BOT}[bot]\") | select(.body | test(\"up to the latest commit\")) - | select(.body | contains(\"$head_oid\"))] | length") + | select(.body | contains(\"$head_oid\")) + | .id" | wc -l) fi if [ "$current" -eq 0 ]; then echo "FAIL: no Qodo review of the current head ($head_oid) —"