Skip to content
Merged
Show file tree
Hide file tree
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
5 changes: 5 additions & 0 deletions src/db/repositories.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { and, desc, eq, gte, inArray, not, or, sql, type SQL } from "drizzle-orm";

Check notice on line 1 in src/db/repositories.ts

View check run for this annotation

Deleted GitHub App / Gittensory Context

Issue discovery is disabled for this repo

This repo is configured for direct contribution review rather than issue-discovery flow.

Check notice on line 1 in src/db/repositories.ts

View check run for this annotation

Deleted GitHub App / Gittensory Context

Open PR queue is busy

This repo has a busy open PR queue in the local Gittensory cache.

Check notice on line 1 in src/db/repositories.ts

View check run for this annotation

Deleted GitHub App / Gittensory Context

PR author has maintainer association

This PR appears to come from a maintainer-associated account.
import { getDb } from "./client";
import {
advisories,
Expand Down Expand Up @@ -2647,6 +2647,11 @@
});
}

export async function deletePullRequestFiles(env: Env, fullName: string, pullNumber: number): Promise<void> {
const db = getDb(env.DB);
await db.delete(pullRequestFiles).where(and(eq(pullRequestFiles.repoFullName, fullName), eq(pullRequestFiles.pullNumber, pullNumber)));
}

export async function listPullRequestFiles(env: Env, fullName: string, pullNumber: number): Promise<PullRequestFileRecord[]> {
const db = getDb(env.DB);
const rows = await db
Expand Down
62 changes: 49 additions & 13 deletions src/github/backfill.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import {

Check notice on line 1 in src/github/backfill.ts

View check run for this annotation

Deleted GitHub App / Gittensory Context

Issue discovery is disabled for this repo

This repo is configured for direct contribution review rather than issue-discovery flow.

Check notice on line 1 in src/github/backfill.ts

View check run for this annotation

Deleted GitHub App / Gittensory Context

Open PR queue is busy

This repo has a busy open PR queue in the local Gittensory cache.

Check notice on line 1 in src/github/backfill.ts

View check run for this annotation

Deleted GitHub App / Gittensory Context

PR author has maintainer association

This PR appears to come from a maintainer-associated account.
getRepositorySettings,
getRepository,
getPullRequest,
countOpenIssues,
countOpenPullRequests,
countRecentMergedPullRequests,
deletePullRequestFiles,
countRepoLabels,
getInstallation,
getLatestRepoGithubTotalsSnapshot,
Expand Down Expand Up @@ -45,6 +47,7 @@
InstallationHealthRecord,
InstallationRecord,
JsonValue,
PullRequestDetailSyncStateRecord,
PullRequestRecord,
RecentMergedPullRequestRecord,
RepoGithubTotalsSnapshotRecord,
Expand Down Expand Up @@ -560,6 +563,34 @@
};
}

export async function refreshPullRequestDetails(
env: Env,
repoFullName: string,
pullNumber: number,
): Promise<{ ok: true; repoFullName: string; pullNumber: number; status: PullRequestDetailSyncStateRecord["status"]; warnings: string[] }> {
const [repo, pr] = await Promise.all([getRepository(env, repoFullName), getPullRequest(env, repoFullName, pullNumber)]);
if (!repo || !pr) {
return { ok: true, repoFullName, pullNumber, status: "partial", warnings: ["Repository or pull request was not found."] };
}
const token = await tokenForRepo(env, repo);
const warnings: string[] = [];
await upsertPullRequestDetailSyncState(env, { repoFullName, pullNumber, status: "running" });
await fetchAndStorePullRequestDetails(env, repoFullName, pr, token, warnings);
const syncedAt = nowIso();
const status: PullRequestDetailSyncStateRecord["status"] = warnings.length > 0 ? "partial" : "complete";
await upsertPullRequestDetailSyncState(env, {
repoFullName,
pullNumber,
status,
filesSyncedAt: syncedAt,
reviewsSyncedAt: syncedAt,
checksSyncedAt: syncedAt,
lastSyncedAt: syncedAt,
errorSummary: warnings.at(-1),
});
return { ok: true, repoFullName, pullNumber, status, warnings };
}

export async function refreshContributorActivity(
env: Env,
login: string,
Expand Down Expand Up @@ -1698,20 +1729,25 @@
token: string | undefined,
warnings: string[],
): Promise<void> {
const warningStart = warnings.length;
const [files, reviews, checks] = await Promise.all([fetchPullRequestFiles(env, repoFullName, pr.number, token, warnings), fetchPullRequestReviews(env, repoFullName, pr.number, token, warnings), fetchPullRequestChecks(env, repoFullName, pr, token, warnings)]);

for (const file of files) {
await upsertPullRequestFile(env, {
repoFullName,
pullNumber: pr.number,
path: file.filename,
status: file.status,
additions: file.additions ?? 0,
deletions: file.deletions ?? 0,
changes: file.changes ?? 0,
previousFilename: file.previous_filename,
payload: file as unknown as Record<string, JsonValue>,
});
const fileSyncFailed = warnings.slice(warningStart).some((warning) => warning.startsWith(`File sync failed for #${pr.number}:`));

if (!fileSyncFailed) {
await deletePullRequestFiles(env, repoFullName, pr.number);
for (const file of files) {
await upsertPullRequestFile(env, {
repoFullName,
pullNumber: pr.number,
path: file.filename,
status: file.status,
additions: file.additions ?? 0,
deletions: file.deletions ?? 0,
changes: file.changes ?? 0,
previousFilename: file.previous_filename,
payload: file as unknown as Record<string, JsonValue>,
});
}
}
for (const review of reviews) {
await upsertPullRequestReview(env, {
Expand Down
4 changes: 4 additions & 0 deletions src/queue/processors.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {

Check notice on line 1 in src/queue/processors.ts

View check run for this annotation

Deleted GitHub App / Gittensory Context

Issue discovery is disabled for this repo

This repo is configured for direct contribution review rather than issue-discovery flow.

Check notice on line 1 in src/queue/processors.ts

View check run for this annotation

Deleted GitHub App / Gittensory Context

Open PR queue is busy

This repo has a busy open PR queue in the local Gittensory cache.

Check notice on line 1 in src/queue/processors.ts

View check run for this annotation

Deleted GitHub App / Gittensory Context

PR author has maintainer association

This PR appears to come from a maintainer-associated account.
countOpenIssues,
countOpenPullRequests,
getAgentCommandAnswer,
Expand Down Expand Up @@ -65,6 +65,7 @@
enqueueRepositoryOpenDataBackfill,
refreshContributorActivity,
refreshInstallationHealth,
refreshPullRequestDetails,
} from "../github/backfill";
import { contributorRepoStatsFromGittensor, fetchGittensorContributorSnapshot, fetchOfficialGittensorMiner, type GittensorContributorSnapshot, type OfficialGittensorMinerDetection } from "../gittensor/api";
import { createOrUpdateCheckRun, createOrUpdateErroredGateCheckRun, createOrUpdateGateCheckRun, createOrUpdateOverriddenGateCheckRun, createOrUpdatePendingGateCheckRun, createOrUpdateSkippedGateCheckRun, getInstallationId, getRepositoryCollaboratorPermission } from "../github/app";
Expand Down Expand Up @@ -923,6 +924,9 @@
});
await persistAdvisory(env, advisory);
if (installationId && shouldProcessPullRequestPublicSurface(payload.action)) {
if (settings.slopGateMode !== "off" || settings.manifestPolicyGateMode !== "off") {
await refreshPullRequestDetails(env, repoFullName, pr.number);
}
const gate = await maybePublishPrPublicSurface(env, installationId, repoFullName, pr, repo, settings, advisory, {
deliveryId,
authorType: payload.pull_request.user?.type,
Expand Down
80 changes: 80 additions & 0 deletions test/unit/backfill.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { afterEach, describe, expect, it, vi } from "vitest";

Check notice on line 1 in test/unit/backfill.test.ts

View check run for this annotation

Deleted GitHub App / Gittensory Context

Issue discovery is disabled for this repo

This repo is configured for direct contribution review rather than issue-discovery flow.

Check notice on line 1 in test/unit/backfill.test.ts

View check run for this annotation

Deleted GitHub App / Gittensory Context

Open PR queue is busy

This repo has a busy open PR queue in the local Gittensory cache.

Check notice on line 1 in test/unit/backfill.test.ts

View check run for this annotation

Deleted GitHub App / Gittensory Context

PR author has maintainer association

This PR appears to come from a maintainer-associated account.
import {
listCheckSummaries,
listContributorRepoStats,
Expand All @@ -18,6 +18,7 @@
upsertInstallation,
upsertRepoSyncSegment,
upsertRepoSyncState,
upsertPullRequestFile,
upsertPullRequestFromGitHub,
upsertIssueFromGitHub,
upsertRepositoryFromGitHub,
Expand All @@ -32,6 +33,7 @@
enrichInstallationHealth,
refreshContributorActivity,
refreshInstallationHealth,
refreshPullRequestDetails,
} from "../../src/github/backfill";
import { normalizeRegistryPayload } from "../../src/registry/normalize";
import { persistRegistrySnapshot } from "../../src/registry/sync";
Expand Down Expand Up @@ -1792,6 +1794,84 @@
);
});


it("refreshes one pull request's files before gate evaluation and drops stale cached paths", async () => {
const env = createTestEnv({ GITHUB_PUBLIC_TOKEN: "public-token" });
await seedRegisteredRepo(env);
await upsertPullRequestFromGitHub(env, "JSONbored/gittensory", {
number: 12,
title: "Refresh files",
state: "open",
user: { login: "oktofeesh1" },
head: { sha: "new-head" },
labels: [],
body: "",
});
await upsertPullRequestFile(env, {
repoFullName: "JSONbored/gittensory",
pullNumber: 12,
path: "stale/old-secret.txt",
status: "modified",
additions: 1,
deletions: 0,
changes: 1,
payload: { filename: "stale/old-secret.txt" },
});
vi.stubGlobal("fetch", async (input: RequestInfo | URL) => {
const url = input.toString();
if (url.includes("/pulls/12/files")) return Response.json([{ filename: "src/current.ts", status: "modified", additions: 2, deletions: 1, changes: 3 }]);
if (url.includes("/pulls/12/reviews")) return Response.json([]);
if (url.includes("/commits/new-head/check-runs")) return Response.json({ check_runs: [] });
return Response.json([]);
});

const result = await refreshPullRequestDetails(env, "JSONbored/gittensory", 12);

expect(result).toMatchObject({ status: "complete", pullNumber: 12 });
expect(await listPullRequestFiles(env, "JSONbored/gittensory", 12)).toEqual([expect.objectContaining({ path: "src/current.ts", changes: 3 })]);
});

it("preserves cached pull request files when refresh cannot reload the current file list", async () => {
const env = createTestEnv({ GITHUB_PUBLIC_TOKEN: "public-token" });
await seedRegisteredRepo(env);
await upsertPullRequestFromGitHub(env, "JSONbored/gittensory", {
number: 12,
title: "Refresh unavailable",
state: "open",
user: { login: "oktofeesh1" },
head: { sha: "new-head" },
labels: [],
body: "",
});
await upsertPullRequestFile(env, {
repoFullName: "JSONbored/gittensory",
pullNumber: 12,
path: "src/cached.ts",
status: "modified",
additions: 1,
deletions: 0,
changes: 1,
payload: { filename: "src/cached.ts" },
});
vi.stubGlobal("fetch", async (input: RequestInfo | URL, init?: RequestInit) => {
const url = input.toString();
if (url === "https://api.github.com/graphql") {
const query = JSON.parse(String(init?.body ?? "{}")).query as string;
if (query.includes("GittensoryPullRequestDetails")) return Response.json({ data: { repository: { pullRequest: null } } });
}
if (url.includes("/pulls/12/files")) return new Response("files unavailable", { status: 503 });
if (url.includes("/pulls/12/reviews")) return Response.json([]);
if (url.includes("/commits/new-head/check-runs")) return Response.json({ check_runs: [] });
return Response.json([]);
});

const result = await refreshPullRequestDetails(env, "JSONbored/gittensory", 12);

expect(result).toMatchObject({ status: "partial", pullNumber: 12 });
expect(result.warnings).toEqual([expect.stringContaining("File sync failed for #12")]);
expect(await listPullRequestFiles(env, "JSONbored/gittensory", 12)).toEqual([expect.objectContaining({ path: "src/cached.ts", changes: 1 })]);
});

it("records partial PR detail state and check summary segment when check-run fetches fail", async () => {
const env = createTestEnv({ GITHUB_PUBLIC_TOKEN: "public-token" });
await seedRegisteredRepo(env);
Expand Down
Loading