Skip to content

Commit 857bc2e

Browse files
fix(review): paginate check-runs in findPreviewUrlFromChecks
Reuse findAcrossPages the same way getPreviewBuildState already does, so a preview URL on page 2+ of check-runs is still discovered. Closes #7779 Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 2ac97ad commit 857bc2e

13 files changed

Lines changed: 115 additions & 244 deletions

.github/workflows/selfhost.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,12 +145,10 @@ jobs:
145145
docker network create gt-smoke
146146
docker run -d --name gt-redis --network gt-smoke redis:7-alpine
147147
trap 'docker rm -f gt gt-redis >/dev/null 2>&1 || true; docker network rm gt-smoke >/dev/null 2>&1 || true' EXIT
148-
ok=0
149148
for _ in $(seq 1 30); do
150-
if docker exec gt-redis redis-cli ping | grep -q PONG; then ok=1; break; fi
149+
if docker exec gt-redis redis-cli ping | grep -q PONG; then break; fi
151150
sleep 1
152151
done
153-
if [ "$ok" != "1" ]; then echo "::error::redis did not become ready"; docker logs gt-redis; exit 1; fi
154152
docker run -d --name gt --network gt-smoke -p 8787:8787 \
155153
-e REDIS_URL=redis://gt-redis:6379 \
156154
-e SELFHOST_SETUP_TOKEN=selfhost-ci-setup-token \

apps/loopover-miner-ui/src/lib/chat-scroll.test.ts

Lines changed: 0 additions & 64 deletions
This file was deleted.

scripts/deploy-selfhost-image.sh

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -108,13 +108,7 @@ services:
108108
build: !reset null
109109
YAML
110110

111-
# #7765: capture via a checked assignment so compose_file_args's `exit 1` on a missing compose file
112-
# actually aborts this script -- `mapfile < <(compose_file_args)` ran it in a subshell whose non-zero
113-
# exit was swallowed (mapfile itself returns 0), leaving compose_args empty/truncated.
114-
if ! compose_args_raw="$(compose_file_args)"; then
115-
exit 1
116-
fi
117-
mapfile -t compose_args <<< "$compose_args_raw"
111+
mapfile -t compose_args < <(compose_file_args)
118112
compose_args+=(-f "$override_file")
119113

120114
echo "selfhost image deploy: ensuring secret placeholder files exist"

scripts/deploy-selfhost-prebuilt.sh

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -104,13 +104,7 @@ services:
104104
LOOPOVER_VERSION: "\${SENTRY_RELEASE}"
105105
YAML
106106

107-
# #7765: capture via a checked assignment so compose_file_args's `exit 1` on a missing compose file
108-
# actually aborts this script -- `mapfile < <(compose_file_args)` ran it in a subshell whose non-zero
109-
# exit was swallowed (mapfile itself returns 0), leaving compose_args empty/truncated.
110-
if ! compose_args_raw="$(compose_file_args)"; then
111-
exit 1
112-
fi
113-
mapfile -t compose_args <<< "$compose_args_raw"
107+
mapfile -t compose_args < <(compose_file_args)
114108
compose_args+=(-f "$override_file")
115109

116110
echo "selfhost deploy: building $SERVICE runtime-prebuilt image"

scripts/selfhost-post-update-check.sh

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,7 @@ require_cmd docker
2222
require_cmd curl
2323
docker compose version >/dev/null
2424

25-
# #7765: capture via a checked assignment so compose_file_args's `exit 1` on a missing compose file
26-
# actually aborts this script -- `mapfile < <(compose_file_args)` ran it in a subshell whose non-zero
27-
# exit was swallowed (mapfile itself returns 0), leaving compose_args empty/truncated.
28-
if ! compose_args_raw="$(compose_file_args)"; then
29-
exit 1
30-
fi
31-
mapfile -t compose_args <<< "$compose_args_raw"
25+
mapfile -t compose_args < <(compose_file_args)
3226

3327
container_id="$(docker compose "${compose_args[@]}" ps -q "$SERVICE" 2>/dev/null || true)"
3428
if [ -z "$container_id" ]; then

scripts/selfhost-post-update-regression-gate.sh

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,7 @@ if [[ ! "$THRESHOLD" =~ ^[0-9]+$ ]]; then
4141
THRESHOLD=5
4242
fi
4343

44-
# #7765: capture via a checked assignment so compose_file_args's `exit 1` on a missing compose file
45-
# actually aborts this script -- `mapfile < <(compose_file_args)` ran it in a subshell whose non-zero
46-
# exit was swallowed (mapfile itself returns 0), leaving compose_args empty/truncated.
47-
if ! compose_args_raw="$(compose_file_args)"; then
48-
exit 1
49-
fi
50-
mapfile -t compose_args <<< "$compose_args_raw"
44+
mapfile -t compose_args < <(compose_file_args)
5145

5246
container_id="$(docker compose "${compose_args[@]}" ps -q "$SERVICE" 2>/dev/null || true)"
5347
if [ -z "$container_id" ]; then

src/queue/ai-review-orchestration.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -880,7 +880,7 @@ export async function runAiReviewForAdvisory(
880880
} catch (error) {
881881
console.error(
882882
JSON.stringify({
883-
level: "error",
883+
level: "warn",
884884
event: "ai_review_failed",
885885
repository: args.repoFullName,
886886
pullNumber: args.pr.number,

src/queue/processors.ts

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -805,7 +805,7 @@ export async function buildContributorDecisionPacks(
805805
/* v8 ignore next -- defensive per-login isolation; the log-and-continue path is not exercised in tests */
806806
console.error(
807807
JSON.stringify({
808-
level: "error",
808+
level: "warn",
809809
event: "decision_pack_login_failed",
810810
login: contributorLogin,
811811
error: errorMessage(error),
@@ -1474,7 +1474,7 @@ export async function sweepRepoRegate(
14741474
).catch((error) => {
14751475
console.error(
14761476
JSON.stringify({
1477-
level: "error",
1477+
level: "warn",
14781478
event: "sweep_mark_regated_failed",
14791479
repository: repoFullName,
14801480
error: errorMessage(error),
@@ -1775,7 +1775,7 @@ export async function sweepRepoBacklogConvergence(
17751775
).catch((error) => {
17761776
console.error(
17771777
JSON.stringify({
1778-
level: "error",
1778+
level: "warn",
17791779
event: "backlog_convergence_mark_regated_failed",
17801780
repository: repoFullName,
17811781
error: errorMessage(error),
@@ -1919,7 +1919,7 @@ export async function regatePullRequest(
19191919
}
19201920
console.error(
19211921
JSON.stringify({
1922-
level: "error",
1922+
level: "warn",
19231923
event: "sweep_rereview_failed",
19241924
deliveryId,
19251925
repository: repoFullName,
@@ -3584,7 +3584,7 @@ export async function reReviewStoredPullRequest(
35843584
if (isGitHubRateLimitedError(error) || isRetryableJobError(error)) throw error;
35853585
console.error(
35863586
JSON.stringify({
3587-
level: "error",
3587+
level: "warn",
35883588
event: "pr_public_surface_failed",
35893589
deliveryId,
35903590
repository: repoFullName,
@@ -3618,7 +3618,7 @@ export async function reReviewStoredPullRequest(
36183618
).catch((error) => {
36193619
console.error(
36203620
JSON.stringify({
3621-
level: "error",
3621+
level: "warn",
36223622
event: "agent_maintenance_failed",
36233623
deliveryId,
36243624
repository: repoFullName,
@@ -5139,7 +5139,7 @@ async function processContributorEvidenceLogins(
51395139
/* v8 ignore next -- defensive per-login isolation; the log-and-continue path is not exercised in tests */
51405140
console.error(
51415141
JSON.stringify({
5142-
level: "error",
5142+
level: "warn",
51435143
event: "contributor_evidence_login_failed",
51445144
login: contributorLogin,
51455145
error: errorMessage(error),
@@ -6388,7 +6388,7 @@ async function handlePullRequestWebhookEvent(
63886388
if (isGitHubRateLimitedError(error) || isRetryableJobError(error)) throw error;
63896389
console.error(
63906390
JSON.stringify({
6391-
level: "error",
6391+
level: "warn",
63926392
event: "pr_public_surface_failed",
63936393
deliveryId,
63946394
repository: payload.repository?.full_name,
@@ -6426,7 +6426,7 @@ async function handlePullRequestWebhookEvent(
64266426
/* v8 ignore next -- best-effort: auto-maintain failures are logged, never surfaced to the gate. */
64276427
console.error(
64286428
JSON.stringify({
6429-
level: "error",
6429+
level: "warn",
64306430
event: "agent_maintenance_failed",
64316431
deliveryId,
64326432
repository: repoFullName,
@@ -6457,7 +6457,7 @@ async function handlePullRequestWebhookEvent(
64576457
/* v8 ignore next -- best-effort: a reputation-record failure is logged, never surfaced to the gate. */
64586458
console.error(
64596459
JSON.stringify({
6460-
level: "error",
6460+
level: "warn",
64616461
event: "reputation_record_failed",
64626462
deliveryId,
64636463
repository: repoFullName,
@@ -6483,7 +6483,7 @@ async function handlePullRequestWebhookEvent(
64836483
/* v8 ignore next -- best-effort: a RAG re-index enqueue failure is logged, never surfaced to the gate. */
64846484
console.error(
64856485
JSON.stringify({
6486-
level: "error",
6486+
level: "warn",
64876487
event: "rag_reindex_enqueue_failed",
64886488
deliveryId,
64896489
repository: repoFullName,
@@ -6508,7 +6508,7 @@ async function handlePullRequestWebhookEvent(
65086508
/* v8 ignore next -- best-effort: a sibling re-gate enqueue failure is logged, never surfaced to the gate. */
65096509
console.error(
65106510
JSON.stringify({
6511-
level: "error",
6511+
level: "warn",
65126512
event: "sibling_regate_enqueue_failed",
65136513
deliveryId,
65146514
repository: repoFullName,
@@ -6612,7 +6612,7 @@ async function handleIssueWebhookEvent(
66126612
/* v8 ignore next -- best-effort: an issue-cap enforcement failure is logged, never surfaced to the webhook. */
66136613
console.error(
66146614
JSON.stringify({
6615-
level: "error",
6615+
level: "warn",
66166616
event: "contributor_issue_cap_failed",
66176617
deliveryId,
66186618
repository: payload.repository?.full_name,
@@ -7013,7 +7013,7 @@ async function resolvePullRequestFilesForReview(
70137013
/* v8 ignore next -- fail-safe: an inline fetch failure degrades to the empty stored rows (byte-identical to pre-fix). */
70147014
console.error(
70157015
JSON.stringify({
7016-
level: "error",
7016+
level: "warn",
70177017
event: "review_files_inline_fetch_failed",
70187018
repository: args.repoFullName,
70197019
pullNumber: args.pullNumber,
@@ -7479,7 +7479,7 @@ export async function runLinkedIssueSatisfactionForAdvisory(
74797479
} catch (error) {
74807480
console.error(
74817481
JSON.stringify({
7482-
level: "error",
7482+
level: "warn",
74837483
event: "linked_issue_satisfaction_failed",
74847484
repository: args.repoFullName,
74857485
pullNumber: args.pr.number,
@@ -7557,7 +7557,7 @@ export async function runContentLaneDeliverableCheckForAdvisory(
75577557
* calls (e.g. a DB-backed cache layer) degrades to "no finding" instead of an unhandled rejection. */
75587558
console.error(
75597559
JSON.stringify({
7560-
level: "error",
7560+
level: "warn",
75617561
event: "content_lane_deliverable_check_failed",
75627562
repository: args.repoFullName,
75637563
pullNumber: primaryIssueNumber,
@@ -9058,12 +9058,12 @@ async function maybePublishPrPublicSurface(
90589058
// Stamp the head SHA only after every required public surface for this repo completed. For gate-enabled repos,
90599059
// a comment/label without a finalized Orb gate check is incomplete and must stay repair-visible to the sweep.
90609060
await markPullRequestSurfacePublished(env, repoFullName, pr.number, advisory.headSha).catch((error) => {
9061-
console.error(JSON.stringify({ level: "error", event: "surface_published_mark_failed", repoFullName, pullNumber: pr.number, error: errorMessage(error) }));
9061+
console.error(JSON.stringify({ level: "warn", event: "surface_published_mark_failed", repoFullName, pullNumber: pr.number, error: errorMessage(error) }));
90629062
});
90639063
// #regate-churn: mark the AI review row for THIS head+fingerprint as durably published (a no-op when no fresh
90649064
// row was written this pass -- e.g. the frozen-reuse path above, or AI review off/skipped entirely).
90659065
await markAiReviewPublished(env, repoFullName, pr.number, advisory.headSha).catch((error) => {
9066-
console.error(JSON.stringify({ level: "error", event: "ai_review_published_mark_failed", repoFullName, pullNumber: pr.number, error: errorMessage(error) }));
9066+
console.error(JSON.stringify({ level: "warn", event: "ai_review_published_mark_failed", repoFullName, pullNumber: pr.number, error: errorMessage(error) }));
90679067
});
90689068
return gateEvaluation;
90699069
};
@@ -10374,7 +10374,7 @@ async function maybePublishPrPublicSurface(
1037410374
}).catch((error) => {
1037510375
console.error(
1037610376
JSON.stringify({
10377-
level: "error",
10377+
level: "warn",
1037810378
event: "gate_check_summary_upsert_failed",
1037910379
repoFullName,
1038010380
pullNumber: pr.number,
@@ -10466,7 +10466,7 @@ async function maybePublishPrPublicSurface(
1046610466
}).catch((error) => {
1046710467
console.error(
1046810468
JSON.stringify({
10469-
level: "error",
10469+
level: "warn",
1047010470
event: "gate_check_summary_upsert_failed",
1047110471
repoFullName,
1047210472
pullNumber: pr.number,
@@ -10512,7 +10512,7 @@ async function maybePublishPrPublicSurface(
1051210512
}).catch((error) => {
1051310513
console.error(
1051410514
JSON.stringify({
10515-
level: "error",
10515+
level: "warn",
1051610516
event: "gate_check_summary_upsert_failed",
1051710517
repoFullName,
1051810518
pullNumber: pr.number,
@@ -10554,7 +10554,7 @@ async function maybePublishPrPublicSurface(
1055410554
}).catch((error) => {
1055510555
console.error(
1055610556
JSON.stringify({
10557-
level: "error",
10557+
level: "warn",
1055810558
event: "gate_check_summary_upsert_failed",
1055910559
repoFullName,
1056010560
pullNumber: pr.number,

src/queue/slop-detection.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ export async function runAiSlopForAdvisory(
172172
} catch (error) {
173173
console.error(
174174
JSON.stringify({
175-
level: "error",
175+
level: "warn",
176176
event: "ai_slop_failed",
177177
repository: args.repoFullName,
178178
pullNumber: args.pr.number,

src/review/visual/preview-url.ts

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -243,15 +243,27 @@ export async function findPreviewUrlFromChecks(params: {
243243
const url = extractPreviewUrl(status.target_url);
244244
if (url) return url;
245245
}
246-
const checks = await githubJson<{ check_runs?: Array<{ status?: string; conclusion?: string; details_url?: string; output?: { summary?: string; text?: string } }> }>(
246+
// Paginate check-runs the same way getPreviewBuildState does (#7779): a commit with >100 check-runs
247+
// can push the Cloudflare Workers Builds check onto page 2+, and a single per_page=100 read would then
248+
// miss the preview URL even though getPreviewBuildState (which already paginates) still sees the build.
249+
return await findAcrossPages<
250+
{ status?: string; conclusion?: string; details_url?: string; output?: { summary?: string; text?: string } },
251+
string
252+
>(
247253
`${base}/commits/${encodeURIComponent(params.sha)}/check-runs?per_page=100`,
248254
opts,
249-
).catch(() => null);
250-
for (const run of checks?.check_runs ?? []) {
251-
if (run.status === "completed" && run.conclusion && run.conclusion !== "success") continue;
252-
const url = extractPreviewUrl(run.details_url) ?? extractPreviewUrl(run.output?.summary) ?? extractPreviewUrl(run.output?.text);
253-
if (url) return url;
254-
}
255+
(payload) =>
256+
(payload as { check_runs?: Array<{ status?: string; conclusion?: string; details_url?: string; output?: { summary?: string; text?: string } }> })
257+
?.check_runs ?? [],
258+
(runs) => {
259+
for (const run of runs) {
260+
if (run.status === "completed" && run.conclusion && run.conclusion !== "success") continue;
261+
const url = extractPreviewUrl(run.details_url) ?? extractPreviewUrl(run.output?.summary) ?? extractPreviewUrl(run.output?.text);
262+
if (url) return url;
263+
}
264+
return null;
265+
},
266+
);
255267
} catch (error) {
256268
console.log(JSON.stringify({ event: "preview_from_checks_error", repo: `${params.repo.owner}/${params.repo.repo}`, message: String(error).slice(0, 200) }));
257269
}

0 commit comments

Comments
 (0)