feat(dashboard): add check run external links and rerun buttons#164
Conversation
Surface the GitHub check run URL in the type so the UI can link directly to the run on github.com.
…n helpers Extract deduplicateCheckRuns and isFailedCheckRun as pure shared helpers used by both computePullStatus and the new rerunChecks mutation. The rerunChecks server function calls GitHub's checks.rerequestRun API to re-trigger failed or all check runs for a given pull request. - RerunChecksInput extends PullFromRepoInput (project convention) - Refactors computePullStatus to use deduplicateCheckRuns - isFailedCheckRun mirrors the UI's getCheckRunStatus logic - Passes html_url through computePullStatus mapping
…ction - Add external link icon (↗) to each check run row, linking to the run on github.com. Uses group-hover/run opacity pattern matching existing project conventions. - Add 'Re-run failed checks' button when checks have failures - Add 'Re-run all checks' button when any checks exist - Both buttons follow the ghost/xs/Spinner pattern used by UpdateBranchButton and MergeFooter - Pass owner/repo/pullNumber through ChecksSection props
…CheckRun 15 tests covering deduplication by name/id, all failure conclusion variants (failure, timed_out, cancelled, action_required), and all non-failure conclusions (success, neutral, skipped, null).
|
Caution Review failedPull request was closed or merged during review Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds check-run/approval management: server mutations (rerunChecks, approveWorkflowRuns), check-run utilities (dedupe, failure classifier), PullStatus extensions (expected, pendingWorkflowApprovals, htmlUrl, required), UI wiring for approve/rerun, StatePill UI component, tests, and revalidation/cache-policy updates. Changes
Sequence DiagramsequenceDiagram
participant User
participant UI as ChecksSection (Client)
participant Server as API Server
participant GH as GitHub API
User->>UI: Click "Re-run checks" / "Approve workflows"
UI->>UI: set isRerunning / isApproving = true
UI->>Server: POST rerunChecks / approveWorkflowRuns (owner,repo,pullNumber,workflowRunIds,failedOnly)
Server->>GH: Get PR head SHA, list check runs, combined statuses, workflow runs
GH-->>Server: returns PR/checkRuns/statuses/workflowRuns
Server->>Server: deduplicateCheckRuns, filter failedOnly (if set)
alt approveWorkflowRuns
Server->>GH: Approve workflow run(s)
GH-->>Server: approval responses (success/fail)
else rerunChecks
loop per deduped run
alt Actions workflow run
Server->>GH: Actions re-run endpoint
else Checks API
Server->>GH: checks.rerequestRun
end
GH-->>Server: ok / 403(resource-shape) -> mark skipped
end
end
Server->>Server: Bust pull-detail caches (pullEntity + repoStatuses keys)
Server-->>UI: result { ok, rerun/skipped/approved/failed, partial }
UI->>UI: invalidate queries, set isRerunning/isApproving = false
UI-->>User: show toast (success/partial/failure)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
apps/dashboard/src/lib/github-check-runs.test.ts (1)
126-134: Rename this test description to match its payload.Line 126 says “still running”, but Line 131 sets
status: "completed". Renaming avoids semantic drift in test intent.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/dashboard/src/lib/github-check-runs.test.ts` around lines 126 - 134, The test description for the unit testing is mismatched: update the it(...) description for the test that calls isFailedCheckRun with status: "completed" and conclusion: null so it accurately reflects the payload (e.g., change "returns false for null conclusion (still running)" to "returns false for null conclusion (completed)"); locate the it block that invokes isFailedCheckRun({... status: "completed", conclusion: null ...}) and replace only the human-readable string to match the payload.apps/dashboard/src/lib/github.functions.ts (1)
750-759: Reuse this helper incomputePullStatustoo.Failure semantics are centralized here, but
computePullStatusstill keeps a second hard-coded classifier at Lines 3757-3769. That makeschecks.failedandfailedOnlyeasy to drift apart. Tally failures viaisFailedCheckRunso button visibility and rerun targeting stay in lockstep.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/dashboard/src/lib/github.functions.ts` around lines 750 - 759, computePullStatus currently reimplements failure semantics with a hard-coded classifier (the block around lines 3757-3769) causing drift from the central helper; replace that ad-hoc check with calls to the exported isFailedCheckRun(run: CheckRunPayload) helper when tallying failed checks (e.g., wherever checks.failed or failedOnly are computed) so both failure counts and rerun/visibility logic use the same predicate. Locate computePullStatus and swap any conditionals like run.status === "completed" && run.conclusion !== ... for isFailedCheckRun(run) and ensure any aggregates (failed count/failedOnly flag) use that function.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/dashboard/src/components/pulls/detail/pull-detail-activity.tsx`:
- Around line 888-897: The external link anchor that renders when run.htmlUrl
exists currently hides the icon with opacity-0 except on hover; update the
anchor (the <a> that wraps ExternalLinkIcon where run.htmlUrl is checked) to
make it discoverable and accessible by adding an accessible name (e.g.,
aria-label={`Open check run in new tab`} or include visually-hidden text inside
the anchor) and adjust classes so the icon is visible to keyboard users (e.g.,
add group-focus/run:opacity-100 and focus-visible:opacity-100 or ensure
non-hover devices see it by default), and ensure rel/target remain unchanged;
this ensures the ExternalLinkIcon is both keyboard-focusable and screen-reader
labeled.
In `@apps/dashboard/src/lib/github.functions.ts`:
- Around line 6088-6104: Replace the single-page call to
context.octokit.rest.checks.listForRef with a paginated fetch using
listPaginatedGitHubItems to collect all check runs for pr.data.head.sha, then
pass the full array to deduplicateCheckRuns and proceed to compute runsToRerun
(respecting data.failedOnly and isFailedCheckRun) — i.e., call
listPaginatedGitHubItems for the checks endpoint, assemble the flattened check
run list, then use deduplicateCheckRuns(checkRuns) and the existing runsToRerun
logic.
---
Nitpick comments:
In `@apps/dashboard/src/lib/github-check-runs.test.ts`:
- Around line 126-134: The test description for the unit testing is mismatched:
update the it(...) description for the test that calls isFailedCheckRun with
status: "completed" and conclusion: null so it accurately reflects the payload
(e.g., change "returns false for null conclusion (still running)" to "returns
false for null conclusion (completed)"); locate the it block that invokes
isFailedCheckRun({... status: "completed", conclusion: null ...}) and replace
only the human-readable string to match the payload.
In `@apps/dashboard/src/lib/github.functions.ts`:
- Around line 750-759: computePullStatus currently reimplements failure
semantics with a hard-coded classifier (the block around lines 3757-3769)
causing drift from the central helper; replace that ad-hoc check with calls to
the exported isFailedCheckRun(run: CheckRunPayload) helper when tallying failed
checks (e.g., wherever checks.failed or failedOnly are computed) so both failure
counts and rerun/visibility logic use the same predicate. Locate
computePullStatus and swap any conditionals like run.status === "completed" &&
run.conclusion !== ... for isFailedCheckRun(run) and ensure any aggregates
(failed count/failedOnly flag) use that function.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 3ecec03c-f83b-47c2-8ffe-9d19c288117d
📒 Files selected for processing (4)
apps/dashboard/src/components/pulls/detail/pull-detail-activity.tsxapps/dashboard/src/lib/github-check-runs.test.tsapps/dashboard/src/lib/github.functions.tsapps/dashboard/src/lib/github.types.ts
- Paginate checks.listForRef in rerunChecks using listPaginatedGitHubItems to handle >100 check runs - Add aria-label and focus-visible opacity to check run external links for accessibility (keyboard/screen-reader) - Use prefersNoHover to show links on non-hover devices - Use isFailedCheckRun in computePullStatus tallying to keep failure semantics in sync with rerun filtering - Fix test description: null conclusion with completed status is not 'still running'
There was a problem hiding this comment.
🧹 Nitpick comments (1)
apps/dashboard/src/components/pulls/detail/pull-detail-activity.tsx (1)
909-941: Remove redundant footer wrapper condition.
checks.total > 0is already guaranteed whenChecksSectionis rendered (Line 494), so this guard always evaluates true.♻️ Suggested simplification
- {(hasCheckFailures || checks.total > 0) && ( - <div className="flex items-center gap-2 border-b border-border/50 bg-surface-1/50 px-4 py-1.5 pl-11"> - {hasCheckFailures && ( - <Button - variant="ghost" - size="xs" - disabled={isRerunning} - className="h-6 text-xs text-muted-foreground" - iconLeft={ - isRerunning ? ( - <Spinner size={12} /> - ) : ( - <RefreshCwIcon size={12} strokeWidth={2} /> - ) - } - onClick={() => void handleRerun(true)} - > - Re-run failed checks - </Button> - )} - {checks.total > 0 && ( - <Button - variant="ghost" - size="xs" - disabled={isRerunning} - className="h-6 text-xs text-muted-foreground" - onClick={() => void handleRerun(false)} - > - Re-run all checks - </Button> - )} - </div> - )} + <div className="flex items-center gap-2 border-b border-border/50 bg-surface-1/50 px-4 py-1.5 pl-11"> + {hasCheckFailures && ( + <Button + variant="ghost" + size="xs" + disabled={isRerunning} + className="h-6 text-xs text-muted-foreground" + iconLeft={ + isRerunning ? ( + <Spinner size={12} /> + ) : ( + <RefreshCwIcon size={12} strokeWidth={2} /> + ) + } + onClick={() => void handleRerun(true)} + > + Re-run failed checks + </Button> + )} + <Button + variant="ghost" + size="xs" + disabled={isRerunning} + className="h-6 text-xs text-muted-foreground" + onClick={() => void handleRerun(false)} + > + Re-run all checks + </Button> + </div>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/dashboard/src/components/pulls/detail/pull-detail-activity.tsx` around lines 909 - 941, The outer conditional "(hasCheckFailures || checks.total > 0) &&" around the footer div is redundant because ChecksSection already guarantees checks.total > 0; remove that guard and render the footer div unconditionally (leave the inner hasCheckFailures conditional for the "Re-run failed checks" Button and keep the "Re-run all checks" Button using handleRerun). This affects the JSX block that contains hasCheckFailures, checks.total, the footer div, and the Buttons that call handleRerun.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@apps/dashboard/src/components/pulls/detail/pull-detail-activity.tsx`:
- Around line 909-941: The outer conditional "(hasCheckFailures || checks.total
> 0) &&" around the footer div is redundant because ChecksSection already
guarantees checks.total > 0; remove that guard and render the footer div
unconditionally (leave the inner hasCheckFailures conditional for the "Re-run
failed checks" Button and keep the "Re-run all checks" Button using
handleRerun). This affects the JSX block that contains hasCheckFailures,
checks.total, the footer div, and the Buttons that call handleRerun.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 09c4b3ad-0fc9-4ba9-ac53-2510f050daff
📒 Files selected for processing (3)
apps/dashboard/src/components/pulls/detail/pull-detail-activity.tsxapps/dashboard/src/lib/github-check-runs.test.tsapps/dashboard/src/lib/github.functions.ts
✅ Files skipped from review due to trivial changes (1)
- apps/dashboard/src/lib/github-check-runs.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/dashboard/src/lib/github.functions.ts
|
Thanks for the contribution! |
…orkflow approvals - Fetch commit statuses (CodeRabbit/CircleCI) alongside check runs - Show required and "Expected" checks sourced from branch rulesets - Surface workflow-approval banner + approveWorkflowRuns server fn - Route reruns via actions API (reRunWorkflow / reRunWorkflowFailedJobs) for GitHub Actions jobs; per-run rerequest for other apps - Group the checks list by status (Expected, Failed, Pending, Skipped, Passed) - Extract reusable StatePill component for Open/Merged/Closed/Draft badges - Webhook signals for status, workflow_run → pullEntity, repository_ruleset/branch_protection → repoProtection - Distinguish 403-resource errors from 403-auth in mutation handling
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (1)
apps/dashboard/src/components/pulls/detail/pull-detail-activity.tsx (1)
774-796: Handle the approval-only state in the checks summary.
ChecksSectionnow renders even when there are no check runs yet, but this title/description block still reads only fromchecks.*. IfpendingWorkflowApprovals.length > 0andchecks.total === 0, the section shows0 pending checks/0 successful checks, which is misleading above the approval banner.Suggested adjustment
const pendingTotal = checks.pending + checks.expected; + const hasPendingApprovals = pendingWorkflowApprovals.length > 0; const title = allChecksPassed ? "All checks have passed" : hasCheckFailures ? `${checks.failed} failing check${checks.failed > 1 ? "s" : ""}` - : `${pendingTotal} pending check${pendingTotal > 1 ? "s" : ""}`; + : pendingTotal > 0 + ? `${pendingTotal} pending check${pendingTotal > 1 ? "s" : ""}` + : hasPendingApprovals + ? `${pendingWorkflowApprovals.length} workflow${pendingWorkflowApprovals.length > 1 ? "s" : ""} awaiting approval` + : "No checks reported"; const parts: string[] = []; if (checks.skipped > 0) parts.push(`${checks.skipped} skipped`); parts.push( `${checks.passed} successful check${checks.passed !== 1 ? "s" : ""}`, ); if (checks.pending > 0) parts.push(`${checks.pending} pending`); if (checks.expected > 0) parts.push(`${checks.expected} expected`); if (checks.failed > 0) parts.push(`${checks.failed} failing`); - const description = parts.join(", "); + const description = + checks.total === 0 && hasPendingApprovals + ? "This workflow requires approval from a maintainer." + : parts.join(", ");🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/dashboard/src/components/pulls/detail/pull-detail-activity.tsx` around lines 774 - 796, When pendingWorkflowApprovals.length > 0 and checks.total === 0, treat this as an "approval-only" state and avoid showing the misleading checks summary: update the logic that computes title and description (the variables title, description and the parts array in pull-detail-activity.tsx) to branch for approval-only and produce an approval-specific title/description (e.g., "X pending approval(s)" and an appropriate description or empty string) instead of using checks.* counts; reference pendingWorkflowApprovals, checks.total, title, description and parts when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/dashboard/src/components/pulls/detail/pull-detail-activity.tsx`:
- Around line 1562-1571: The frontend getCheckRunStatus currently treats any
completed run without success/neutral/skipped/stale as "failure", which includes
conclusion === null and mismatches the backend isFailedCheckRun; update
getCheckRunStatus (the function named getCheckRunStatus) so that if run.status
!== "completed" OR run.conclusion === null it returns "pending" instead of
"failure", preserving the existing branches for "expected", "success", and
"skipped"; any other completed runs with a non-null conclusion should still
return "failure".
In `@apps/dashboard/src/lib/github.functions.ts`:
- Around line 6399-6404: The current return path treats any partial rerun as
full success; update the mutation result logic in the block that currently
returns "{ ok: true, rerun, skipped }" so that if hardFailures.length > 0 you
either return a failure via toMutationError (e.g., describing "partial rerun
failures") or return an explicit partial-failure payload the client can handle
(include fields like partial: true and hardFailures). Ensure you still call
bustPullDetailCaches(context.session.user.id, data) when appropriate but change
the final return to reflect partial failures by inspecting rerun, hardFailures
and skipped so the UI can surface dropped checks.
- Around line 3791-3798: computePullStatus is currently calling
context.octokit.rest.checks.listForRef(...) which only returns the first page
(100) of check runs; replace that call with listPaginatedGitHubItems to fetch
all pages (pass the same params: owner: data.owner, repo: data.repo, ref:
pull.head.sha, per_page: 100) and then pass the full array into
deduplicateCheckRuns, preserving existing error handling (e.g., return null or
empty array on error) so downstream code expecting a list still works.
In `@README.md`:
- Around line 247-250: Update the "Subscribe to events" setup checklist in
README.md to include the additional webhook events listed in the table: add
entries for "Status", "Repository ruleset", "Branch protection rule", and
"Workflow run" so the setup steps match the table rows; ensure the checklist
items explicitly instruct subscribing to the corresponding webhook event types
and any required checkboxes/options referenced by the table labels, and verify
the language matches existing checklist styling under the "Subscribe to events"
section.
---
Nitpick comments:
In `@apps/dashboard/src/components/pulls/detail/pull-detail-activity.tsx`:
- Around line 774-796: When pendingWorkflowApprovals.length > 0 and checks.total
=== 0, treat this as an "approval-only" state and avoid showing the misleading
checks summary: update the logic that computes title and description (the
variables title, description and the parts array in pull-detail-activity.tsx) to
branch for approval-only and produce an approval-specific title/description
(e.g., "X pending approval(s)" and an appropriate description or empty string)
instead of using checks.* counts; reference pendingWorkflowApprovals,
checks.total, title, description and parts when making the change.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: ed0e7cbc-7ac7-43c4-be3f-3d76fd2f46e5
📒 Files selected for processing (12)
README.mdapps/dashboard/src/components/issues/detail/issue-detail-header.tsxapps/dashboard/src/components/pulls/detail/pull-detail-activity.tsxapps/dashboard/src/components/pulls/detail/pull-detail-header.tsxapps/dashboard/src/components/pulls/detail/pull-detail-page.tsxapps/dashboard/src/lib/github-cache-invalidation.test.tsapps/dashboard/src/lib/github-cache-policy.tsapps/dashboard/src/lib/github-revalidation.tsapps/dashboard/src/lib/github.functions.tsapps/dashboard/src/lib/github.types.tsapps/dashboard/src/lib/pr-state.tspackages/ui/src/components/state-pill.tsx
- getCheckRunStatus: treat completed+null conclusion as pending (match backend)
- computePullStatus: paginate checks.listForRef to cover PRs with >100 runs
- rerunChecks: surface partial failures via { partial, failed } on result; UI
shows a warning toast instead of a green success when some reruns hard-fail
- ChecksSection: when checks.total === 0 but workflows await approval, render
an approval-only title/description instead of "0 pending checks"
- Approve workflows CTA: keep loading state until webhook drains the pending
approvals list, with a 30s safety timeout
- README: align Subscribe to events setup checklist with the webhook table
(Status, Repository ruleset, Branch protection rule, Workflow run)
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/dashboard/src/lib/github.functions.ts`:
- Around line 6457-6476: The current approveWorkflowRun batch (inside
approveWorkflowRun Promise.allSettled block) treats any non-empty success set as
full success and returns { ok: true }, hiding partial failures; change the logic
after computing results and rejected to surface partial failures by checking if
rejected.length > 0 and either (a) return a partial-failure mutation payload
containing which run IDs failed and their rejection reasons, or (b) treat any
rejection as overall failure by calling toMutationError with aggregated rejected
reasons; update the branch that currently only checks rejected.length ===
data.workflowRunIds.length to instead handle rejected.length > 0 (use
data.workflowRunIds, results, rejected, approveWorkflowRun, toMutationError and
bustPullDetailCaches to decide whether to call bustPullDetailCaches only on full
success or still call it and include partial-failure metadata).
- Around line 3809-3824: computePullStatus is only fetching the first page of
commit statuses and workflow runs via
context.octokit.rest.repos.getCombinedStatusForRef and
context.octokit.rest.actions.listWorkflowRunsForRepo, which truncates results on
busy PRs; replace those single-page calls with paginated fetches (use
context.octokit.paginate or the rest.paginate helper) to retrieve all pages for
getCombinedStatusForRef and listWorkflowRunsForRepo (remove the fixed
per_page=100 limit), then aggregate the paginated results into the same shape
the rest of computePullStatus expects so check runs and workflow runs are
complete.
- Around line 6331-6341: The run URL parser in the loop that inspects
run.html_url is too strict; update the regex used where match is computed so it
accepts both /actions/runs/{id} and /runs/{id} and allows a trailing slash, a
query string, or end-of-string as terminators. Locate the block that checks
run.app?.slug === "github-actions" and the match = run.html_url?.match(...)
expression, replace the current pattern with one that captures the numeric id
from either "/actions/runs/123" or "/runs/123" and uses a non-capturing group
for the optional "actions/" prefix and a lookahead or alternation to allow "/"
or "?" or end-of-string after the id; keep the rest of the logic that converts
match[1] to Number and sets actionsRunIdByCheck/actionsRunIds unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 81f8f623-a4d9-4aa1-8f43-3461b6a2f480
📒 Files selected for processing (3)
README.mdapps/dashboard/src/components/pulls/detail/pull-detail-activity.tsxapps/dashboard/src/lib/github.functions.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- README.md
- approveWorkflowRuns: surface partial failures via { approved, failed, partial }
matching the rerunChecks shape; UI shows a warning toast on partial success
- Broaden GHA workflow-run URL regex to accept /actions/runs/{id} OR /runs/{id}
with `/`, `?`, or end-of-string terminators (still guarded by app.slug)
- Paginate getCombinedStatusForRef + listWorkflowRunsForRepo in computePullStatus
so large PRs don't truncate statuses or miss approval-awaiting workflow runs
- Dedup combined statuses by context across pages
Summary
Adds GitHub Actions-equivalent CI controls to the PR checks section — re-run buttons and external links to check runs on github.com.
Changes
1.
htmlUrlonPullCheckRuntype (github.types.ts)htmlUrl: string | nullto surface the GitHub check run URL2.
rerunChecksserver function + shared helpers (github.functions.ts)deduplicateCheckRuns— extracted fromcomputePullStatus, now shared withrerunChecksisFailedCheckRun— pure function mirroring the UIgetCheckRunStatuslogic (any completed check that isn't success/neutral/skipped/null)rerunChecks— newPOSTserver function that:failedOnly: true, re-runs only failed checksfailedOnly: false, re-runs all checkschecks.rerequestRunAPIcomputePullStatusto usededuplicateCheckRuns3. PR checks section UI (
pull-detail-activity.tsx)group/run+group-hover/run:opacity-100pattern (matches existinggroup/comment,group/labelpatterns)ghost/xs/Spinnerpattern fromUpdateBranchButtonandMergeFooterChecksSectionnow receivesowner/repo/pullNumberprops4. Unit tests (
github-check-runs.test.ts)deduplicateCheckRuns(5) andisFailedCheckRun(10)Atomic commits
f24e4a0htmlUrltoPullCheckRunce1c6fbrerunChecksfn + shared helpers + refactorcomputePullStatusb8ee1d2c0b63fededuplicateCheckRunsandisFailedCheckRunPermission note
The existing GitHub App permission
Actions: Read-onlyis sufficient for the UI to display checks. To fully enable re-running checks, the App permission needs to be upgraded toActions: Read & write— this is already documented in the README permissions table with the note: "Workflow run history and logs (upgrade to Read & write for rerun/cancel)". If the token lacks write access, the existing 403 error handling + install URL flow will guide users.Screenshots (conceptual)
Before: Check runs show name, status, and app avatar only.
After:
github.com/owner/repo/actions/runs/...Re-run failed checks+Re-run all checksbuttonsTesting
Summary by CodeRabbit
New Features
Documentation
Tests