@telorun/cli 0.73.0 → 0.75.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bundle/manifest-text.d.ts +28 -0
- package/dist/bundle/manifest-text.d.ts.map +1 -0
- package/dist/bundle/manifest-text.js +92 -0
- package/dist/bundle/manifest-text.js.map +1 -0
- package/dist/bundle/module-payload.d.ts +157 -0
- package/dist/bundle/module-payload.d.ts.map +1 -0
- package/dist/bundle/module-payload.js +273 -0
- package/dist/bundle/module-payload.js.map +1 -0
- package/dist/bundle/payload-drift.d.ts +14 -8
- package/dist/bundle/payload-drift.d.ts.map +1 -1
- package/dist/bundle/payload-drift.js +23 -3
- package/dist/bundle/payload-drift.js.map +1 -1
- package/dist/bundle/select-files.d.ts +16 -4
- package/dist/bundle/select-files.d.ts.map +1 -1
- package/dist/bundle/select-files.js +25 -7
- package/dist/bundle/select-files.js.map +1 -1
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/publish.d.ts +7 -18
- package/dist/commands/publish.d.ts.map +1 -1
- package/dist/commands/publish.js +60 -250
- package/dist/commands/publish.js.map +1 -1
- package/dist/commands/release.d.ts +16 -0
- package/dist/commands/release.d.ts.map +1 -0
- package/dist/commands/release.js +376 -0
- package/dist/commands/release.js.map +1 -0
- package/dist/output.d.ts +40 -0
- package/dist/output.d.ts.map +1 -1
- package/dist/output.js +86 -2
- package/dist/output.js.map +1 -1
- package/dist/release/apply-plan.d.ts +38 -0
- package/dist/release/apply-plan.d.ts.map +1 -0
- package/dist/release/apply-plan.js +103 -0
- package/dist/release/apply-plan.js.map +1 -0
- package/dist/release/evidence.d.ts +56 -0
- package/dist/release/evidence.d.ts.map +1 -0
- package/dist/release/evidence.js +245 -0
- package/dist/release/evidence.js.map +1 -0
- package/dist/release/ledger-store.d.ts +27 -0
- package/dist/release/ledger-store.d.ts.map +1 -0
- package/dist/release/ledger-store.js +62 -0
- package/dist/release/ledger-store.js.map +1 -0
- package/dist/release/render.d.ts +17 -0
- package/dist/release/render.d.ts.map +1 -0
- package/dist/release/render.js +71 -0
- package/dist/release/render.js.map +1 -0
- package/dist/release/workspace.d.ts +58 -0
- package/dist/release/workspace.d.ts.map +1 -0
- package/dist/release/workspace.js +138 -0
- package/dist/release/workspace.js.map +1 -0
- package/package.json +6 -6
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Writing a release plan to disk — the half of `telo release apply` that
|
|
3
|
+
* changes files.
|
|
4
|
+
*
|
|
5
|
+
* Split from the command so the command is wiring: `commands/release.ts` reads
|
|
6
|
+
* argv, resolves the registry and prints, and everything that touches a manifest,
|
|
7
|
+
* a changelog or the ledger is here. The seam is the plan itself, which is
|
|
8
|
+
* already a complete description of what to write.
|
|
9
|
+
*/
|
|
10
|
+
import { type Ledger, type ModuleKey, type ReleasePlan } from "@telorun/analyzer";
|
|
11
|
+
import { type Workspace } from "./workspace.js";
|
|
12
|
+
/** One module's writes, reported so `apply` can list what it touched. */
|
|
13
|
+
export interface AppliedModule {
|
|
14
|
+
readonly key: ModuleKey;
|
|
15
|
+
readonly from: string;
|
|
16
|
+
readonly to: string;
|
|
17
|
+
/** Workspace-relative paths written for this module. */
|
|
18
|
+
readonly files: readonly string[];
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Write every planned module's version and changelog.
|
|
22
|
+
*
|
|
23
|
+
* Returns before the ledger is recorded, because the ledger has to be built from
|
|
24
|
+
* the versions this pass just wrote.
|
|
25
|
+
*/
|
|
26
|
+
export declare function writePlannedVersions(workspace: Workspace, plan: ReleasePlan, date: string): AppliedModule[];
|
|
27
|
+
/**
|
|
28
|
+
* The ledger as it will look once this release is published.
|
|
29
|
+
*
|
|
30
|
+
* Built from a SECOND payload pass taken after the versions are on disk, because
|
|
31
|
+
* that is what will actually ship: a dependent's manifest layer carries its
|
|
32
|
+
* dependency's new version and the pin derived from the dependency's new bytes,
|
|
33
|
+
* neither of which existed while the plan was being formed. Recording the
|
|
34
|
+
* pre-bump digest would guarantee the next `check` reported drift on every
|
|
35
|
+
* module in this release.
|
|
36
|
+
*/
|
|
37
|
+
export declare function recordLedger(root: string, registry: string, plan: ReleasePlan): Promise<Ledger>;
|
|
38
|
+
//# sourceMappingURL=apply-plan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply-plan.d.ts","sourceRoot":"","sources":["../../src/release/apply-plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAML,KAAK,MAAM,EAEX,KAAK,SAAS,EAEd,KAAK,WAAW,EACjB,MAAM,mBAAmB,CAAC;AAM3B,OAAO,EAAgC,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE9E,yEAAyE;AACzE,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,wDAAwD;IACxD,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,WAAW,EACjB,IAAI,EAAE,MAAM,GACX,aAAa,EAAE,CAQjB;AAoDD;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CAChC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,WAAW,GAChB,OAAO,CAAC,MAAM,CAAC,CAuBjB"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Writing a release plan to disk — the half of `telo release apply` that
|
|
3
|
+
* changes files.
|
|
4
|
+
*
|
|
5
|
+
* Split from the command so the command is wiring: `commands/release.ts` reads
|
|
6
|
+
* argv, resolves the registry and prints, and everything that touches a manifest,
|
|
7
|
+
* a changelog or the ledger is here. The seam is the plan itself, which is
|
|
8
|
+
* already a complete description of what to write.
|
|
9
|
+
*/
|
|
10
|
+
import { prependChangelogRelease, renderChangelogRelease, stampCrateVersion, stampManifestVersion, stampPackageVersion, } from "@telorun/analyzer";
|
|
11
|
+
import * as fs from "node:fs";
|
|
12
|
+
import * as path from "node:path";
|
|
13
|
+
import { ModulePayloadBuilder } from "../bundle/module-payload.js";
|
|
14
|
+
import { destinationFor, digestPayload, imageDigest } from "./evidence.js";
|
|
15
|
+
import { readLedger } from "./ledger-store.js";
|
|
16
|
+
import { loadWorkspace, requireModule } from "./workspace.js";
|
|
17
|
+
/**
|
|
18
|
+
* Write every planned module's version and changelog.
|
|
19
|
+
*
|
|
20
|
+
* Returns before the ledger is recorded, because the ledger has to be built from
|
|
21
|
+
* the versions this pass just wrote.
|
|
22
|
+
*/
|
|
23
|
+
export function writePlannedVersions(workspace, plan, date) {
|
|
24
|
+
return plan.modules.map((module) => {
|
|
25
|
+
const discovered = requireModule(workspace, module.key);
|
|
26
|
+
const files = [...stampVersion(discovered.dir, module.to)];
|
|
27
|
+
const changelog = writeChangelog(workspace, discovered.dir, module, date);
|
|
28
|
+
if (changelog)
|
|
29
|
+
files.push(changelog);
|
|
30
|
+
return { key: module.key, from: module.from, to: module.to, files };
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Stamp a module's one version into every manifest it owns.
|
|
35
|
+
*
|
|
36
|
+
* A file that carries no version is skipped — a module may own only a
|
|
37
|
+
* `telo.yaml`, and most have no Rust crate. One whose version is written in a
|
|
38
|
+
* shape that cannot be rewritten in place throws instead, because leaving a
|
|
39
|
+
* module's manifests disagreeing about its own version is worse than stopping.
|
|
40
|
+
*/
|
|
41
|
+
function stampVersion(dir, version) {
|
|
42
|
+
const targets = [
|
|
43
|
+
["telo.yaml", stampManifestVersion],
|
|
44
|
+
["nodejs/package.json", stampPackageVersion],
|
|
45
|
+
["rust/Cargo.toml", stampCrateVersion],
|
|
46
|
+
];
|
|
47
|
+
const written = [];
|
|
48
|
+
for (const [relative, stamp] of targets) {
|
|
49
|
+
const file = path.join(dir, relative);
|
|
50
|
+
if (!fs.existsSync(file))
|
|
51
|
+
continue;
|
|
52
|
+
const before = fs.readFileSync(file, "utf8");
|
|
53
|
+
const after = stamp(before, version, relative);
|
|
54
|
+
if (after === undefined || after === before)
|
|
55
|
+
continue;
|
|
56
|
+
fs.writeFileSync(file, after, "utf8");
|
|
57
|
+
written.push(relative);
|
|
58
|
+
}
|
|
59
|
+
return written;
|
|
60
|
+
}
|
|
61
|
+
/** Prepend this release's block, or nothing when no fragment named the module —
|
|
62
|
+
* a bump that came only from propagation or a toolchain move has no prose, and
|
|
63
|
+
* an empty heading would be worse than silence. */
|
|
64
|
+
function writeChangelog(workspace, dir, module, date) {
|
|
65
|
+
if (module.entries.length === 0)
|
|
66
|
+
return undefined;
|
|
67
|
+
const file = path.join(dir, "CHANGELOG.md");
|
|
68
|
+
const existing = fs.existsSync(file) ? fs.readFileSync(file, "utf8") : undefined;
|
|
69
|
+
fs.writeFileSync(file, prependChangelogRelease(existing, renderChangelogRelease({ version: module.to, date, entries: module.entries })), "utf8");
|
|
70
|
+
return path.relative(workspace.root, file);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* The ledger as it will look once this release is published.
|
|
74
|
+
*
|
|
75
|
+
* Built from a SECOND payload pass taken after the versions are on disk, because
|
|
76
|
+
* that is what will actually ship: a dependent's manifest layer carries its
|
|
77
|
+
* dependency's new version and the pin derived from the dependency's new bytes,
|
|
78
|
+
* neither of which existed while the plan was being formed. Recording the
|
|
79
|
+
* pre-bump digest would guarantee the next `check` reported drift on every
|
|
80
|
+
* module in this release.
|
|
81
|
+
*/
|
|
82
|
+
export async function recordLedger(root, registry, plan) {
|
|
83
|
+
// Re-read the workspace so discovery sees the versions just written.
|
|
84
|
+
const workspace = loadWorkspace(root);
|
|
85
|
+
const planned = new Set(plan.modules.map((module) => module.key));
|
|
86
|
+
const builder = new ModulePayloadBuilder({ cacheRoot: path.join(workspace.root, ".telo") });
|
|
87
|
+
// A module that is not in the plan keeps whatever the ledger already said —
|
|
88
|
+
// which may be nothing, the correct reading for one that has never published.
|
|
89
|
+
// Recording a digest for it here would claim a publish that is not happening.
|
|
90
|
+
const entries = new Map(readLedger(workspace.root).modules);
|
|
91
|
+
for (const module of workspace.modules) {
|
|
92
|
+
if (!planned.has(module.key))
|
|
93
|
+
continue;
|
|
94
|
+
entries.set(module.key, {
|
|
95
|
+
version: module.version,
|
|
96
|
+
layers: module.artifactKind === "image"
|
|
97
|
+
? { image: await imageDigest(module) }
|
|
98
|
+
: await digestPayload(await builder.payload(module.manifestPath, destinationFor(registry, module))),
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
return { registry, modules: entries };
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=apply-plan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply-plan.js","sourceRoot":"","sources":["../../src/release/apply-plan.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collecting what the planner needs: one `ModuleEvidence` per module.
|
|
3
|
+
*
|
|
4
|
+
* Three separate readings, because the plan asks three separate questions:
|
|
5
|
+
*
|
|
6
|
+
* - **The payload digest** — built through the shared `ModulePayloadBuilder`, so
|
|
7
|
+
* the number recorded here is the number `telo publish` computes against the
|
|
8
|
+
* registry. That equality is the whole point of the ledger.
|
|
9
|
+
* - **The edge graph** — from the build's own metafile (which module's source
|
|
10
|
+
* got inlined into whose artifact) and from in-repo relative `imports:`. A
|
|
11
|
+
* declared-dependency graph cannot see `--external`, so `@telorun/sdk` —
|
|
12
|
+
* declared by 54 modules, inlined by none — would bump the entire standard
|
|
13
|
+
* library on every SDK change.
|
|
14
|
+
* - **Own changed files** — a git diff, path-scoped. It used to decide the
|
|
15
|
+
* version, which is why its guesswork had to be sound; here it decides only
|
|
16
|
+
* whether a changelog line is requested.
|
|
17
|
+
*/
|
|
18
|
+
import { type LayerDigests, type ModuleEvidence } from "@telorun/analyzer";
|
|
19
|
+
import { type ModulePayload } from "../bundle/module-payload.js";
|
|
20
|
+
import type { DiscoveredModule, Workspace } from "./workspace.js";
|
|
21
|
+
export interface EvidenceOptions {
|
|
22
|
+
/** `oci://host/org` — the base each module's destination derives from. */
|
|
23
|
+
readonly registry: string;
|
|
24
|
+
/** Git ref the changed-files reading diffs against. */
|
|
25
|
+
readonly baseRef: string;
|
|
26
|
+
/** Called before each module is built, so a long batch shows progress. */
|
|
27
|
+
readonly onModule?: (module: DiscoveredModule, index: number, total: number) => void;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* A module's publish destination: the registry base plus its own directory name.
|
|
31
|
+
*
|
|
32
|
+
* Identity is the ref, never `metadata.name` — this is the same rule the release
|
|
33
|
+
* job has always applied, lifted out of a shell script.
|
|
34
|
+
*
|
|
35
|
+
* This is the ROOT destination, which is a policy rather than a derivation:
|
|
36
|
+
* nothing in the graph can say which repo a module publishes to. The payload
|
|
37
|
+
* builder derives a SIBLING's from it instead of re-applying this rule, so the
|
|
38
|
+
* ref an artifact carries and the destination its dependency is pushed to are
|
|
39
|
+
* the same string by construction.
|
|
40
|
+
*/
|
|
41
|
+
export declare function destinationFor(registry: string, module: DiscoveredModule): string;
|
|
42
|
+
/**
|
|
43
|
+
* A built payload reduced to the per-layer digest map the ledger records.
|
|
44
|
+
*
|
|
45
|
+
* ONE function, because there are two write paths into the ledger — `apply`
|
|
46
|
+
* recording what it is about to publish, and `verify --write` re-recording what
|
|
47
|
+
* the registry actually serves — and the gates only work if they produce the
|
|
48
|
+
* same map. Two hand-built copies that drifted would make `verify --write`
|
|
49
|
+
* record numbers `check` cannot reproduce, and every module would then report
|
|
50
|
+
* permanent phantom drift: the exact failure the ledger's "both gates compute
|
|
51
|
+
* the same number" premise rests on not happening.
|
|
52
|
+
*/
|
|
53
|
+
export declare function digestPayload(payload: ModulePayload): Promise<LayerDigests>;
|
|
54
|
+
export declare function collectEvidence(workspace: Workspace, options: EvidenceOptions): Promise<ModuleEvidence[]>;
|
|
55
|
+
export declare function imageDigest(module: DiscoveredModule): Promise<string>;
|
|
56
|
+
//# sourceMappingURL=evidence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evidence.d.ts","sourceRoot":"","sources":["../../src/release/evidence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,cAAc,EAEpB,MAAM,mBAAmB,CAAC;AAM3B,OAAO,EAAwB,KAAK,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACvF,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAElE,MAAM,WAAW,eAAe;IAC9B,0EAA0E;IAC1E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,uDAAuD;IACvD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,0EAA0E;IAC1E,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACtF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAEjF;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAajF;AAED,wBAAsB,eAAe,CACnC,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,cAAc,EAAE,CAAC,CAe3B;AAmED,wBAAsB,WAAW,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CA8B3E"}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collecting what the planner needs: one `ModuleEvidence` per module.
|
|
3
|
+
*
|
|
4
|
+
* Three separate readings, because the plan asks three separate questions:
|
|
5
|
+
*
|
|
6
|
+
* - **The payload digest** — built through the shared `ModulePayloadBuilder`, so
|
|
7
|
+
* the number recorded here is the number `telo publish` computes against the
|
|
8
|
+
* registry. That equality is the whole point of the ledger.
|
|
9
|
+
* - **The edge graph** — from the build's own metafile (which module's source
|
|
10
|
+
* got inlined into whose artifact) and from in-repo relative `imports:`. A
|
|
11
|
+
* declared-dependency graph cannot see `--external`, so `@telorun/sdk` —
|
|
12
|
+
* declared by 54 modules, inlined by none — would bump the entire standard
|
|
13
|
+
* library on every SDK change.
|
|
14
|
+
* - **Own changed files** — a git diff, path-scoped. It used to decide the
|
|
15
|
+
* version, which is why its guesswork had to be sound; here it decides only
|
|
16
|
+
* whether a changelog line is requested.
|
|
17
|
+
*/
|
|
18
|
+
import { MANIFEST_LAYER, layerDigestKey, } from "@telorun/analyzer";
|
|
19
|
+
import { computeFilesIntegrity } from "@telorun/kernel";
|
|
20
|
+
import { selectByPatterns } from "@telorun/glob";
|
|
21
|
+
import { execFileSync } from "node:child_process";
|
|
22
|
+
import * as fs from "node:fs";
|
|
23
|
+
import * as path from "node:path";
|
|
24
|
+
import { ModulePayloadBuilder } from "../bundle/module-payload.js";
|
|
25
|
+
/**
|
|
26
|
+
* A module's publish destination: the registry base plus its own directory name.
|
|
27
|
+
*
|
|
28
|
+
* Identity is the ref, never `metadata.name` — this is the same rule the release
|
|
29
|
+
* job has always applied, lifted out of a shell script.
|
|
30
|
+
*
|
|
31
|
+
* This is the ROOT destination, which is a policy rather than a derivation:
|
|
32
|
+
* nothing in the graph can say which repo a module publishes to. The payload
|
|
33
|
+
* builder derives a SIBLING's from it instead of re-applying this rule, so the
|
|
34
|
+
* ref an artifact carries and the destination its dependency is pushed to are
|
|
35
|
+
* the same string by construction.
|
|
36
|
+
*/
|
|
37
|
+
export function destinationFor(registry, module) {
|
|
38
|
+
return `${registry.replace(/\/+$/, "")}/${path.basename(module.dir)}`;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* A built payload reduced to the per-layer digest map the ledger records.
|
|
42
|
+
*
|
|
43
|
+
* ONE function, because there are two write paths into the ledger — `apply`
|
|
44
|
+
* recording what it is about to publish, and `verify --write` re-recording what
|
|
45
|
+
* the registry actually serves — and the gates only work if they produce the
|
|
46
|
+
* same map. Two hand-built copies that drifted would make `verify --write`
|
|
47
|
+
* record numbers `check` cannot reproduce, and every module would then report
|
|
48
|
+
* permanent phantom drift: the exact failure the ledger's "both gates compute
|
|
49
|
+
* the same number" premise rests on not happening.
|
|
50
|
+
*/
|
|
51
|
+
export async function digestPayload(payload) {
|
|
52
|
+
// The manifest is not one of `partitionLayers`' layers — the transport writes
|
|
53
|
+
// it as its own — but it is the layer that changes when a dependency's version
|
|
54
|
+
// or pin moves, which is most of what propagation is about.
|
|
55
|
+
const layers = {
|
|
56
|
+
[MANIFEST_LAYER]: await computeFilesIntegrity([
|
|
57
|
+
{ name: MANIFEST_LAYER, content: Buffer.from(payload.manifest, "utf8") },
|
|
58
|
+
]),
|
|
59
|
+
};
|
|
60
|
+
for (const layer of payload.layers) {
|
|
61
|
+
layers[layerDigestKey(layer.role, layer.selector)] = await computeFilesIntegrity(layer.files);
|
|
62
|
+
}
|
|
63
|
+
return layers;
|
|
64
|
+
}
|
|
65
|
+
export async function collectEvidence(workspace, options) {
|
|
66
|
+
const byDir = new Map(workspace.modules.map((module) => [path.resolve(module.dir), module]));
|
|
67
|
+
const changed = changedModules(workspace, options.baseRef);
|
|
68
|
+
const builder = new ModulePayloadBuilder({ cacheRoot: path.join(workspace.root, ".telo") });
|
|
69
|
+
const evidence = [];
|
|
70
|
+
for (const [index, module] of workspace.modules.entries()) {
|
|
71
|
+
options.onModule?.(module, index, workspace.modules.length);
|
|
72
|
+
evidence.push(module.artifactKind === "image"
|
|
73
|
+
? await imageEvidence(module, changed)
|
|
74
|
+
: await registryEvidence(workspace, module, byDir, builder, options, changed));
|
|
75
|
+
}
|
|
76
|
+
return evidence;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* A registry artifact module: the layers `telo publish` builds, digested.
|
|
80
|
+
*/
|
|
81
|
+
async function registryEvidence(workspace, module, byDir, builder, options, changed) {
|
|
82
|
+
const payload = await builder.payload(module.manifestPath, destinationFor(options.registry, module));
|
|
83
|
+
return {
|
|
84
|
+
key: module.key,
|
|
85
|
+
name: module.name,
|
|
86
|
+
version: module.version,
|
|
87
|
+
artifactKind: "registry",
|
|
88
|
+
layers: await digestPayload(payload),
|
|
89
|
+
inlines: attributeInputs(workspace, payload.buildInputs, module, byDir),
|
|
90
|
+
imports: payload.relativeImports
|
|
91
|
+
.map((entry) => byDir.get(path.resolve(path.dirname(entry.manifestPath)))?.key)
|
|
92
|
+
.filter((key) => key !== undefined && key !== module.key),
|
|
93
|
+
ownFilesChanged: changed.has(module.key),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* An image module: the file set its Docker ignore file defines, digested.
|
|
98
|
+
*
|
|
99
|
+
* The ignore file is already the authored statement of what the image contains,
|
|
100
|
+
* so it is read rather than the `COPY` directives parsed. Without a digest here
|
|
101
|
+
* the demoted changed-files rule would be authoritative again for a third of the
|
|
102
|
+
* set — which is precisely the guesswork this design moves off the critical path.
|
|
103
|
+
*
|
|
104
|
+
* The base image is deliberately outside it: a kernel change alters `apps/hub`'s
|
|
105
|
+
* image while this digest does not move. That exposure is closed elsewhere —
|
|
106
|
+
* every app image publishes `:latest` and `:sha-<short>` on each push, so the
|
|
107
|
+
* change reaches the deployed app regardless, and the immutable `:<version>` tag
|
|
108
|
+
* is what a version move is for.
|
|
109
|
+
*/
|
|
110
|
+
async function imageEvidence(module, changed) {
|
|
111
|
+
return {
|
|
112
|
+
key: module.key,
|
|
113
|
+
name: module.name,
|
|
114
|
+
version: module.version,
|
|
115
|
+
artifactKind: "image",
|
|
116
|
+
layers: { image: await imageDigest(module) },
|
|
117
|
+
inlines: new Map(),
|
|
118
|
+
imports: [],
|
|
119
|
+
ownFilesChanged: changed.has(module.key),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
/** BuildKit's per-Dockerfile ignore file, then the classic one. Both image
|
|
123
|
+
* modules here carry the former, and looking for only `.dockerignore` would
|
|
124
|
+
* digest every excluded file in both. */
|
|
125
|
+
const DOCKERIGNORE_NAMES = ["Dockerfile.dockerignore", ".dockerignore"];
|
|
126
|
+
export async function imageDigest(module) {
|
|
127
|
+
const ignoreFile = DOCKERIGNORE_NAMES.map((name) => path.join(module.dir, name)).find((file) => fs.existsSync(file));
|
|
128
|
+
const ignored = ignoreFile
|
|
129
|
+
? fs
|
|
130
|
+
.readFileSync(ignoreFile, "utf8")
|
|
131
|
+
.split("\n")
|
|
132
|
+
.map((line) => line.trim())
|
|
133
|
+
.filter((line) => line !== "" && !line.startsWith("#"))
|
|
134
|
+
: [];
|
|
135
|
+
// An ignore file EXCLUDES, so it goes in `exclude:` rather than being read as
|
|
136
|
+
// a selector — `*` followed by `!*.yaml` means "nothing but the YAML", and
|
|
137
|
+
// treating those as includes would digest exactly the files Docker drops.
|
|
138
|
+
// `exclude` shares the same last-match-wins engine, so the re-include works.
|
|
139
|
+
//
|
|
140
|
+
// The same digest primitive the artifact layers use, so "did this module's
|
|
141
|
+
// payload change?" is one question with one answer regardless of which of the
|
|
142
|
+
// two file sets stands behind it.
|
|
143
|
+
const files = selectByPatterns(listFiles(module.dir), ["**"], {
|
|
144
|
+
applyDefaultIgnore: false,
|
|
145
|
+
exclude: ignored,
|
|
146
|
+
});
|
|
147
|
+
return computeFilesIntegrity([...files].sort().map((file) => ({
|
|
148
|
+
name: file,
|
|
149
|
+
content: fs.readFileSync(path.join(module.dir, file)),
|
|
150
|
+
})));
|
|
151
|
+
}
|
|
152
|
+
function listFiles(root) {
|
|
153
|
+
const found = [];
|
|
154
|
+
const walk = (dir) => {
|
|
155
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
156
|
+
if (entry.name === "node_modules" || entry.name === ".git" || entry.name === ".telo")
|
|
157
|
+
continue;
|
|
158
|
+
const full = path.join(dir, entry.name);
|
|
159
|
+
if (entry.isDirectory())
|
|
160
|
+
walk(full);
|
|
161
|
+
else if (entry.isFile())
|
|
162
|
+
found.push(path.relative(root, full).split(path.sep).join("/"));
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
walk(root);
|
|
166
|
+
return found;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Attribute each build input to the workspace module that owns it.
|
|
170
|
+
*
|
|
171
|
+
* A module's own sources are excluded — they are covered by its digest and by
|
|
172
|
+
* the changed-files reading, and listing them as an inline edge would make every
|
|
173
|
+
* module inline itself. An input under no module (a third-party package, a
|
|
174
|
+
* changesets-owned library) is deliberately not attributed: that is the
|
|
175
|
+
* *unattributed* case, reported rather than papered over.
|
|
176
|
+
*/
|
|
177
|
+
function attributeInputs(workspace, inputs, module, byDir) {
|
|
178
|
+
const owners = new Map();
|
|
179
|
+
for (const input of inputs) {
|
|
180
|
+
const owner = ownerOf(path.resolve(input), byDir);
|
|
181
|
+
if (!owner || owner.key === module.key)
|
|
182
|
+
continue;
|
|
183
|
+
const list = owners.get(owner.key);
|
|
184
|
+
const relative = path.relative(workspace.root, input).split(path.sep).join("/");
|
|
185
|
+
if (list)
|
|
186
|
+
list.push(relative);
|
|
187
|
+
else
|
|
188
|
+
owners.set(owner.key, [relative]);
|
|
189
|
+
}
|
|
190
|
+
for (const files of owners.values())
|
|
191
|
+
files.sort();
|
|
192
|
+
return owners;
|
|
193
|
+
}
|
|
194
|
+
/** The nearest enclosing module directory, by walking up. Nearest rather than
|
|
195
|
+
* any, so a nested module is credited to itself. */
|
|
196
|
+
function ownerOf(file, byDir) {
|
|
197
|
+
let dir = path.dirname(file);
|
|
198
|
+
for (;;) {
|
|
199
|
+
const owner = byDir.get(dir);
|
|
200
|
+
if (owner)
|
|
201
|
+
return owner;
|
|
202
|
+
const parent = path.dirname(dir);
|
|
203
|
+
if (parent === dir)
|
|
204
|
+
return undefined;
|
|
205
|
+
dir = parent;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/** Paths under a module that never reach its artifact, so editing one is not a
|
|
209
|
+
* semantic change worth a changelog line. Kept deliberately short: this rule no
|
|
210
|
+
* longer decides a version, so a false positive costs one sentence and the old
|
|
211
|
+
* per-language guesswork bought nothing. */
|
|
212
|
+
const NON_ARTIFACT_PATHS = [/^docs\//, /^plans\//, /^tests\//, /^README\.md$/, /^CHANGELOG\.md$/];
|
|
213
|
+
/**
|
|
214
|
+
* Modules with a change of their own on this branch.
|
|
215
|
+
*
|
|
216
|
+
* No merge base — a shallow clone, a fresh repo — means the reading cannot be
|
|
217
|
+
* taken, and guessing would ask for a changelog entry at random. The digest is
|
|
218
|
+
* unaffected: it compares against the ledger, not against a ref, which is why it
|
|
219
|
+
* needs no merge base in the first place.
|
|
220
|
+
*/
|
|
221
|
+
function changedModules(workspace, baseRef) {
|
|
222
|
+
let diff;
|
|
223
|
+
try {
|
|
224
|
+
diff = execFileSync("git", ["diff", "--name-only", `${baseRef}...HEAD`], {
|
|
225
|
+
cwd: workspace.root,
|
|
226
|
+
encoding: "utf8",
|
|
227
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
return new Set();
|
|
232
|
+
}
|
|
233
|
+
const changed = new Set();
|
|
234
|
+
for (const file of diff.split("\n").map((line) => line.trim()).filter(Boolean)) {
|
|
235
|
+
const module = workspace.modules.find((candidate) => file.startsWith(`${candidate.key}/`));
|
|
236
|
+
if (!module)
|
|
237
|
+
continue;
|
|
238
|
+
const rest = file.slice(module.key.length + 1);
|
|
239
|
+
if (NON_ARTIFACT_PATHS.some((pattern) => pattern.test(rest)))
|
|
240
|
+
continue;
|
|
241
|
+
changed.add(module.key);
|
|
242
|
+
}
|
|
243
|
+
return changed;
|
|
244
|
+
}
|
|
245
|
+
//# sourceMappingURL=evidence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evidence.js","sourceRoot":"","sources":["../../src/release/evidence.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading and writing `.changes/ledger.yaml`, and the pending fragment
|
|
3
|
+
* directory beside it.
|
|
4
|
+
*
|
|
5
|
+
* The Node half only — the shapes and their parsers are the analyzer's, so the
|
|
6
|
+
* editor reads the same files the same way.
|
|
7
|
+
*/
|
|
8
|
+
import { type Ledger, type ReleaseFragment } from "@telorun/analyzer";
|
|
9
|
+
/** Where a fragment waits to be released. Sits under `.changes/` beside the
|
|
10
|
+
* ledger, so everything the release system owns is in one directory. */
|
|
11
|
+
export declare const PENDING_DIR = ".changes/pending";
|
|
12
|
+
export declare function readLedger(root: string): Ledger;
|
|
13
|
+
export declare function writeLedger(root: string, ledger: Ledger): void;
|
|
14
|
+
/** Every pending fragment, in filename order so a plan's changelog entries land
|
|
15
|
+
* in a stable order across runs. */
|
|
16
|
+
export declare function readFragments(root: string): ReleaseFragment[];
|
|
17
|
+
/**
|
|
18
|
+
* Write a fragment, never over one that already exists.
|
|
19
|
+
*
|
|
20
|
+
* The filename is derived from the kind and the first words of the body, which
|
|
21
|
+
* is what makes the pending directory readable — and what makes a collision
|
|
22
|
+
* possible. Silently overwriting would delete somebody's changelog line, so a
|
|
23
|
+
* taken name gets a `-2` rather than the file it names.
|
|
24
|
+
*/
|
|
25
|
+
export declare function writeFragment(root: string, name: string, text: string): string;
|
|
26
|
+
export declare function deleteFragment(root: string, source: string): void;
|
|
27
|
+
//# sourceMappingURL=ledger-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ledger-store.d.ts","sourceRoot":"","sources":["../../src/release/ledger-store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAML,KAAK,MAAM,EACX,KAAK,eAAe,EACrB,MAAM,mBAAmB,CAAC;AAI3B;yEACyE;AACzE,eAAO,MAAM,WAAW,qBAAqB,CAAC;AAE9C,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI/C;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAI9D;AAED;qCACqC;AACrC,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,EAAE,CAW7D;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAU9E;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAEjE"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading and writing `.changes/ledger.yaml`, and the pending fragment
|
|
3
|
+
* directory beside it.
|
|
4
|
+
*
|
|
5
|
+
* The Node half only — the shapes and their parsers are the analyzer's, so the
|
|
6
|
+
* editor reads the same files the same way.
|
|
7
|
+
*/
|
|
8
|
+
import { EMPTY_LEDGER, LEDGER_PATH, parseFragment, parseLedger, serializeLedger, } from "@telorun/analyzer";
|
|
9
|
+
import * as fs from "node:fs";
|
|
10
|
+
import * as path from "node:path";
|
|
11
|
+
/** Where a fragment waits to be released. Sits under `.changes/` beside the
|
|
12
|
+
* ledger, so everything the release system owns is in one directory. */
|
|
13
|
+
export const PENDING_DIR = ".changes/pending";
|
|
14
|
+
export function readLedger(root) {
|
|
15
|
+
const file = path.join(root, LEDGER_PATH);
|
|
16
|
+
if (!fs.existsSync(file))
|
|
17
|
+
return EMPTY_LEDGER;
|
|
18
|
+
return parseLedger(fs.readFileSync(file, "utf8"), LEDGER_PATH);
|
|
19
|
+
}
|
|
20
|
+
export function writeLedger(root, ledger) {
|
|
21
|
+
const file = path.join(root, LEDGER_PATH);
|
|
22
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
23
|
+
fs.writeFileSync(file, serializeLedger(ledger), "utf8");
|
|
24
|
+
}
|
|
25
|
+
/** Every pending fragment, in filename order so a plan's changelog entries land
|
|
26
|
+
* in a stable order across runs. */
|
|
27
|
+
export function readFragments(root) {
|
|
28
|
+
const dir = path.join(root, PENDING_DIR);
|
|
29
|
+
if (!fs.existsSync(dir))
|
|
30
|
+
return [];
|
|
31
|
+
return fs
|
|
32
|
+
.readdirSync(dir)
|
|
33
|
+
.filter((name) => name.endsWith(".yaml") || name.endsWith(".yml"))
|
|
34
|
+
.sort()
|
|
35
|
+
.map((name) => {
|
|
36
|
+
const source = `${PENDING_DIR}/${name}`;
|
|
37
|
+
return parseFragment(fs.readFileSync(path.join(dir, name), "utf8"), source);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Write a fragment, never over one that already exists.
|
|
42
|
+
*
|
|
43
|
+
* The filename is derived from the kind and the first words of the body, which
|
|
44
|
+
* is what makes the pending directory readable — and what makes a collision
|
|
45
|
+
* possible. Silently overwriting would delete somebody's changelog line, so a
|
|
46
|
+
* taken name gets a `-2` rather than the file it names.
|
|
47
|
+
*/
|
|
48
|
+
export function writeFragment(root, name, text) {
|
|
49
|
+
const dir = path.join(root, PENDING_DIR);
|
|
50
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
51
|
+
const [, stem, ext] = /^(.*?)(\.[^.]+)$/.exec(name) ?? [undefined, name, ""];
|
|
52
|
+
let candidate = name;
|
|
53
|
+
for (let n = 2; fs.existsSync(path.join(dir, candidate)); n++) {
|
|
54
|
+
candidate = `${stem}-${n}${ext}`;
|
|
55
|
+
}
|
|
56
|
+
fs.writeFileSync(path.join(dir, candidate), text, "utf8");
|
|
57
|
+
return `${PENDING_DIR}/${candidate}`;
|
|
58
|
+
}
|
|
59
|
+
export function deleteFragment(root, source) {
|
|
60
|
+
fs.rmSync(path.join(root, source), { force: true });
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=ledger-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ledger-store.js","sourceRoot":"","sources":["../../src/release/ledger-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rendering a release plan for a person.
|
|
3
|
+
*
|
|
4
|
+
* The output's job is to answer "why is this module in the list", because that
|
|
5
|
+
* is the question every previous version of this system could not answer. A
|
|
6
|
+
* payload that moved through an inlined sibling, through an import whose version
|
|
7
|
+
* is about to change, or through nothing anyone can name are three different
|
|
8
|
+
* situations, and only the last one is a judgement call the reader has to make.
|
|
9
|
+
*/
|
|
10
|
+
import type { BumpReason, ReleasePlan } from "@telorun/analyzer";
|
|
11
|
+
import type { Logger } from "../logger.js";
|
|
12
|
+
export declare function describeReason(reason: BumpReason): string;
|
|
13
|
+
export declare function renderPlan(plan: ReleasePlan, log: Logger): string[];
|
|
14
|
+
export declare function renderDiagnostics(plan: ReleasePlan, log: Logger): string[];
|
|
15
|
+
/** The machine surface: the same plan, without the column alignment. */
|
|
16
|
+
export declare function planPayload(plan: ReleasePlan): unknown;
|
|
17
|
+
//# sourceMappingURL=render.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/release/render.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAiB,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAM3C,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAczD;AAgBD,wBAAgB,UAAU,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAenE;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAM1E;AAED,wEAAwE;AACxE,wBAAgB,WAAW,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAetD"}
|