mirror of
https://github.com/prdlk/leetcode.git
synced 2026-09-16 23:16:26 +00:00
feat(cli): send bucket info to SRS API and render due list from worker
This commit is contained in:
+26
-25
@@ -19,14 +19,12 @@
|
||||
* SRS_ADMIN_KEY for the D1 push (unset = skip it); SRS_API overrides
|
||||
* the Worker URL for local `wrangler dev` runs.
|
||||
*/
|
||||
import { basename, join } from "node:path";
|
||||
import { join } from "node:path";
|
||||
|
||||
import { github } from "./github.ts";
|
||||
import { markdownTable, printTable, writeStepSummary } from "./report.ts";
|
||||
import { isImplemented } from "./source.ts";
|
||||
|
||||
const ROOT = join(import.meta.dir, "..", "..");
|
||||
const WORK = join(ROOT, "work");
|
||||
import { WORK, parseWorkPath, type Bucket } from "./work.ts";
|
||||
|
||||
const DRY =
|
||||
process.argv.includes("--dry-run") ||
|
||||
@@ -41,27 +39,27 @@ const gh = await github();
|
||||
|
||||
interface WorkEntry {
|
||||
files: string[];
|
||||
/** Any bucket implemented — this is what closes the problem issue. */
|
||||
implemented: boolean;
|
||||
/** Buckets holding a real solution: 1 = first solve, 3/7 = the re-solves. */
|
||||
solved: Set<Bucket>;
|
||||
}
|
||||
|
||||
/** LC number -> solution files (a problem may have both js and py). */
|
||||
/** LC number -> its solution files across every bucket (js and py both count). */
|
||||
const work = new Map<number, WorkEntry>();
|
||||
for await (const rel of new Bun.Glob("**/*.{js,py}").scan(WORK)) {
|
||||
const m = basename(rel).match(/^(\d+)\.(.+)\.(?:js|py)$/);
|
||||
if (!m) {
|
||||
console.warn(`skip (unrecognized name): work/${rel}`);
|
||||
const file = parseWorkPath(rel);
|
||||
if (!file) {
|
||||
console.warn(`skip (off-layout): work/${rel}`);
|
||||
continue;
|
||||
}
|
||||
const num = Number(m[1]);
|
||||
const src = await Bun.file(join(WORK, rel)).text();
|
||||
const implemented = isImplemented(src, rel.endsWith(".py") ? "py" : "js");
|
||||
const entry = work.get(num);
|
||||
if (entry) {
|
||||
entry.files.push(`work/${rel}`);
|
||||
entry.implemented ||= implemented;
|
||||
} else {
|
||||
work.set(num, { files: [`work/${rel}`], implemented });
|
||||
}
|
||||
const entry = work.get(file.lc) ?? { files: [], implemented: false, solved: new Set<Bucket>() };
|
||||
entry.files.push(`work/${rel}`);
|
||||
entry.implemented ||= implemented;
|
||||
if (implemented) entry.solved.add(file.bucket);
|
||||
work.set(file.lc, entry);
|
||||
}
|
||||
|
||||
// ── open problem issues ──────────────────────────────────────────
|
||||
@@ -157,14 +155,17 @@ for (const num of [...work.keys()].sort((a, b) => a - b)) {
|
||||
// or the charts, the digest's "already solved" ticks, and the drill/gate
|
||||
// pools all keep treating it as untouched.
|
||||
//
|
||||
// The whole implemented set goes over, not just this run's closes: the
|
||||
// Worker drops anything already on the ladder, so the call is a total
|
||||
// recompute and backfills whatever earlier runs missed.
|
||||
// Each entry carries the BUCKET the file sits in, which is the rung it
|
||||
// settles: work/1 is the first solve, work/3 the 3-day review, work/7 the
|
||||
// 7-day one. That is what makes a pushed re-solve advance the ladder instead
|
||||
// of vanishing — and the Worker writes only when a problem is standing on the
|
||||
// rung named, so the whole implemented set can go over on every push (a total
|
||||
// recompute that backfills whatever earlier runs missed) and re-runs write
|
||||
// nothing.
|
||||
const SRS_API = process.env.SRS_API ?? "https://srs-api.prdlk.workers.dev";
|
||||
const solved = [...work.entries()]
|
||||
.filter(([, entry]) => entry.implemented)
|
||||
.map(([lc]) => lc)
|
||||
.sort((a, b) => a - b);
|
||||
.flatMap(([lc, entry]) => [...entry.solved].sort().map((bucket) => ({ lc, bucket })))
|
||||
.sort((a, b) => a.lc - b.lc || a.bucket - b.bucket);
|
||||
|
||||
let syncNote: string;
|
||||
let syncFailed = false;
|
||||
@@ -180,7 +181,7 @@ if (!process.env.SRS_ADMIN_KEY) {
|
||||
authorization: `Bearer ${process.env.SRS_ADMIN_KEY}`,
|
||||
"content-type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ lc: solved }),
|
||||
body: JSON.stringify({ solved }),
|
||||
});
|
||||
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
|
||||
// Narrow the report payload instead of casting it; a shape change should
|
||||
@@ -209,7 +210,7 @@ printTable(rows);
|
||||
|
||||
const actionable = report.filter((r) => r[3] !== "no open issue");
|
||||
console.log(
|
||||
`\n${work.size} in work/ · ${solved.length} implemented · ` +
|
||||
`\n${work.size} problems in work/ · ${solved.length} solved files across buckets · ` +
|
||||
`${actionable.length} matched an open issue · ` +
|
||||
`${DRY ? `would close ${actionable.filter((r) => r[3] === "would close").length}` : `closed ${closed}`}` +
|
||||
`\nd1: ${syncNote}`,
|
||||
@@ -217,7 +218,7 @@ console.log(
|
||||
|
||||
await writeStepSummary(
|
||||
`### close-solved${DRY ? " (dry run)" : ""}\n\n` +
|
||||
`${work.size} files in \`work/\`, ${solved.length} implemented, ` +
|
||||
`${work.size} problems in \`work/\`, ${solved.length} solved files across buckets, ` +
|
||||
`${actionable.length} matched an open issue.\n\n` +
|
||||
(actionable.length
|
||||
? `${markdownTable([rows[0]!, ...actionable])}\n`
|
||||
|
||||
Reference in New Issue
Block a user