@sdd-method/sdd-cli 1.29.2 → 1.31.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/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/snapshot/advance.d.ts +57 -0
- package/dist/lib/snapshot/advance.d.ts.map +1 -0
- package/dist/lib/snapshot/advance.js +347 -0
- package/dist/lib/snapshot/advance.js.map +1 -0
- package/dist/lib/snapshot/catalogue-diff.d.ts +27 -0
- package/dist/lib/snapshot/catalogue-diff.d.ts.map +1 -0
- package/dist/lib/snapshot/catalogue-diff.js +154 -0
- package/dist/lib/snapshot/catalogue-diff.js.map +1 -0
- package/dist/lib/snapshot/diff.d.ts +73 -0
- package/dist/lib/snapshot/diff.d.ts.map +1 -0
- package/dist/lib/snapshot/diff.js +177 -0
- package/dist/lib/snapshot/diff.js.map +1 -0
- package/dist/lib/snapshot/fold.d.ts +14 -0
- package/dist/lib/snapshot/fold.d.ts.map +1 -0
- package/dist/lib/snapshot/fold.js +106 -0
- package/dist/lib/snapshot/fold.js.map +1 -0
- package/dist/lib/snapshot/land.d.ts +21 -0
- package/dist/lib/snapshot/land.d.ts.map +1 -0
- package/dist/lib/snapshot/land.js +166 -0
- package/dist/lib/snapshot/land.js.map +1 -0
- package/dist/lib/snapshot/manifest.d.ts +63 -0
- package/dist/lib/snapshot/manifest.d.ts.map +1 -0
- package/dist/lib/snapshot/manifest.js +159 -0
- package/dist/lib/snapshot/manifest.js.map +1 -0
- package/dist/lib/snapshot/targets.d.ts +33 -0
- package/dist/lib/snapshot/targets.d.ts.map +1 -0
- package/dist/lib/snapshot/targets.js +147 -0
- package/dist/lib/snapshot/targets.js.map +1 -0
- package/dist/lib/snapshot/verify.d.ts +18 -0
- package/dist/lib/snapshot/verify.d.ts.map +1 -0
- package/dist/lib/snapshot/verify.js +85 -0
- package/dist/lib/snapshot/verify.js.map +1 -0
- package/dist/verbs/catalogue.d.ts.map +1 -1
- package/dist/verbs/catalogue.js +13 -0
- package/dist/verbs/catalogue.js.map +1 -1
- package/dist/verbs/snapshot.d.ts +9 -0
- package/dist/verbs/snapshot.d.ts.map +1 -0
- package/dist/verbs/snapshot.js +128 -0
- package/dist/verbs/snapshot.js.map +1 -0
- package/package.json +2 -2
- package/scripts/build-verify-package.mjs +23 -2
- package/scripts/verify-acceptance.sh +39 -2
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
// `sdd-cli snapshot land` — write T1's set manifest (delta-reverse.md §2).
|
|
2
|
+
//
|
|
3
|
+
// Refusals, each a failure a hand run actually made:
|
|
4
|
+
// - no --id, or an id in the future: the baseline id is the OBSERVATION date and
|
|
5
|
+
// has no default, so the processing date cannot slip in unasked;
|
|
6
|
+
// - a member observed after the set date;
|
|
7
|
+
// - a prior member absent from the export and not declared carried (with a
|
|
8
|
+
// reason) or removed (with a reason) — never left to be inferred;
|
|
9
|
+
// - a member re-exported at the same revision whose bytes differ;
|
|
10
|
+
// - no recorded credential scan, or one with findings but no disposition —
|
|
11
|
+
// a snapshot owner often cannot remediate upstream code, so findings land
|
|
12
|
+
// with the disposition on the record, never as a false `clean`;
|
|
13
|
+
// - an existing snapshot.yaml (no overwrite).
|
|
14
|
+
import { writeFile } from "node:fs/promises";
|
|
15
|
+
import { join } from "node:path";
|
|
16
|
+
import { stringify } from "yaml";
|
|
17
|
+
import { SnapshotError, baselineIds, diffTrees, exists, hashTree, isIsoDate, manifestPath, memberBytesDir, memberFolders, readManifest, splitFolder, } from "./manifest.js";
|
|
18
|
+
const BRANCH_SUFFIX = /-(master|main|develop|trunk)$/;
|
|
19
|
+
export async function runSnapshotLand(inputs, write) {
|
|
20
|
+
try {
|
|
21
|
+
const m = await land(inputs, write);
|
|
22
|
+
write(`landed ${m.snapshot_id}: ${m.members.length} member(s), ${m.members_removed?.length ?? 0} removed\n`);
|
|
23
|
+
return { exitCode: 0 };
|
|
24
|
+
}
|
|
25
|
+
catch (e) {
|
|
26
|
+
if (e instanceof SnapshotError) {
|
|
27
|
+
write(`REFUSED: ${e.message}\n`);
|
|
28
|
+
return { exitCode: 1 };
|
|
29
|
+
}
|
|
30
|
+
throw e;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export async function land(inputs, write) {
|
|
34
|
+
const { areaRoot } = inputs;
|
|
35
|
+
const today = inputs.today ?? new Date().toISOString().slice(0, 10);
|
|
36
|
+
const id = inputs.id;
|
|
37
|
+
if (id === undefined) {
|
|
38
|
+
throw new SnapshotError("--id is required: the date the snapshot was OBSERVED. It has no default, so the date it was processed cannot stand in for it.");
|
|
39
|
+
}
|
|
40
|
+
if (!isIsoDate(id))
|
|
41
|
+
throw new SnapshotError(`--id '${id}' is not a YYYY-MM-DD date`);
|
|
42
|
+
if (id > today)
|
|
43
|
+
throw new SnapshotError(`--id ${id} is in the future (today is ${today})`);
|
|
44
|
+
const dir = join(areaRoot, id);
|
|
45
|
+
if (!(await exists(dir)))
|
|
46
|
+
throw new SnapshotError(`no baseline folder ${dir} — export the members into it first`);
|
|
47
|
+
if (await exists(manifestPath(areaRoot, id))) {
|
|
48
|
+
throw new SnapshotError(`${manifestPath(areaRoot, id)} already exists — land does not overwrite a manifest`);
|
|
49
|
+
}
|
|
50
|
+
const priorId = inputs.prior ?? (await baselineIds(areaRoot)).filter((b) => b < id).pop();
|
|
51
|
+
const prior = priorId === undefined ? null : await readManifest(areaRoot, priorId);
|
|
52
|
+
const implementation = inputs.implementation ?? prior?.implementation;
|
|
53
|
+
if (!implementation)
|
|
54
|
+
throw new SnapshotError("--implementation is required when there is no prior baseline");
|
|
55
|
+
const scan = inputs.credentialScan;
|
|
56
|
+
if (!scan || !scan.tool || !scan.version || !scan.date || !scan.result) {
|
|
57
|
+
throw new SnapshotError("a credential scan must be recorded before anything reads the tree: --credential-scan tool=…,version=…,date=YYYY-MM-DD,result=clean");
|
|
58
|
+
}
|
|
59
|
+
if (!isIsoDate(scan.date))
|
|
60
|
+
throw new SnapshotError(`credential scan date '${scan.date}' is not YYYY-MM-DD`);
|
|
61
|
+
if (scan.result !== "clean" && !scan.disposition) {
|
|
62
|
+
throw new SnapshotError(`credential scan result is '${scan.result}': record a disposition=… (what was found, and why it stands — e.g. present at the prior baseline, upstream's to rotate). ` +
|
|
63
|
+
"Never record `clean` for a scan that found something.");
|
|
64
|
+
}
|
|
65
|
+
if (scan.result !== "clean")
|
|
66
|
+
write(`CREDENTIAL FINDINGS landing on the record: ${scan.result} — ${scan.disposition}\n`);
|
|
67
|
+
const priorByKey = new Map((prior?.members ?? []).map((m) => [m.canonical_repo_key, m]));
|
|
68
|
+
const priorByStem = new Map((prior?.members ?? []).flatMap((m) => {
|
|
69
|
+
const s = splitFolder(m.exported_folder_name);
|
|
70
|
+
return s ? [[s.stem, m.canonical_repo_key]] : [];
|
|
71
|
+
}));
|
|
72
|
+
const members = [];
|
|
73
|
+
const seen = new Set();
|
|
74
|
+
for (const folder of await memberFolders(dir)) {
|
|
75
|
+
const { stem, revision } = splitFolder(folder);
|
|
76
|
+
let key = inputs.keys?.get(folder) ?? priorByStem.get(stem);
|
|
77
|
+
if (key === undefined) {
|
|
78
|
+
key = stem.replace(BRANCH_SUFFIX, "");
|
|
79
|
+
write(`note: ${folder} is new; canonical_repo_key derived as '${key}' (override with --key ${folder}=<key>)\n`);
|
|
80
|
+
}
|
|
81
|
+
if (seen.has(key))
|
|
82
|
+
throw new SnapshotError(`two member folders resolve to canonical_repo_key '${key}'`);
|
|
83
|
+
seen.add(key);
|
|
84
|
+
const entry = { canonical_repo_key: key, exported_folder_name: folder, source_revision: revision };
|
|
85
|
+
const md = inputs.memberDates?.get(key);
|
|
86
|
+
if (md !== undefined) {
|
|
87
|
+
if (!isIsoDate(md))
|
|
88
|
+
throw new SnapshotError(`--member-date ${key}=${md} is not YYYY-MM-DD`);
|
|
89
|
+
if (md > id)
|
|
90
|
+
throw new SnapshotError(`member ${key} observed ${md}, after the set date ${id}`);
|
|
91
|
+
if (md !== id)
|
|
92
|
+
entry.observed_at = md;
|
|
93
|
+
}
|
|
94
|
+
const p = priorByKey.get(key);
|
|
95
|
+
if (prior && p && p.source_revision === revision) {
|
|
96
|
+
const before = await hashTree(memberBytesDir(areaRoot, prior, p));
|
|
97
|
+
const after = await hashTree(join(dir, folder));
|
|
98
|
+
const d = diffTrees(before, after);
|
|
99
|
+
const changed = d.added.length + d.removed.length + d.modified.length;
|
|
100
|
+
if (changed > 0) {
|
|
101
|
+
throw new SnapshotError(`${key} was re-exported at the same revision ${revision} as ${prior.snapshot_id}, but ${changed} file(s) differ — one of the two exports is not what its name says`);
|
|
102
|
+
}
|
|
103
|
+
entry.reverified_at = md ?? id;
|
|
104
|
+
entry.reverification = `re-exported at the same revision as ${prior.snapshot_id}; ${after.size} file(s) byte-identical`;
|
|
105
|
+
}
|
|
106
|
+
members.push(entry);
|
|
107
|
+
}
|
|
108
|
+
const removed = [];
|
|
109
|
+
const unaccounted = [];
|
|
110
|
+
for (const p of prior?.members ?? []) {
|
|
111
|
+
if (seen.has(p.canonical_repo_key))
|
|
112
|
+
continue;
|
|
113
|
+
const reasonCarried = inputs.carried?.get(p.canonical_repo_key);
|
|
114
|
+
const reasonRemoved = inputs.removed?.get(p.canonical_repo_key);
|
|
115
|
+
if (reasonCarried && reasonRemoved) {
|
|
116
|
+
throw new SnapshotError(`${p.canonical_repo_key} is declared both carried and removed`);
|
|
117
|
+
}
|
|
118
|
+
if (reasonCarried) {
|
|
119
|
+
members.push({
|
|
120
|
+
canonical_repo_key: p.canonical_repo_key,
|
|
121
|
+
exported_folder_name: p.exported_folder_name,
|
|
122
|
+
source_revision: p.source_revision,
|
|
123
|
+
carried_from: p.carried_from ?? prior.snapshot_id,
|
|
124
|
+
carried_reason: reasonCarried,
|
|
125
|
+
...(p.role_hint ? { role_hint: p.role_hint } : {}),
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
else if (reasonRemoved) {
|
|
129
|
+
removed.push({
|
|
130
|
+
canonical_repo_key: p.canonical_repo_key,
|
|
131
|
+
last_revision: p.source_revision,
|
|
132
|
+
last_observed: p.carried_from ?? prior.snapshot_id,
|
|
133
|
+
reason: reasonRemoved,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
unaccounted.push(p.canonical_repo_key);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (unaccounted.length > 0) {
|
|
141
|
+
throw new SnapshotError(`${unaccounted.length} member(s) of ${priorId} are absent from this export and not accounted for: ${unaccounted.join(", ")}.\n` +
|
|
142
|
+
" Declare each --carried <key>=<why it was not re-observed> or --removed <key>=<why it left>. " +
|
|
143
|
+
"An absence nobody can explain yet is an open question: carry it with that as its reason, and never let it be inferred.");
|
|
144
|
+
}
|
|
145
|
+
for (const [flag, map] of [["--carried", inputs.carried], ["--removed", inputs.removed]]) {
|
|
146
|
+
for (const k of map?.keys() ?? []) {
|
|
147
|
+
if (!priorByKey.has(k) || seen.has(k))
|
|
148
|
+
throw new SnapshotError(`${flag} ${k}: not a member of ${priorId ?? "the prior baseline"} that is absent from this export`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
const manifest = {
|
|
152
|
+
snapshot_id: id,
|
|
153
|
+
observed_at: id,
|
|
154
|
+
implementation,
|
|
155
|
+
prior_snapshot: priorId ?? null,
|
|
156
|
+
members,
|
|
157
|
+
...(removed.length > 0 ? { members_removed: removed } : {}),
|
|
158
|
+
credential_scan: scan,
|
|
159
|
+
...(inputs.notes ? { notes: inputs.notes } : {}),
|
|
160
|
+
};
|
|
161
|
+
const header = "# Implementation-set snapshot (baseline) -- reverse/artifact-conventions.md \"Implementation-Set Snapshots\".\n" +
|
|
162
|
+
"# Written by `sdd-cli snapshot land`.\n";
|
|
163
|
+
await writeFile(manifestPath(areaRoot, id), header + stringify(manifest, { lineWidth: 0 }));
|
|
164
|
+
return manifest;
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=land.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"land.js","sourceRoot":"","sources":["../../../src/lib/snapshot/land.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export interface ManifestMember {
|
|
2
|
+
canonical_repo_key: string;
|
|
3
|
+
exported_folder_name: string;
|
|
4
|
+
source_revision: string;
|
|
5
|
+
observed_at?: string;
|
|
6
|
+
carried_from?: string;
|
|
7
|
+
carried_reason?: string;
|
|
8
|
+
reverified_at?: string;
|
|
9
|
+
reverification?: string;
|
|
10
|
+
role_hint?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface RemovedMember {
|
|
13
|
+
canonical_repo_key: string;
|
|
14
|
+
last_revision: string;
|
|
15
|
+
last_observed?: string;
|
|
16
|
+
reason: string;
|
|
17
|
+
}
|
|
18
|
+
export interface CredentialScan {
|
|
19
|
+
tool: string;
|
|
20
|
+
version: string;
|
|
21
|
+
date: string;
|
|
22
|
+
result: string;
|
|
23
|
+
/** Required when result is not `clean`: what was found, and why it stands. */
|
|
24
|
+
disposition?: string;
|
|
25
|
+
}
|
|
26
|
+
/** The line every later verb prints while a baseline carries unresolved credential findings. */
|
|
27
|
+
export declare function credentialNotice(m: SnapshotManifest): string | null;
|
|
28
|
+
export interface SnapshotManifest {
|
|
29
|
+
snapshot_id: string;
|
|
30
|
+
observed_at: string;
|
|
31
|
+
implementation: string;
|
|
32
|
+
prior_snapshot: string | null;
|
|
33
|
+
members: ManifestMember[];
|
|
34
|
+
members_removed?: RemovedMember[];
|
|
35
|
+
credential_scan?: CredentialScan;
|
|
36
|
+
notes?: string;
|
|
37
|
+
}
|
|
38
|
+
export declare class SnapshotError extends Error {
|
|
39
|
+
}
|
|
40
|
+
export declare function isIsoDate(s: unknown): s is string;
|
|
41
|
+
/** `name-branch@rev` → { stem: "name-branch", revision: "rev" }. */
|
|
42
|
+
export declare function splitFolder(folder: string): {
|
|
43
|
+
stem: string;
|
|
44
|
+
revision: string;
|
|
45
|
+
} | null;
|
|
46
|
+
/** Member folders (`*@*` directories) directly under a baseline directory. */
|
|
47
|
+
export declare function memberFolders(baselineDir: string): Promise<string[]>;
|
|
48
|
+
/** Dated baseline ids under an area, ascending. */
|
|
49
|
+
export declare function baselineIds(areaRoot: string): Promise<string[]>;
|
|
50
|
+
export declare function exists(p: string): Promise<boolean>;
|
|
51
|
+
export declare function manifestPath(areaRoot: string, id: string): string;
|
|
52
|
+
export declare function readManifest(areaRoot: string, id: string): Promise<SnapshotManifest>;
|
|
53
|
+
/** Where a member's bytes live: its own baseline, or the one it was carried from. */
|
|
54
|
+
export declare function memberBytesDir(areaRoot: string, manifest: SnapshotManifest, m: ManifestMember): string;
|
|
55
|
+
/** relative path → sha256 for every file under a directory. */
|
|
56
|
+
export declare function hashTree(root: string): Promise<Map<string, string>>;
|
|
57
|
+
export interface FileDelta {
|
|
58
|
+
added: string[];
|
|
59
|
+
removed: string[];
|
|
60
|
+
modified: string[];
|
|
61
|
+
}
|
|
62
|
+
export declare function diffTrees(before: Map<string, string>, after: Map<string, string>): FileDelta;
|
|
63
|
+
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../src/lib/snapshot/manifest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
// Implementation-set snapshot manifests (`<area>/<baseline-id>/snapshot.yaml`)
|
|
2
|
+
// and the file-level primitives the `snapshot` verbs share.
|
|
3
|
+
//
|
|
4
|
+
// The shape is the method's, not this module's: reverse/artifact-conventions.md
|
|
5
|
+
// "Implementation-Set Snapshots". Where the conventions REQUIRE a companion
|
|
6
|
+
// field (`carried_reason` beside `carried_from`, `reverification` beside
|
|
7
|
+
// `reverified_at`), readManifest refuses a manifest without it — a carried member
|
|
8
|
+
// with no reason cannot be told apart from an unrecorded removal.
|
|
9
|
+
import { createHash } from "node:crypto";
|
|
10
|
+
import { readdir, readFile, stat } from "node:fs/promises";
|
|
11
|
+
import { join, relative, sep } from "node:path";
|
|
12
|
+
import { parse } from "yaml";
|
|
13
|
+
/** The line every later verb prints while a baseline carries unresolved credential findings. */
|
|
14
|
+
export function credentialNotice(m) {
|
|
15
|
+
const s = m.credential_scan;
|
|
16
|
+
if (!s || s.result === "clean")
|
|
17
|
+
return null;
|
|
18
|
+
return `CREDENTIAL FINDINGS on record for ${m.snapshot_id}: ${s.result} — ${s.disposition ?? "NO DISPOSITION"}`;
|
|
19
|
+
}
|
|
20
|
+
export class SnapshotError extends Error {
|
|
21
|
+
}
|
|
22
|
+
const DATE = /^\d{4}-\d{2}-\d{2}$/;
|
|
23
|
+
export function isIsoDate(s) {
|
|
24
|
+
if (typeof s !== "string" || !DATE.test(s))
|
|
25
|
+
return false;
|
|
26
|
+
const d = new Date(`${s}T00:00:00Z`);
|
|
27
|
+
return !Number.isNaN(d.getTime()) && d.toISOString().slice(0, 10) === s;
|
|
28
|
+
}
|
|
29
|
+
/** `name-branch@rev` → { stem: "name-branch", revision: "rev" }. */
|
|
30
|
+
export function splitFolder(folder) {
|
|
31
|
+
const at = folder.lastIndexOf("@");
|
|
32
|
+
if (at <= 0 || at === folder.length - 1)
|
|
33
|
+
return null;
|
|
34
|
+
return { stem: folder.slice(0, at), revision: folder.slice(at + 1) };
|
|
35
|
+
}
|
|
36
|
+
/** Member folders (`*@*` directories) directly under a baseline directory. */
|
|
37
|
+
export async function memberFolders(baselineDir) {
|
|
38
|
+
const out = [];
|
|
39
|
+
for (const e of await readdir(baselineDir, { withFileTypes: true })) {
|
|
40
|
+
if (e.isDirectory() && splitFolder(e.name) !== null)
|
|
41
|
+
out.push(e.name);
|
|
42
|
+
}
|
|
43
|
+
return out.sort();
|
|
44
|
+
}
|
|
45
|
+
/** Dated baseline ids under an area, ascending. */
|
|
46
|
+
export async function baselineIds(areaRoot) {
|
|
47
|
+
const out = [];
|
|
48
|
+
for (const e of await readdir(areaRoot, { withFileTypes: true })) {
|
|
49
|
+
if (e.isDirectory() && isIsoDate(e.name))
|
|
50
|
+
out.push(e.name);
|
|
51
|
+
}
|
|
52
|
+
return out.sort();
|
|
53
|
+
}
|
|
54
|
+
export async function exists(p) {
|
|
55
|
+
try {
|
|
56
|
+
await stat(p);
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
export function manifestPath(areaRoot, id) {
|
|
64
|
+
return join(areaRoot, id, "snapshot.yaml");
|
|
65
|
+
}
|
|
66
|
+
export async function readManifest(areaRoot, id) {
|
|
67
|
+
const p = manifestPath(areaRoot, id);
|
|
68
|
+
if (!(await exists(p)))
|
|
69
|
+
throw new SnapshotError(`no manifest at ${p}`);
|
|
70
|
+
const raw = parse(await readFile(p, "utf8"));
|
|
71
|
+
if (raw === null || typeof raw !== "object")
|
|
72
|
+
throw new SnapshotError(`${p}: not a mapping`);
|
|
73
|
+
const problems = [];
|
|
74
|
+
if (raw.snapshot_id !== id)
|
|
75
|
+
problems.push(`snapshot_id '${String(raw.snapshot_id)}' does not match its folder '${id}'`);
|
|
76
|
+
if (!isIsoDate(raw.observed_at))
|
|
77
|
+
problems.push("observed_at must be YYYY-MM-DD");
|
|
78
|
+
if (typeof raw.implementation !== "string" || raw.implementation === "")
|
|
79
|
+
problems.push("implementation missing");
|
|
80
|
+
if (raw.prior_snapshot !== null && raw.prior_snapshot !== undefined && !isIsoDate(raw.prior_snapshot)) {
|
|
81
|
+
problems.push("prior_snapshot must be a baseline id or null");
|
|
82
|
+
}
|
|
83
|
+
if (!Array.isArray(raw.members))
|
|
84
|
+
problems.push("members must be a list");
|
|
85
|
+
// A hand-written revision of digits only (`50834756022`) parses as a NUMBER, and
|
|
86
|
+
// a strict comparison with the folder's string suffix then calls an unchanged
|
|
87
|
+
// member changed. Identity fields are strings, whatever YAML made of them.
|
|
88
|
+
for (const m of raw.members ?? []) {
|
|
89
|
+
if (m && typeof m === "object") {
|
|
90
|
+
for (const f of ["canonical_repo_key", "exported_folder_name", "source_revision"]) {
|
|
91
|
+
if (typeof m[f] === "number")
|
|
92
|
+
m[f] = String(m[f]);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
for (const r of raw.members_removed ?? []) {
|
|
97
|
+
if (r && typeof r.last_revision === "number")
|
|
98
|
+
r.last_revision = String(r.last_revision);
|
|
99
|
+
}
|
|
100
|
+
for (const [i, m] of (raw.members ?? []).entries()) {
|
|
101
|
+
const at = `members[${i}] (${m?.canonical_repo_key ?? "?"})`;
|
|
102
|
+
if (!m?.canonical_repo_key || !m.exported_folder_name || !m.source_revision) {
|
|
103
|
+
problems.push(`${at}: canonical_repo_key, exported_folder_name and source_revision are required`);
|
|
104
|
+
}
|
|
105
|
+
if (m?.carried_from !== undefined && !m.carried_reason)
|
|
106
|
+
problems.push(`${at}: carried_from requires carried_reason`);
|
|
107
|
+
if (m?.reverified_at !== undefined && !m.reverification)
|
|
108
|
+
problems.push(`${at}: reverified_at requires reverification`);
|
|
109
|
+
}
|
|
110
|
+
for (const [i, r] of (raw.members_removed ?? []).entries()) {
|
|
111
|
+
if (!r?.canonical_repo_key || !r.last_revision || !r.reason) {
|
|
112
|
+
problems.push(`members_removed[${i}]: canonical_repo_key, last_revision and reason are required`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (problems.length > 0)
|
|
116
|
+
throw new SnapshotError(`${p}:\n - ${problems.join("\n - ")}`);
|
|
117
|
+
return raw;
|
|
118
|
+
}
|
|
119
|
+
/** Where a member's bytes live: its own baseline, or the one it was carried from. */
|
|
120
|
+
export function memberBytesDir(areaRoot, manifest, m) {
|
|
121
|
+
return join(areaRoot, m.carried_from ?? manifest.snapshot_id, m.exported_folder_name);
|
|
122
|
+
}
|
|
123
|
+
/** relative path → sha256 for every file under a directory. */
|
|
124
|
+
export async function hashTree(root) {
|
|
125
|
+
const out = new Map();
|
|
126
|
+
async function walk(dir) {
|
|
127
|
+
for (const e of await readdir(dir, { withFileTypes: true })) {
|
|
128
|
+
const full = join(dir, e.name);
|
|
129
|
+
if (e.isDirectory()) {
|
|
130
|
+
if (e.name === ".git")
|
|
131
|
+
continue;
|
|
132
|
+
await walk(full);
|
|
133
|
+
}
|
|
134
|
+
else if (e.isFile()) {
|
|
135
|
+
const h = createHash("sha256").update(await readFile(full)).digest("hex");
|
|
136
|
+
out.set(relative(root, full).split(sep).join("/"), h);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
await walk(root);
|
|
141
|
+
return out;
|
|
142
|
+
}
|
|
143
|
+
export function diffTrees(before, after) {
|
|
144
|
+
const added = [];
|
|
145
|
+
const removed = [];
|
|
146
|
+
const modified = [];
|
|
147
|
+
for (const [p, h] of after) {
|
|
148
|
+
const b = before.get(p);
|
|
149
|
+
if (b === undefined)
|
|
150
|
+
added.push(p);
|
|
151
|
+
else if (b !== h)
|
|
152
|
+
modified.push(p);
|
|
153
|
+
}
|
|
154
|
+
for (const p of before.keys())
|
|
155
|
+
if (!after.has(p))
|
|
156
|
+
removed.push(p);
|
|
157
|
+
return { added: added.sort(), removed: removed.sort(), modified: modified.sort() };
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../src/lib/snapshot/manifest.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,4DAA4D;AAC5D,EAAE;AACF,gFAAgF;AAChF,4EAA4E;AAC5E,yEAAyE;AACzE,kFAAkF;AAClF,kEAAkE;AAElE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AA8B7B,gGAAgG;AAChG,MAAM,UAAU,gBAAgB,CAAC,CAAmB;IAClD,MAAM,CAAC,GAAG,CAAC,CAAC,eAAe,CAAC;IAC5B,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,OAAO;QAAE,OAAO,IAAI,CAAC;IAC5C,OAAO,qCAAqC,CAAC,CAAC,WAAW,KAAK,CAAC,CAAC,MAAM,MAAM,CAAC,CAAC,WAAW,IAAI,gBAAgB,EAAE,CAAC;AAClH,CAAC;AAaD,MAAM,OAAO,aAAc,SAAQ,KAAK;CAAG;AAE3C,MAAM,IAAI,GAAG,qBAAqB,CAAC;AAEnC,MAAM,UAAU,SAAS,CAAC,CAAU;IAClC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACzD,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IACrC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;AAC1E,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,WAAW,CAAC,MAAc;IACxC,MAAM,EAAE,GAAG,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACnC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACrD,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC;AACvE,CAAC;AAED,8EAA8E;AAC9E,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,WAAmB;IACrD,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,CAAC,IAAI,MAAM,OAAO,CAAC,WAAW,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QACpE,IAAI,CAAC,CAAC,WAAW,EAAE,IAAI,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI;YAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACxE,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;AACpB,CAAC;AAED,mDAAmD;AACnD,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,QAAgB;IAChD,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,CAAC,IAAI,MAAM,OAAO,CAAC,QAAQ,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QACjE,IAAI,CAAC,CAAC,WAAW,EAAE,IAAI,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAC7D,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;AACpB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,CAAS;IACpC,IAAI,CAAC;QACH,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC;QACd,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,QAAgB,EAAE,EAAU;IACvD,OAAO,IAAI,CAAC,QAAQ,EAAE,EAAE,EAAE,eAAe,CAAC,CAAC;AAC7C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAgB,EAAE,EAAU;IAC7D,MAAM,CAAC,GAAG,YAAY,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACrC,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,CAAC,CAAC,CAAC;QAAE,MAAM,IAAI,aAAa,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC;IACvE,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,CAAqC,CAAC;IACjF,IAAI,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,MAAM,IAAI,aAAa,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IAC5F,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,GAAG,CAAC,WAAW,KAAK,EAAE;QAAE,QAAQ,CAAC,IAAI,CAAC,gBAAgB,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,gCAAgC,EAAE,GAAG,CAAC,CAAC;IACxH,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC;QAAE,QAAQ,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;IACjF,IAAI,OAAO,GAAG,CAAC,cAAc,KAAK,QAAQ,IAAI,GAAG,CAAC,cAAc,KAAK,EAAE;QAAE,QAAQ,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;IACjH,IAAI,GAAG,CAAC,cAAc,KAAK,IAAI,IAAI,GAAG,CAAC,cAAc,KAAK,SAAS,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC;QACtG,QAAQ,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAC;IAChE,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;QAAE,QAAQ,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;IACzE,iFAAiF;IACjF,8EAA8E;IAC9E,2EAA2E;IAC3E,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;QAClC,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;YAC/B,KAAK,MAAM,CAAC,IAAI,CAAC,oBAAoB,EAAE,sBAAsB,EAAE,iBAAiB,CAAU,EAAE,CAAC;gBAC3F,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,QAAQ;oBAAG,CAAwC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC5F,CAAC;QACH,CAAC;IACH,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,eAAe,IAAI,EAAE,EAAE,CAAC;QAC1C,IAAI,CAAC,IAAI,OAAO,CAAC,CAAC,aAAa,KAAK,QAAQ;YAAG,CAAwC,CAAC,aAAa,GAAG,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;IAClI,CAAC;IACD,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;QACnD,MAAM,EAAE,GAAG,WAAW,CAAC,MAAM,CAAC,EAAE,kBAAkB,IAAI,GAAG,GAAG,CAAC;QAC7D,IAAI,CAAC,CAAC,EAAE,kBAAkB,IAAI,CAAC,CAAC,CAAC,oBAAoB,IAAI,CAAC,CAAC,CAAC,eAAe,EAAE,CAAC;YAC5E,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,6EAA6E,CAAC,CAAC;QACpG,CAAC;QACD,IAAI,CAAC,EAAE,YAAY,KAAK,SAAS,IAAI,CAAC,CAAC,CAAC,cAAc;YAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,wCAAwC,CAAC,CAAC;QACrH,IAAI,CAAC,EAAE,aAAa,KAAK,SAAS,IAAI,CAAC,CAAC,CAAC,cAAc;YAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,yCAAyC,CAAC,CAAC;IACzH,CAAC;IACD,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;QAC3D,IAAI,CAAC,CAAC,EAAE,kBAAkB,IAAI,CAAC,CAAC,CAAC,aAAa,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;YAC5D,QAAQ,CAAC,IAAI,CAAC,mBAAmB,CAAC,8DAA8D,CAAC,CAAC;QACpG,CAAC;IACH,CAAC;IACD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,IAAI,aAAa,CAAC,GAAG,CAAC,UAAU,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC1F,OAAO,GAAuB,CAAC;AACjC,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,cAAc,CAAC,QAAgB,EAAE,QAA0B,EAAE,CAAiB;IAC5F,OAAO,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,YAAY,IAAI,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC,oBAAoB,CAAC,CAAC;AACxF,CAAC;AAED,+DAA+D;AAC/D,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAAY;IACzC,MAAM,GAAG,GAAG,IAAI,GAAG,EAAkB,CAAC;IACtC,KAAK,UAAU,IAAI,CAAC,GAAW;QAC7B,KAAK,MAAM,CAAC,IAAI,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;YAC5D,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;YAC/B,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;gBACpB,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM;oBAAE,SAAS;gBAChC,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;YACnB,CAAC;iBAAM,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;gBACtB,MAAM,CAAC,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBAC1E,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;YACxD,CAAC;QACH,CAAC;IACH,CAAC;IACD,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;IACjB,OAAO,GAAG,CAAC;AACb,CAAC;AAQD,MAAM,UAAU,SAAS,CAAC,MAA2B,EAAE,KAA0B;IAC/E,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC;QAC3B,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACxB,IAAI,CAAC,KAAK,SAAS;YAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;aAC9B,IAAI,CAAC,KAAK,CAAC;YAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACrC,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,EAAE;QAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;YAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClE,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;AACrF,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type DeltaFinding } from "./diff.js";
|
|
2
|
+
type Writer = (s: string) => void;
|
|
3
|
+
export interface TargetsInputs {
|
|
4
|
+
sddPath: string;
|
|
5
|
+
areaRoot: string;
|
|
6
|
+
id: string;
|
|
7
|
+
/** Globs (SDD-relative) naming GENERATED artefacts — scores, reports, registries: regenerated, never re-derived. */
|
|
8
|
+
derived?: readonly string[];
|
|
9
|
+
}
|
|
10
|
+
export interface Target {
|
|
11
|
+
artefact: string;
|
|
12
|
+
/** file: cites a changed path. repo: only names the member. confirmed: narrowed by hand. */
|
|
13
|
+
grain: "file" | "repo" | "confirmed";
|
|
14
|
+
cited: string;
|
|
15
|
+
/** spec: an artefact to re-derive by reading it. derived: one to regenerate. */
|
|
16
|
+
kind?: "spec" | "derived";
|
|
17
|
+
}
|
|
18
|
+
/** Minimal glob → RegExp: `**` any path, `*` within a segment, `?` one character. */
|
|
19
|
+
export declare function globToRegExp(glob: string): RegExp;
|
|
20
|
+
/** Every text artefact of the SDD, excluding the method's own copies and generated catalogues. */
|
|
21
|
+
export declare function sddArtefacts(sddPath: string): Promise<Map<string, string>>;
|
|
22
|
+
/**
|
|
23
|
+
* `shared` holds paths that more than one member changed (`helm/values.yaml`,
|
|
24
|
+
* `src/main/resources/application.properties`): a citation of one of those names
|
|
25
|
+
* nobody in particular, so it is file grain only on a line that also names this
|
|
26
|
+
* member. Without that, a citation of another member's copy reads as precise.
|
|
27
|
+
*/
|
|
28
|
+
export declare function routeFinding(f: Pick<DeltaFinding, "member" | "files">, artefacts: ReadonlyMap<string, string>, shared?: ReadonlySet<string>): Target[];
|
|
29
|
+
export declare function runSnapshotTargets(inputs: TargetsInputs, write: Writer): Promise<{
|
|
30
|
+
exitCode: number;
|
|
31
|
+
}>;
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=targets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"targets.d.ts","sourceRoot":"","sources":["../../../src/lib/snapshot/targets.ts"],"names":[],"mappings":"AAeA,OAAO,EAAa,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AAGzD,KAAK,MAAM,GAAG,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;AAElC,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,oHAAoH;IACpH,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,MAAM;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,4FAA4F;IAC5F,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,WAAW,CAAC;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,gFAAgF;IAChF,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B;AAED,qFAAqF;AACrF,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAYjD;AAMD,kGAAkG;AAClG,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAgBhF;AAMD;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,QAAQ,GAAG,OAAO,CAAC,EACzC,SAAS,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,EACtC,MAAM,GAAE,WAAW,CAAC,MAAM,CAAa,GACtC,MAAM,EAAE,CAkBV;AAED,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CA6D5G"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
// `sdd-cli snapshot targets` — route each delta.yaml finding to the SDD
|
|
2
|
+
// artefacts it grounds, recording the GRAIN each route was found at:
|
|
3
|
+
//
|
|
4
|
+
// file — the artefact cites a changed file's path (feature-grounding style
|
|
5
|
+
// evidence citing `src/…`): the route is as precise as the citation;
|
|
6
|
+
// repo — the artefact only names the member's canonical_repo_key: the route
|
|
7
|
+
// reaches everything that repo grounds, and must not read as precise.
|
|
8
|
+
//
|
|
9
|
+
// Findings whose targets are already set are left alone (routing refined by
|
|
10
|
+
// hand is judgement). Findings nothing cites are listed as unroutable, never
|
|
11
|
+
// dropped. Writes back into delta.yaml preserving everything else in it.
|
|
12
|
+
import { readdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
13
|
+
import { join, relative, sep } from "node:path";
|
|
14
|
+
import { parseDocument } from "yaml";
|
|
15
|
+
import { deltaPath } from "./diff.js";
|
|
16
|
+
import { SnapshotError, exists } from "./manifest.js";
|
|
17
|
+
/** Minimal glob → RegExp: `**` any path, `*` within a segment, `?` one character. */
|
|
18
|
+
export function globToRegExp(glob) {
|
|
19
|
+
let re = "";
|
|
20
|
+
for (let i = 0; i < glob.length; i++) {
|
|
21
|
+
const c = glob[i];
|
|
22
|
+
if (c === "*" && glob[i + 1] === "*") {
|
|
23
|
+
re += glob[i + 2] === "/" ? "(?:.*/)?" : ".*";
|
|
24
|
+
i += glob[i + 2] === "/" ? 2 : 1;
|
|
25
|
+
}
|
|
26
|
+
else if (c === "*")
|
|
27
|
+
re += "[^/]*";
|
|
28
|
+
else if (c === "?")
|
|
29
|
+
re += "[^/]";
|
|
30
|
+
else
|
|
31
|
+
re += c.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
32
|
+
}
|
|
33
|
+
return new RegExp(`^${re}$`);
|
|
34
|
+
}
|
|
35
|
+
const TEXT = /\.(md|ya?ml|json|txt|adoc|mermaid|puml|csv)$/i;
|
|
36
|
+
const SKIP_DIRS = new Set([".git", "node_modules", ".sdd", "catalogues"]);
|
|
37
|
+
const MAX_BYTES = 4 * 1024 * 1024;
|
|
38
|
+
/** Every text artefact of the SDD, excluding the method's own copies and generated catalogues. */
|
|
39
|
+
export async function sddArtefacts(sddPath) {
|
|
40
|
+
const out = new Map();
|
|
41
|
+
async function walk(dir) {
|
|
42
|
+
for (const e of await readdir(dir, { withFileTypes: true })) {
|
|
43
|
+
const full = join(dir, e.name);
|
|
44
|
+
const rel = relative(sddPath, full).split(sep).join("/");
|
|
45
|
+
if (e.isDirectory()) {
|
|
46
|
+
if (SKIP_DIRS.has(e.name) || rel === "docs/method")
|
|
47
|
+
continue;
|
|
48
|
+
await walk(full);
|
|
49
|
+
}
|
|
50
|
+
else if (e.isFile() && TEXT.test(e.name) && (await stat(full)).size <= MAX_BYTES) {
|
|
51
|
+
out.set(rel, await readFile(full, "utf8"));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
await walk(sddPath);
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
58
|
+
// A path needs two segments to be a citation rather than a coincidence:
|
|
59
|
+
// `pom.xml` alone appears in every Java SDD.
|
|
60
|
+
const citable = (p) => p.includes("/");
|
|
61
|
+
/**
|
|
62
|
+
* `shared` holds paths that more than one member changed (`helm/values.yaml`,
|
|
63
|
+
* `src/main/resources/application.properties`): a citation of one of those names
|
|
64
|
+
* nobody in particular, so it is file grain only on a line that also names this
|
|
65
|
+
* member. Without that, a citation of another member's copy reads as precise.
|
|
66
|
+
*/
|
|
67
|
+
export function routeFinding(f, artefacts, shared = new Set()) {
|
|
68
|
+
const targets = new Map();
|
|
69
|
+
const paths = [...f.files.added, ...f.files.removed, ...f.files.modified].filter(citable);
|
|
70
|
+
// The key alone, or in export-folder form (`<key>-master@<rev>`): a hyphen may
|
|
71
|
+
// follow it only as a branch suffix, so `tcu` never matches inside `tcu-collector`.
|
|
72
|
+
const keyRe = new RegExp(`(^|[^A-Za-z0-9_-])${f.member.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(-(master|main|develop|trunk)@|[^A-Za-z0-9_-]|$)`);
|
|
73
|
+
const cites = (text, p) => shared.has(p) ? text.split("\n").some((line) => line.includes(p) && keyRe.test(line)) : text.includes(p);
|
|
74
|
+
for (const [rel, text] of artefacts) {
|
|
75
|
+
const hit = paths.find((p) => cites(text, p));
|
|
76
|
+
if (hit)
|
|
77
|
+
targets.set(rel, { artefact: rel, grain: "file", cited: hit });
|
|
78
|
+
}
|
|
79
|
+
for (const [rel, text] of artefacts) {
|
|
80
|
+
if (!targets.has(rel) && keyRe.test(text))
|
|
81
|
+
targets.set(rel, { artefact: rel, grain: "repo", cited: f.member });
|
|
82
|
+
}
|
|
83
|
+
return [...targets.values()].sort((a, b) => (a.grain === b.grain ? a.artefact.localeCompare(b.artefact) : a.grain === "file" ? -1 : 1));
|
|
84
|
+
}
|
|
85
|
+
export async function runSnapshotTargets(inputs, write) {
|
|
86
|
+
const dp = deltaPath(inputs.areaRoot, inputs.id);
|
|
87
|
+
if (!(await exists(dp))) {
|
|
88
|
+
write(`REFUSED: no ${dp} — run snapshot diff first\n`);
|
|
89
|
+
return { exitCode: 1 };
|
|
90
|
+
}
|
|
91
|
+
try {
|
|
92
|
+
const doc = parseDocument(await readFile(dp, "utf8"));
|
|
93
|
+
const findings = doc.toJS().findings ?? [];
|
|
94
|
+
const derivedRes = (inputs.derived ?? []).map(globToRegExp);
|
|
95
|
+
const kindOf = (artefact) => (derivedRes.some((r) => r.test(artefact)) ? "derived" : "spec");
|
|
96
|
+
const artefacts = await sddArtefacts(inputs.sddPath);
|
|
97
|
+
const owners = new Map();
|
|
98
|
+
for (const f of findings) {
|
|
99
|
+
for (const p of [...(f.files?.added ?? []), ...(f.files?.removed ?? []), ...(f.files?.modified ?? [])]) {
|
|
100
|
+
if (!owners.has(p))
|
|
101
|
+
owners.set(p, new Set());
|
|
102
|
+
owners.get(p).add(f.member);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const shared = new Set([...owners].filter(([, m]) => m.size > 1).map(([p]) => p));
|
|
106
|
+
let routed = 0;
|
|
107
|
+
let kept = 0;
|
|
108
|
+
const unroutable = [];
|
|
109
|
+
const grains = { file: 0, repo: 0, confirmed: 0 };
|
|
110
|
+
const kinds = { spec: 0, derived: 0 };
|
|
111
|
+
for (const [i, f] of findings.entries()) {
|
|
112
|
+
if (Array.isArray(f.targets) && f.targets.length > 0) {
|
|
113
|
+
kept++;
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
const t = routeFinding(f, artefacts, shared);
|
|
117
|
+
if (t.length === 0) {
|
|
118
|
+
unroutable.push(f.id);
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
for (const x of t) {
|
|
122
|
+
x.kind = kindOf(x.artefact);
|
|
123
|
+
grains[x.grain]++;
|
|
124
|
+
kinds[x.kind]++;
|
|
125
|
+
}
|
|
126
|
+
doc.setIn(["findings", i, "targets"], doc.createNode(t));
|
|
127
|
+
routed++;
|
|
128
|
+
}
|
|
129
|
+
await writeFile(dp, doc.toString({ lineWidth: 0 }));
|
|
130
|
+
write(`${routed} finding(s) routed (${grains.file} file-grain, ${grains.repo} repo-grain target(s)); ${kept} already targeted, left alone; ` +
|
|
131
|
+
`${unroutable.length} unroutable${unroutable.length ? `: ${unroutable.join(", ")}` : ""}\n` +
|
|
132
|
+
`targets by kind: ${kinds.spec} spec (re-derive by reading), ${kinds.derived} derived (regenerate)` +
|
|
133
|
+
`${(inputs.derived ?? []).length === 0 ? " — no --derived globs given, so every target is counted as a spec" : ""}\n`);
|
|
134
|
+
if (grains.repo > 0) {
|
|
135
|
+
write("note: a repo-grain target reaches everything that repo grounds — narrow it by hand before re-reversing\n");
|
|
136
|
+
}
|
|
137
|
+
return { exitCode: 0 };
|
|
138
|
+
}
|
|
139
|
+
catch (e) {
|
|
140
|
+
if (e instanceof SnapshotError) {
|
|
141
|
+
write(`REFUSED: ${e.message}\n`);
|
|
142
|
+
return { exitCode: 1 };
|
|
143
|
+
}
|
|
144
|
+
throw e;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=targets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"targets.js","sourceRoot":"","sources":["../../../src/lib/snapshot/targets.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
type Writer = (s: string) => void;
|
|
2
|
+
export interface Waiver {
|
|
3
|
+
who: string;
|
|
4
|
+
why: string;
|
|
5
|
+
date: string;
|
|
6
|
+
}
|
|
7
|
+
export interface VerifyInputs {
|
|
8
|
+
areaRoot: string;
|
|
9
|
+
id: string;
|
|
10
|
+
confirmed?: ReadonlyMap<string, string>;
|
|
11
|
+
waiver?: Partial<Waiver>;
|
|
12
|
+
today?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function runSnapshotVerify(inputs: VerifyInputs, write: Writer): Promise<{
|
|
15
|
+
exitCode: number;
|
|
16
|
+
}>;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=verify.d.ts.map
|