match a diff line to a read by the params the knot marks any, instead of guessing from a subset of them
Signed-off-by: dawn <90008@klbr.net>
35 unmodified lines3637383940404142434418 unmodified lines636465666768676869707172737475767778757980818222 unmodified lines10510610710810610710810911011111211311411511611711811912010911011111212512612712812913011311411511611711811912012112212315 unmodified lines35 unmodified lines return null;};
const parse = async (files) => { const diffs = { entries: 0, exact: new Set(), nsids: new Set(), defaults: new Set(), any: new Map(), resets: new Set(), repos: new Set(), global: false }; const diffs = { entries: 0, exact: new Set(), defaults: new Set(), any: new Map(), resets: new Set(), repos: new Set(), global: false }; for (const file of files) { let text; try { text = await readFile(file, "utf8");18 unmodified lines if (repo) diffs.repos.add(repo); else diffs.global = true; const params = { ...entry.params }; for (const name of entry.any) delete params[name]; if (!diffs.any.has(entry.nsid)) diffs.any.set(entry.nsid, { names: entry.any, keys: new Set() }); diffs.any.get(entry.nsid).keys.add(keyOf(entry.nsid, params)); // lines of one nsid can leave out different params (a bucketed search vs a plain list) const names = [...entry.any].sort(); const byNames = diffs.any.get(entry.nsid) ?? new Map(); diffs.any.set(entry.nsid, byNames); if (!byNames.has(names.join())) byNames.set(names.join(), { names, keys: new Set() }); byNames.get(names.join()).keys.add(keyOf(entry.nsid, params)); } else { const repo = repoOfParams(entry.params); if (repo) diffs.repos.add(repo); else diffs.global = true; // an added key is one a page may have read while the map default answered it diffs.exact.add(keyOf(entry.nsid, entry.params)); diffs.nsids.add(entry.nsid); } } } return diffs;22 unmodified lines } return params;};
// the knot lists every git read as spelled, but an appview map keys on only some of a// read's params (comments on subject and order, not limit), so a line naming fewer params// stands for every read that has thoseconst MAX_PARAMS = 6;
const touchedBySubset = (diffs, nsid, key) => { const pairs = Object.entries(splitKey(key)); if (pairs.length < 2 || pairs.length > MAX_PARAMS) return false; for (let mask = 1; mask < (1 << pairs.length) - 1; mask++) { const params = Object.fromEntries(pairs.filter((_, i) => mask & (1 << i))); if (diffs.exact.has(keyOf(nsid, params))) return true; } return false;};
const touched = (diffs, key) => { if (diffs.exact.has(key)) return true; const nsid = nsidOf(key); if (diffs.defaults.has(nsid)) return true; if (diffs.nsids.has(nsid) && !nsid.startsWith("org.tangled.git.") && touchedBySubset(diffs, nsid, key)) return true; const any = diffs.any.get(nsid); if (!any) return false; const params = splitKey(key); for (const name of any.names) delete params[name]; return any.keys.has(keyOf(nsid, params)); // a line with `any` matches a read whose params, less those, are the line's for (const { names, keys } of diffs.any.get(nsid)?.values() ?? []) { const params = splitKey(key); for (const name of names) delete params[name]; if (keys.has(keyOf(nsid, params))) return true; } return false;};
// whether the open ticket counts the repo publishes apart from its pages changedexport const countsChanged = (prior, diffs) => (prior.counts ?? []).some((key) => touched(diffs, key));15 unmodified lines98 unmodified lines9910010110210310310410510610710810911011011111211311420 unmodified lines13513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516649 unmodified lines98 unmodified lines assert.deepEqual([...dirtyPages(prior, diffs)].sort(), ["/o/r", "/o/r/issues"]); assert.equal(dirtyPages({ ...prior, did: "did:plc:z" }, diffs), "all");});
test("a comment or a state change dirties the ticket's page and the board, nothing else", async () => {test("a comment or a state change dirties the ticket's page and the board, nothing else, through the params the knot marks any", async () => { const ticket = (rkey) => `at://did:plc:a/org.tangled.track.ticket/${rkey}`; const { hookPath, hook } = await chain([ ["g1", []], [ "g2", [ { op: "changed", nsid: "org.tangled.feed.listComments", params: { order: "desc", subject: ticket(3) }, old: "x", new: "y" }, { op: "changed", nsid: "org.tangled.feed.listComments", params: { order: "desc", subject: ticket(3) }, any: ["limit", "offset"], old: "x", new: "y" }, { op: "changed", nsid: "org.tangled.track.getTicketView", params: { uri: ticket(5) }, old: "x", new: "y" }, { op: "changed", nsid: "org.tangled.search.query", params: { kind: "issue", repoDid: "did:plc:a" }, any: ["q", "state", "limit", "offset", "cursor"] }, { op: "changed", nsid: "org.tangled.git.getTree", params: { ref: "main", repo: "did:plc:a" }, old: "x", new: "y" } ]20 unmodified lines }; assert.deepEqual([...dirtyPages(prior, diffs)].sort(), ["/o/r/issues", "/o/r/issues/3", "/o/r/issues/5"]);});
test("a line matches a read through its any params only, and without any only exactly", async () => { const ticket = "at://did:plc:a/org.tangled.track.ticket/3"; const { hookPath, hook } = await chain([ ["g1", []], [ "g2", [ { op: "changed", nsid: "org.tangled.label.listDefinitions", params: { subject: "did:plc:a" }, any: ["limit", "offset", "order"], old: "x", new: "y" }, { op: "changed", nsid: "org.tangled.temp.review.listPatches", params: { ticket }, old: "x", new: "y" } ] ] ]); const diffs = await readDiff(hookPath, hook, "g1"); const prior = { did: "did:plc:a", pages: { "/o/r/issues/1": page("org.tangled.label.listDefinitions?limit=100&subject=did:plc:a"), "/o/r/pulls/3/latest": page(`org.tangled.temp.review.listPatches?limit=500&order=asc&ticket=${ticket}`), "/o/r/pulls/4/latest": page("org.tangled.label.listDefinitions?limit=100&subject=did:plc:b") } }; assert.deepEqual([...dirtyPages(prior, diffs)], ["/o/r/issues/1"]);});
test("a new ticket changes the repo's counts and no page that doesn't read them", async () => { const { hookPath, hook } = await chain([ ["g1", []], ["g2", [{ op: "changed", nsid: "org.tangled.repo.countIssues", params: { state: "open", subject: "did:plc:a" }, old: "1", new: "2" }]]49 unmodified lines