99 lines
2.7 KiB
TypeScript
99 lines
2.7 KiB
TypeScript
import "server-only";
|
|
import { randomUUID } from "node:crypto";
|
|
import { start } from "workflow/api";
|
|
import { admin, required } from "./supabase";
|
|
import { LinearSupportClient } from "./linear-support-client";
|
|
import { cleanupDoneBugReport } from "./bug-cleanup-workflow";
|
|
|
|
export async function scheduleBugCleanup(id: string) {
|
|
if (!process.env.LINEAR_API_KEY || !process.env.LINEAR_TEAM_ID) return;
|
|
const db = admin(),
|
|
claim = `starting:${randomUUID()}`;
|
|
const rows = required(
|
|
await db.rpc("claim_bug_cleanup", { p_report: id, p_worker: claim }),
|
|
);
|
|
for (const report of rows) {
|
|
try {
|
|
const run = await start(cleanupDoneBugReport, [
|
|
id,
|
|
report.closed_at!,
|
|
claim,
|
|
]);
|
|
required(
|
|
await db
|
|
.from("bug_reports")
|
|
.update({ cleanup_run_id: run.runId, cleanup_lease_until: null })
|
|
.eq("id", id)
|
|
.eq("cleanup_run_id", claim)
|
|
.select("id"),
|
|
);
|
|
} catch {
|
|
console.error("Bug report cleanup remains saved for retry.");
|
|
}
|
|
}
|
|
}
|
|
|
|
export async function reconcileBugStatus(id: string, force = false) {
|
|
const db = admin();
|
|
const lookup = await db
|
|
.from("bug_reports")
|
|
.select("*")
|
|
.eq("id", id)
|
|
.maybeSingle();
|
|
if (lookup.error) required(lookup);
|
|
const report = lookup.data;
|
|
if (!report?.issue_synced || report.purge_started_at) return;
|
|
if (report.state === "done" && !report.linear_done_synced) {
|
|
await scheduleBugCleanup(id);
|
|
return;
|
|
}
|
|
if (
|
|
!force &&
|
|
report.status_checked_at &&
|
|
Date.parse(report.status_checked_at) > Date.now() - 60000
|
|
)
|
|
return;
|
|
required(
|
|
await db
|
|
.from("bug_reports")
|
|
.update({ status_checked_at: new Date().toISOString() })
|
|
.eq("id", id)
|
|
.select("id"),
|
|
);
|
|
const linear = new LinearSupportClient(
|
|
process.env.LINEAR_API_KEY!,
|
|
process.env.LINEAR_TEAM_ID!,
|
|
process.env.LINEAR_PROJECT_ID,
|
|
);
|
|
const issue = await linear.issue(id);
|
|
if (!issue) {
|
|
if (report.state === "done") await scheduleBugCleanup(id);
|
|
return;
|
|
}
|
|
if (issue.state?.type === "completed") {
|
|
required(
|
|
await db.rpc("set_bug_report_done", {
|
|
p_report: id,
|
|
p_done: true,
|
|
p_closed_at: issue.completedAt ?? null,
|
|
}),
|
|
);
|
|
// An external completed status may need normalizing to the team's Done status.
|
|
required(
|
|
await db
|
|
.from("bug_reports")
|
|
.update({
|
|
linear_done_synced: issue.state.name.toLowerCase() === "done",
|
|
})
|
|
.eq("id", id)
|
|
.eq("state", "done")
|
|
.select("id"),
|
|
);
|
|
await scheduleBugCleanup(id);
|
|
} else if (report.state === "done") {
|
|
required(
|
|
await db.rpc("set_bug_report_done", { p_report: id, p_done: false }),
|
|
);
|
|
}
|
|
}
|