feat: publish review check on reviewed HEAD
Adds a dedicated `review` check for the exact pull request HEAD Keeps manual review commands reported separately from the default branch job Documents the new review check behavior in contributing guidelines
This commit is contained in:
+125
-10
@@ -17,12 +17,16 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
review:
|
||||
# Manual comment workflows run on the default branch, so their native job
|
||||
# check cannot represent the reviewed PR HEAD. Publish that check explicitly.
|
||||
name: automation
|
||||
if: |
|
||||
github.event_name == 'pull_request_target' ||
|
||||
(github.event_name == 'issue_comment' && github.event.issue.pull_request && github.event.comment.user.login != 'openchamber-bot[bot]' && (github.event.comment.body == '/oc-review' || startsWith(github.event.comment.body, '/oc-review ') || github.event.comment.body == '@openchamber-bot review' || startsWith(github.event.comment.body, '@openchamber-bot review '))) ||
|
||||
(github.event_name == 'pull_request_review_comment' && github.event.comment.user.login != 'openchamber-bot[bot]' && (github.event.comment.body == '/oc-review' || startsWith(github.event.comment.body, '/oc-review ') || github.event.comment.body == '@openchamber-bot review' || startsWith(github.event.comment.body, '@openchamber-bot review ')))
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
checks: write
|
||||
contents: read
|
||||
pull-requests: write
|
||||
issues: write
|
||||
@@ -32,21 +36,17 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Generate review app token
|
||||
id: app-token
|
||||
uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v2.2.2
|
||||
with:
|
||||
app-id: ${{ secrets.OC_REVIEW_APP_ID }}
|
||||
private-key: ${{ secrets.OC_REVIEW_APP_PRIVATE_KEY }}
|
||||
|
||||
- name: Resolve pull request context
|
||||
id: pr
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
EVENT_PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }}
|
||||
run: |
|
||||
pr_json="$(gh pr view "$EVENT_PR_NUMBER" --json number,url,author,baseRefName,headRefName,headRefOid,headRepositoryOwner,isDraft)"
|
||||
echo "number=$(printf '%s' "$pr_json" | jq -r '.number')" >> "$GITHUB_OUTPUT"
|
||||
{
|
||||
echo "number=$(printf '%s' "$pr_json" | jq -r '.number')"
|
||||
echo "head_sha=$(printf '%s' "$pr_json" | jq -r '.headRefOid')"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
if [ "$(printf '%s' "$pr_json" | jq -r '.isDraft')" = "true" ]; then
|
||||
echo "draft=true" >> "$GITHUB_OUTPUT"
|
||||
@@ -59,10 +59,43 @@ jobs:
|
||||
echo "author=$(printf '%s' "$pr_json" | jq -r '.author.login')"
|
||||
echo "base_ref=$(printf '%s' "$pr_json" | jq -r '.baseRefName')"
|
||||
echo "head_ref=$(printf '%s' "$pr_json" | jq -r '.headRefName')"
|
||||
echo "head_sha=$(printf '%s' "$pr_json" | jq -r '.headRefOid')"
|
||||
echo "head_repo_owner=$(printf '%s' "$pr_json" | jq -r '.headRepositoryOwner.login')"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Start review check
|
||||
id: review-check
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
REVIEW_HEAD_SHA: ${{ steps.pr.outputs.head_sha }}
|
||||
run: |
|
||||
check_run="$(jq -n \
|
||||
--arg head_sha "$REVIEW_HEAD_SHA" \
|
||||
--arg details_url "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" \
|
||||
'{
|
||||
name: "review",
|
||||
head_sha: $head_sha,
|
||||
status: "in_progress",
|
||||
details_url: $details_url,
|
||||
output: {
|
||||
title: "OpenChamber review in progress",
|
||||
summary: "Reviewing the current pull request HEAD."
|
||||
}
|
||||
}')"
|
||||
|
||||
check_id="$(printf '%s' "$check_run" | gh api \
|
||||
--method POST \
|
||||
"repos/${GITHUB_REPOSITORY}/check-runs" \
|
||||
--input - \
|
||||
--jq '.id')"
|
||||
echo "id=$check_id" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Generate review app token
|
||||
id: app-token
|
||||
uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v2.2.2
|
||||
with:
|
||||
app-id: ${{ secrets.OC_REVIEW_APP_ID }}
|
||||
private-key: ${{ secrets.OC_REVIEW_APP_PRIVATE_KEY }}
|
||||
|
||||
- name: Clear review status for draft
|
||||
if: steps.pr.outputs.draft == 'true'
|
||||
env:
|
||||
@@ -246,6 +279,7 @@ jobs:
|
||||
Required reviewed HEAD: $REVIEW_HEAD_SHA"
|
||||
|
||||
- name: Verify and enforce review verdict
|
||||
id: verdict
|
||||
if: always() && steps.pr.outputs.draft == 'false' && steps.safety.outputs.safe == 'true'
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
@@ -366,3 +400,84 @@ jobs:
|
||||
echo "Review verdict is $verdict; only pass satisfies this check." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Publish review check
|
||||
if: always() && steps.review-check.outputs.id != ''
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
CHECK_RUN_ID: ${{ steps.review-check.outputs.id }}
|
||||
PR_NUMBER: ${{ steps.pr.outputs.number }}
|
||||
REVIEW_HEAD_SHA: ${{ steps.pr.outputs.head_sha }}
|
||||
DRAFT: ${{ steps.pr.outputs.draft }}
|
||||
VERDICT_OUTCOME: ${{ steps.verdict.outcome }}
|
||||
run: |
|
||||
current_head="$(gh pr view "$PR_NUMBER" --json headRefOid --jq '.headRefOid')"
|
||||
review_label="$(gh pr view "$PR_NUMBER" --json labels --jq '[.labels[].name | select(startswith("review:"))] | first // ""')"
|
||||
|
||||
set_review_status() {
|
||||
local target_label="$1"
|
||||
local remove_args=()
|
||||
|
||||
while IFS= read -r label; do
|
||||
case "$label" in
|
||||
review:*) remove_args+=(--remove-label "$label") ;;
|
||||
esac
|
||||
done < <(gh pr view "$PR_NUMBER" --json labels --jq '.labels[].name')
|
||||
|
||||
if [ -n "$target_label" ]; then
|
||||
gh pr edit "$PR_NUMBER" "${remove_args[@]}" --add-label "$target_label"
|
||||
elif [ "${#remove_args[@]}" -gt 0 ]; then
|
||||
gh pr edit "$PR_NUMBER" "${remove_args[@]}"
|
||||
fi
|
||||
|
||||
review_label="$target_label"
|
||||
}
|
||||
|
||||
if [ "$current_head" = "$REVIEW_HEAD_SHA" ]; then
|
||||
if [ "$DRAFT" = "true" ]; then
|
||||
set_review_status ""
|
||||
elif [ "$VERDICT_OUTCOME" != "success" ]; then
|
||||
case "$review_label" in
|
||||
review:needs-evidence|review:blocked|review:human-required|review:automation-failed) ;;
|
||||
*) set_review_status "review:automation-failed" ;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$current_head" != "$REVIEW_HEAD_SHA" ]; then
|
||||
conclusion="cancelled"
|
||||
title="Review superseded by a newer HEAD"
|
||||
summary="The pull request HEAD moved before this review completed."
|
||||
elif [ "$DRAFT" = "true" ]; then
|
||||
conclusion="neutral"
|
||||
title="Review skipped for draft pull request"
|
||||
summary="Mark the pull request ready for review to start the readiness check."
|
||||
elif [ "$VERDICT_OUTCOME" = "success" ] && [ "$review_label" = "review:ready" ]; then
|
||||
conclusion="success"
|
||||
title="OpenChamber review passed"
|
||||
summary="The reviewed HEAD is ready for maintainer review."
|
||||
else
|
||||
conclusion="failure"
|
||||
title="OpenChamber review did not pass"
|
||||
summary="Current readiness state: ${review_label:-review:automation-failed}."
|
||||
fi
|
||||
|
||||
check_run="$(jq -n \
|
||||
--arg conclusion "$conclusion" \
|
||||
--arg title "$title" \
|
||||
--arg summary "$summary" \
|
||||
--arg details_url "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" \
|
||||
'{
|
||||
status: "completed",
|
||||
conclusion: $conclusion,
|
||||
details_url: $details_url,
|
||||
output: {
|
||||
title: $title,
|
||||
summary: $summary
|
||||
}
|
||||
}')"
|
||||
|
||||
printf '%s' "$check_run" | gh api \
|
||||
--method PATCH \
|
||||
"repos/${GITHUB_REPOSITORY}/check-runs/${CHECK_RUN_ID}" \
|
||||
--input - >/dev/null
|
||||
|
||||
@@ -219,6 +219,11 @@ the previous readiness label before it starts, and only `review:ready` means
|
||||
the pull request is ready to enter the maintainer review queue. Draft pull
|
||||
requests have no readiness label.
|
||||
|
||||
The workflow publishes a separate `review` check on the exact reviewed HEAD;
|
||||
only `review:ready` passes it. The `automation` job reports workflow execution
|
||||
independently so a manual `/oc-review` result can update readiness without
|
||||
being attached to the default-branch commit that triggered the command.
|
||||
|
||||
Each completed review creates a new comment tied to its reviewed HEAD so the
|
||||
conversation remains chronological. Previous review comments are not rewritten.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user