-
Notifications
You must be signed in to change notification settings - Fork 1
feat: implement issue #425 — dev-lead: Incomplete issue resolution - missing code reviews and CI failures #426
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
Changes from all commits
c35d5b3
69aa61d
d953148
5bfb4e0
315b0d0
a741c76
c73274f
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 |
|---|---|---|
|
|
@@ -259,6 +259,64 @@ resolve_actor_outdated_threads() { | |
| echo "::notice::resolve_actor_outdated_threads: resolved ${resolved_count} outdated thread(s) on PR #${PR_NUMBER}" | ||
| } | ||
|
|
||
| # fetch_pr_context: exports CI_STATUS_JSON and ALL_REVIEWS_JSON for holistic assessment. | ||
| # Called before engine invocation in fix-reviews, fix-bot-comment, and review-changes | ||
| # so the agent can identify Tier-1 blockers (failing CI + CHANGES_REQUESTED reviews) | ||
| # and never wrongly declare "no-changes" while the PR is still blocked. | ||
| fetch_pr_context() { | ||
| # CI check results: requires HEAD_SHA. Gracefully degrade to empty array when not set | ||
| # (e.g., review-changes in dry-run where the PR API call is skipped). | ||
| CI_STATUS_JSON="[]" | ||
| if [ -n "${HEAD_SHA:-}" ]; then | ||
| CI_STATUS_JSON=$(gh api --paginate "repos/${REPO}/commits/${HEAD_SHA}/check-runs?per_page=100" \ | ||
| 2>/dev/null \ | ||
| | jq -s '[.[].check_runs[] | {name:.name, status:.status, conclusion:.conclusion, details_url:.details_url}]' \ | ||
| 2>/dev/null || echo "[]") | ||
| # Also include legacy commit statuses (Jenkins, external CI, etc.) that use | ||
| # the separate statuses API rather than check-runs. Merge into CI_STATUS_JSON | ||
| # so the agent sees a unified picture of all required status checks. | ||
| local statuses_json | ||
| # The statuses API returns the full history per context (newest first). | ||
| # Dedupe by context so a stale failure overwritten by a later success does not | ||
| # appear as a Tier-1 blocker: group_by preserves input order within each group, | ||
| # so `first` picks the newest entry for each context. | ||
| statuses_json=$(gh api --paginate "repos/${REPO}/commits/${HEAD_SHA}/statuses?per_page=100" \ | ||
| 2>/dev/null \ | ||
| | jq -s '[ [.[].[] | select(.context != null)] | group_by(.context)[] | first | {name:.context, status:(if .state == "pending" then "in_progress" else "completed" end), conclusion:(if .state == "success" then "success" elif .state == "failure" or .state == "error" then "failure" else null end), details_url:.target_url} ]' \ | ||
| 2>/dev/null || echo "[]") | ||
| CI_STATUS_JSON=$(printf '%s\n%s' "$CI_STATUS_JSON" "$statuses_json" \ | ||
| | jq -s 'add // []' 2>/dev/null || echo "$CI_STATUS_JSON") | ||
| fi | ||
| export CI_STATUS_JSON | ||
|
|
||
| # All PR reviews with state — deduplicated per reviewer (latest review per user only). | ||
| # Uses --paginate so PRs with more than 100 reviews are fully covered. | ||
| ALL_REVIEWS_JSON=$(gh api --paginate "repos/${REPO}/pulls/${PR_NUMBER}/reviews?per_page=100" \ | ||
| 2>/dev/null \ | ||
| | jq -s '[ [.[].[] | select(.user != null)] | group_by(.user.login)[] | sort_by(.id) | last | {id:.id, user:.user.login, state:.state, submitted_at:.submitted_at} ]' \ | ||
| 2>/dev/null || echo "[]") | ||
| export ALL_REVIEWS_JSON | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| } | ||
|
|
||
| # has_tier1_blockers: returns 0 (true) if CI_STATUS_JSON or ALL_REVIEWS_JSON contain | ||
| # Tier-1 blockers: CI checks with a non-success conclusion (failure, timed_out, | ||
| # cancelled, action_required, stale, startup_failure) or CHANGES_REQUESTED reviews. | ||
| # Used to gate post_no_changes — never post a terminal no-changes marker while blockers | ||
| # exist, so the retry cron can re-attempt on the same SHA. | ||
| has_tier1_blockers() { | ||
| local failing_checks changes_requested | ||
| failing_checks=$(printf '%s' "${CI_STATUS_JSON:-[]}" | \ | ||
| jq '[.[] | select(.conclusion != null and ( | ||
| .conclusion == "failure" or .conclusion == "timed_out" or | ||
| .conclusion == "cancelled" or .conclusion == "action_required" or | ||
| .conclusion == "stale" or .conclusion == "startup_failure" | ||
| ))] | length' 2>/dev/null || echo "0") | ||
| changes_requested=$(printf '%s' "${ALL_REVIEWS_JSON:-[]}" | \ | ||
| jq '[.[] | select(.state == "CHANGES_REQUESTED")] | length' \ | ||
| 2>/dev/null || echo "0") | ||
| [ "${failing_checks:-0}" -gt 0 ] || [ "${changes_requested:-0}" -gt 0 ] | ||
| } | ||
|
|
||
| # try_enable_auto_merge: enables auto-merge (squash) on the PR if reviewDecision is | ||
| # APPROVED and auto-merge is not already set. Safe to call speculatively — checks | ||
| # eligibility first and is idempotent if auto-merge is already on. | ||
|
|
@@ -525,6 +583,7 @@ case "$INTENT_TYPE" in | |
| -F owner="${REPO%%/*}" -F repo="${REPO##*/}" -F pr="$PR_NUMBER" \ | ||
| --jq '.data.repository.pullRequest.reviewThreads.nodes | map(select(.isResolved == false))' 2>/dev/null || echo "[]") | ||
| export OPEN_THREADS_JSON | ||
| fetch_pr_context | ||
|
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.
This fetch only supplies blocker data to the prompt, but the shell still posts a terminal Useful? React with 👍 / 👎. |
||
| rc=0 | ||
| build_and_run "fix-reviews" || rc=$? | ||
| [ "$rc" -eq 2 ] && handle_rate_limit "fix-reviews" | ||
|
Comment on lines
+586
to
589
|
||
|
|
@@ -535,7 +594,11 @@ case "$INTENT_TYPE" in | |
| else | ||
| notify_coderabbit_resolve | ||
| resolve_actor_outdated_threads "fix-reviews" | ||
| post_no_changes "fix-reviews" | ||
| if has_tier1_blockers; then | ||
| echo "::warning::Tier-1 blockers still present (failing CI or CHANGES_REQUESTED reviews) — skipping no-changes marker to allow retries" | ||
| else | ||
| post_no_changes "fix-reviews" | ||
| fi | ||
| fi | ||
| try_enable_auto_merge | ||
| fi | ||
|
|
@@ -544,6 +607,7 @@ case "$INTENT_TYPE" in | |
| fix-bot-comment) | ||
| export PR_NUMBER PR_URL="https://github.com/${REPO}/pull/${PR_NUMBER}" | ||
| export REPO ACTOR="${ACTOR:-}" COMMENT_BODY="${COMMENT_BODY:-}" HEAD_SHA | ||
| fetch_pr_context | ||
| rc=0 | ||
| build_and_run "fix-bot-comment" || rc=$? | ||
| [ "$rc" -eq 2 ] && handle_rate_limit "fix-bot-comment" | ||
|
Comment on lines
+610
to
613
|
||
|
|
@@ -554,7 +618,11 @@ case "$INTENT_TYPE" in | |
| else | ||
| notify_coderabbit_resolve | ||
| resolve_actor_outdated_threads "fix-bot-comment" | ||
| post_no_changes "fix-bot-comment" | ||
| if has_tier1_blockers; then | ||
| echo "::warning::Tier-1 blockers still present (failing CI or CHANGES_REQUESTED reviews) — skipping no-changes marker to allow retries" | ||
| else | ||
| post_no_changes "fix-bot-comment" | ||
| fi | ||
| fi | ||
| try_enable_auto_merge | ||
| fi | ||
|
|
@@ -596,6 +664,7 @@ case "$INTENT_TYPE" in | |
| -F owner="${REPO%%/*}" -F repo="${REPO##*/}" -F pr="$PR_NUMBER" \ | ||
| --jq '.data.repository.pullRequest.reviewThreads.nodes | map(select(.isResolved == false))' 2>/dev/null || echo "[]") | ||
| export OPEN_THREADS_JSON BASE_REF="${BASE_REF:-main}" | ||
| fetch_pr_context | ||
| rc=0 | ||
| build_and_run "review-changes" || rc=$? | ||
| [ "$rc" -eq 2 ] && handle_rate_limit "review-changes" | ||
|
Comment on lines
+667
to
670
|
||
|
|
@@ -606,7 +675,11 @@ case "$INTENT_TYPE" in | |
| else | ||
| notify_coderabbit_resolve | ||
| resolve_actor_outdated_threads "review-changes" | ||
| post_reviews_terminal "review-changes" "no-changes" "No changes were needed for this PR." | ||
| if has_tier1_blockers; then | ||
| echo "::warning::Tier-1 blockers still present (failing CI or CHANGES_REQUESTED reviews) — skipping no-changes marker to allow retries" | ||
| else | ||
| post_reviews_terminal "review-changes" "no-changes" "No changes were needed for this PR." | ||
| fi | ||
| fi | ||
| try_enable_auto_merge | ||
| fi | ||
|
|
||
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.
When org repos invoke this via
.github/workflows/pr-review-reusable.yml, that wrapper still passes onlyCLAUDE_CODE_OAUTH_TOKEN,GOOGLE_API_KEY, andCOPILOT_GITHUB_TOKEN, while this workflow readssecrets.DON_PETRY_BOT_GH_PATforGH_TOKENandsecrets.GH_PATfor Copilot. Adding these accepted secret names here without updating the wrapper leaves both tokens empty in that reusable path, sogh auth status/API calls fail before the review agent can run.Useful? React with 👍 / 👎.