Skip to content
Merged
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
44 changes: 44 additions & 0 deletions .github/workflows/llm-based-quality-gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,11 @@ jobs:
permissions:
contents: read
pull-requests: write
# `checks: write` lets the workflow_dispatch mirror step POST an
# explicit check_run to /repos/.../check-runs. Without it, the mirror
# POST returns 403 and PRs re-fired via workflow_dispatch stay
# `mergeStateStatus: BLOCKED` (the bug this whole step exists to fix).
checks: write
steps:
- name: Download all per-item results
if: ${{ needs.parse-checklist.outputs.skip_gate != 'true' && needs.parse-checklist.outputs.count != '0' }}
Expand All @@ -275,6 +280,7 @@ jobs:
run: ls -la results/ || echo "no results downloaded"

- name: Compose and post checklist comment
id: compose
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
env:
MODEL: ${{ env.GEMINI_MODEL }}
Expand Down Expand Up @@ -401,3 +407,41 @@ jobs:
if (blockingMode && warns > 0 && !overrideActive) {
core.setFailed(`LLM-Based Quality Gate found ${warns} WARN row(s). Add the \`llm-gate/override\` label to bypass (with justification in a PR comment).`);
}

# When this workflow is re-fired via `workflow_dispatch` (e.g. after a
# push that bypassed the `synchronize`-blind PR trigger), the auto-
# generated check_run for this job IS attached to the PR's head SHA,
# but GitHub's PR `statusCheckRollup` (which branch protection
# consults) does NOT include workflow_dispatch-triggered check_runs.
# The required check appears green via the Checks API but the PR stays
# `mergeStateStatus: BLOCKED`. POST an explicit check_run mirror so
# the rollup picks it up.
#
# `always()` is critical: when the gate finds WARN rows and the
# github-script step calls core.setFailed(), the default `if: success()`
# would skip this mirror. The mirror's own conclusion is derived from
# the prior step's outcome, so a failed gate produces a failed mirror.
- name: Mirror conclusion to PR head SHA (workflow_dispatch)
if: always() && github.event_name == 'workflow_dispatch' && needs.parse-checklist.outputs.head_sha != ''
env:
GH_TOKEN: ${{ github.token }}
HEAD_SHA: ${{ needs.parse-checklist.outputs.head_sha }}
COMPOSE_OUTCOME: ${{ steps.compose.outcome }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
set -euo pipefail
if [ "$COMPOSE_OUTCOME" = "success" ]; then
CONCLUSION="success"
TITLE="LLM gate passed (re-fired via workflow_dispatch)"
else
CONCLUSION="failure"
TITLE="LLM gate FAILED (re-fired via workflow_dispatch)"
fi
gh api -X POST "repos/$GITHUB_REPOSITORY/check-runs" \
-f "name=Aggregate and post review" \
-f "head_sha=$HEAD_SHA" \
-f "status=completed" \
-f "conclusion=$CONCLUSION" \
-f "details_url=$RUN_URL" \
-f "output[title]=$TITLE" \
-f "output[summary]=Mirrored from workflow_dispatch run. Full output: $RUN_URL"
Loading