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
7 changes: 7 additions & 0 deletions .moon/workspace.yml
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,13 @@ projects:
# (runInCI:false) — the shell compile itself is covered by the gtk4 e2e +
# darwin CI lanes.
compass-app-dev: 'tools/compass-app-dev'
# The release-notes generator (compass-distribution §18): assembles the
# Release body appendix + the machine-readable nix-outputs.json manifest from
# the built asset names, the resolved container image and the pinned nix
# toolchain store paths. Registered so its typecheck + unit tests ride the
# moon-driven CI sweep — it was unregistered until RIG-3731, so the release
# lane depended on a tool whose 22 tests never ran in CI.
release-notes: 'tools/release-notes'

# File hashing uses moon's in-process native walker (the v2.5+ default), NOT the
# git shell-out. This is load-bearing: the git hasher (`git ls-files` then `git
Expand Down
15 changes: 11 additions & 4 deletions tools/release-notes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -282,8 +282,14 @@ async function gatherImage(sha: string): Promise<ImageIdentity | null> {
});
}

/** The `nix path-info --json` record shape (the fields the manifest reads). */
/**
* The `nix path-info --json` record shape (the fields the manifest reads).
* The array form carries its own `path`; the keyed form does not — there the
* store path IS the object key, so it is modelled separately rather than
* pretending the value carries one.
*/
type PathInfoEntry = { path: string; narHash?: string };
type KeyedPathInfo = Omit<PathInfoEntry, "path">;

/**
* Resolve the toolchain `langs` set to store paths and run `nix path-info` over
Expand All @@ -305,11 +311,12 @@ async function gatherNixOutputs(): Promise<NixOutput[]> {
const infoJson = await $`nix path-info --json ${store}`.quiet().text();
const info = JSON.parse(infoJson) as
| PathInfoEntry[]
| Record<string, PathInfoEntry>;
// nix path-info emits an array (newer nix) or an object keyed by path.
| Record<string, KeyedPathInfo>;
// nix path-info emits an array (newer nix) or an object keyed by path; in
// the keyed form the key is the authoritative store path.
const entries: PathInfoEntry[] = Array.isArray(info)
? info
: Object.entries(info).map(([path, v]) => ({ path, ...v }));
: Object.entries(info).map(([path, v]) => ({ ...v, path }));
// A single-store-path query returns exactly one entry; anything else means
// `store` did not resolve to one output path and picking [0] would record
// an arbitrary identity — fail loud rather than ship a wrong manifest entry.
Expand Down
Loading