The catalogue holds the module graph, and the modules that make it build themselves #21

Merged
jschoubben merged 21 commits from feat/the-catalogue-module into main 2026-09-13 09:17:11 +00:00
Showing only changes of commit 21ad008879 - Show all commits
+27 -5
View File
@@ -279,11 +279,15 @@ export class Graph {
* Resolved through the artifacts each version published, because that is what an edge names.
*/
async dependents(module: string): Promise<{ module: string; commit: string; againstCommit: string }[]> {
// Distinct, because one artifact may have been published by more than one version of the
// module that made it — several commits producing a byte-identical image — and a dependent
// would otherwise be listed once per such commit, as though it were several dependents.
const { rows } = await this.pool.query(
`SELECT b.module, b.commit_sha, a.commit_sha AS against_commit
`SELECT DISTINCT b.module, b.commit_sha, c2.commit_sha AS against_commit
FROM built_against b
JOIN module_current c ON c.module = b.module AND c.commit_sha = b.commit_sha
JOIN module_artifact a ON a.reference = b.against_reference
JOIN module_current c2 ON c2.module = a.module
WHERE a.module = $1
ORDER BY b.module`, [module]);
return rows.map((r) => ({
@@ -301,14 +305,32 @@ export class Graph {
* chain and a diamond need no special handling and nothing has to know the shape in advance.
*/
async stale(): Promise<Stale[]> {
// **Compared by artifact, not by commit.** A commit moving is not the same as the thing it
// produces moving: a change to a comment in a build recipe is a new commit and a byte-identical
// image, and calling everything built on it stale would mean rebuilding the whole mesh to
// arrive back exactly where it started. What makes a module stale is that the artifact it was
// built against is no longer one the current version publishes.
//
// The producing version is picked as the earliest that published this artifact, because when
// several commits produce the identical image, the first one is where it actually came from.
const { rows } = await this.pool.query(
`SELECT b.module, b.commit_sha, a.module AS against_module, a.commit_sha AS against_commit,
`SELECT b.module, b.commit_sha, p.module AS against_module, p.commit_sha AS against_commit,
c2.commit_sha AS now_at
FROM built_against b
JOIN module_current c1 ON c1.module = b.module AND c1.commit_sha = b.commit_sha
JOIN module_artifact a ON a.reference = b.against_reference
JOIN module_current c2 ON c2.module = a.module
WHERE c2.commit_sha <> a.commit_sha
JOIN LATERAL (
SELECT a.module, a.commit_sha
FROM module_artifact a
JOIN module_version v ON v.module = a.module AND v.commit_sha = a.commit_sha
WHERE a.reference = b.against_reference
ORDER BY v.registered
LIMIT 1
) p ON true
JOIN module_current c2 ON c2.module = p.module
WHERE NOT EXISTS (
SELECT 1 FROM module_artifact now
WHERE now.module = c2.module AND now.commit_sha = c2.commit_sha
AND now.reference = b.against_reference)
ORDER BY b.module`);
const by = new Map<string, Stale>();
for (const r of rows) {