@rsaglobaltech/specgate 0.27.9 → 1.0.0-rc.1
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/CHANGELOG.md +36 -0
- package/dist/packages/core/src/application/ValidateChangeUseCase.js +19 -3
- package/dist/packages/core/src/application/ValidateChangeUseCase.js.map +1 -1
- package/dist/packages/core/src/domain/ApiContract.js +157 -0
- package/dist/packages/core/src/domain/ApiContract.js.map +1 -0
- package/dist/packages/core/src/domain/Approvals.js +127 -0
- package/dist/packages/core/src/domain/Approvals.js.map +1 -0
- package/dist/packages/core/src/domain/ChangeLayers.js +281 -0
- package/dist/packages/core/src/domain/ChangeLayers.js.map +1 -0
- package/dist/packages/core/src/domain/HarnessConfig.js.map +1 -1
- package/dist/packages/core/src/domain/HarnessGaps.js +182 -0
- package/dist/packages/core/src/domain/HarnessGaps.js.map +1 -0
- package/dist/packages/core/src/domain/HarnessReport.js +16 -1
- package/dist/packages/core/src/domain/HarnessReport.js.map +1 -1
- package/dist/packages/core/src/domain/HarnessRun.js.map +1 -1
- package/dist/packages/core/src/domain/Principles.js +119 -0
- package/dist/packages/core/src/domain/Principles.js.map +1 -0
- package/dist/packages/core/src/domain/RequirementGraph.js +12 -1
- package/dist/packages/core/src/domain/RequirementGraph.js.map +1 -1
- package/dist/packages/core/src/domain/Workspace.js +150 -0
- package/dist/packages/core/src/domain/Workspace.js.map +1 -0
- package/dist/packages/core/src/index.js +1 -0
- package/dist/packages/core/src/index.js.map +1 -1
- package/dist/packages/core/src/infrastructure/HarnessConfigFile.js +12 -0
- package/dist/packages/core/src/infrastructure/HarnessConfigFile.js.map +1 -1
- package/dist/packages/mcp-spec-driven/src/tools.js +18 -0
- package/dist/packages/mcp-spec-driven/src/tools.js.map +1 -1
- package/dist/scripts/alm/cli.js +45 -4
- package/dist/scripts/alm/cli.js.map +1 -1
- package/dist/scripts/alm/clients.js +3 -1
- package/dist/scripts/alm/clients.js.map +1 -1
- package/dist/scripts/alm/phases.js +279 -0
- package/dist/scripts/alm/phases.js.map +1 -0
- package/dist/scripts/alm/port.js +33 -5
- package/dist/scripts/alm/port.js.map +1 -1
- package/dist/scripts/alm/providers/azure.js +72 -11
- package/dist/scripts/alm/providers/azure.js.map +1 -1
- package/dist/scripts/alm/providers/github.js +67 -7
- package/dist/scripts/alm/providers/github.js.map +1 -1
- package/dist/scripts/alm/providers/index.js +8 -2
- package/dist/scripts/alm/providers/index.js.map +1 -1
- package/dist/scripts/alm/providers/jira.js +86 -8
- package/dist/scripts/alm/providers/jira.js.map +1 -1
- package/dist/scripts/alm/providers/linear.js +167 -0
- package/dist/scripts/alm/providers/linear.js.map +1 -0
- package/dist/scripts/change/artifacts.js +15 -1
- package/dist/scripts/change/artifacts.js.map +1 -1
- package/dist/scripts/change/instructions.js +39 -5
- package/dist/scripts/change/instructions.js.map +1 -1
- package/dist/scripts/cli/commands/alm/PhaseCommand.js +153 -0
- package/dist/scripts/cli/commands/alm/PhaseCommand.js.map +1 -0
- package/dist/scripts/cli/commands/alm/PullCommand.js +33 -2
- package/dist/scripts/cli/commands/alm/PullCommand.js.map +1 -1
- package/dist/scripts/cli/commands/alm/pull-back.js +104 -0
- package/dist/scripts/cli/commands/alm/pull-back.js.map +1 -0
- package/dist/scripts/cli/commands/change/ChangeCommand.js +92 -14
- package/dist/scripts/cli/commands/change/ChangeCommand.js.map +1 -1
- package/dist/scripts/cli/commands/change/TicketCommand.js +20 -7
- package/dist/scripts/cli/commands/change/TicketCommand.js.map +1 -1
- package/dist/scripts/cli/commands/harness/RunCommand.js +64 -20
- package/dist/scripts/cli/commands/harness/RunCommand.js.map +1 -1
- package/dist/scripts/cli/commands/project/AdoptCommand.js +44 -4
- package/dist/scripts/cli/commands/project/AdoptCommand.js.map +1 -1
- package/dist/scripts/cli/commands/project/MigrateCommand.js +166 -0
- package/dist/scripts/cli/commands/project/MigrateCommand.js.map +1 -0
- package/dist/scripts/cli/commands/project/OnboardCommand.js +23 -5
- package/dist/scripts/cli/commands/project/OnboardCommand.js.map +1 -1
- package/dist/scripts/cli/commands/quality/CheckCommand.js +25 -0
- package/dist/scripts/cli/commands/quality/CheckCommand.js.map +1 -1
- package/dist/scripts/cli/commands/quality/ValidateSpecsCommand.js +15 -0
- package/dist/scripts/cli/commands/quality/ValidateSpecsCommand.js.map +1 -1
- package/dist/scripts/cli/commands/spec/ContractCommand.js +117 -0
- package/dist/scripts/cli/commands/spec/ContractCommand.js.map +1 -0
- package/dist/scripts/cli/commands/spec/DraftCommand.js +22 -8
- package/dist/scripts/cli/commands/spec/DraftCommand.js.map +1 -1
- package/dist/scripts/cli/commands/spec/DriftCommand.js +128 -0
- package/dist/scripts/cli/commands/spec/DriftCommand.js.map +1 -0
- package/dist/scripts/cli/commands/spec/StatusCommand.js +12 -0
- package/dist/scripts/cli/commands/spec/StatusCommand.js.map +1 -1
- package/dist/scripts/cli/commands/spec/StudioCommand.js +43 -1
- package/dist/scripts/cli/commands/spec/StudioCommand.js.map +1 -1
- package/dist/scripts/cli/commands/workspace/WorkspaceCommand.js +485 -0
- package/dist/scripts/cli/commands/workspace/WorkspaceCommand.js.map +1 -0
- package/dist/scripts/contract.js +10 -0
- package/dist/scripts/contract.js.map +1 -0
- package/dist/scripts/docs/nav.js +16 -1
- package/dist/scripts/docs/nav.js.map +1 -1
- package/dist/scripts/draft/drafting-guide.js +6 -0
- package/dist/scripts/draft/drafting-guide.js.map +1 -1
- package/dist/scripts/draft/ticket-guide.js +5 -0
- package/dist/scripts/draft/ticket-guide.js.map +1 -1
- package/dist/scripts/drift.js +10 -0
- package/dist/scripts/drift.js.map +1 -0
- package/dist/scripts/harness/gap-evidence.js +149 -0
- package/dist/scripts/harness/gap-evidence.js.map +1 -0
- package/dist/scripts/harness/prompt.js +5 -1
- package/dist/scripts/harness/prompt.js.map +1 -1
- package/dist/scripts/harness/report.js +104 -5
- package/dist/scripts/harness/report.js.map +1 -1
- package/dist/scripts/lib/approvals.js +243 -0
- package/dist/scripts/lib/approvals.js.map +1 -0
- package/dist/scripts/lib/change-review.js +19 -11
- package/dist/scripts/lib/change-review.js.map +1 -1
- package/dist/scripts/lib/contracts.js +211 -0
- package/dist/scripts/lib/contracts.js.map +1 -0
- package/dist/scripts/lib/drift.js +80 -0
- package/dist/scripts/lib/drift.js.map +1 -0
- package/dist/scripts/lib/live-model.js +1 -0
- package/dist/scripts/lib/live-model.js.map +1 -1
- package/dist/scripts/lib/migrate.js +264 -0
- package/dist/scripts/lib/migrate.js.map +1 -0
- package/dist/scripts/lib/role-packages.js +230 -0
- package/dist/scripts/lib/role-packages.js.map +1 -0
- package/dist/scripts/lib/steering.js +180 -0
- package/dist/scripts/lib/steering.js.map +1 -0
- package/dist/scripts/lib/studio-app-page.js +28 -5
- package/dist/scripts/lib/studio-app-page.js.map +1 -1
- package/dist/scripts/lib/studio-app.js +29 -0
- package/dist/scripts/lib/studio-app.js.map +1 -1
- package/dist/scripts/lib/studio-route.js +20 -0
- package/dist/scripts/lib/studio-route.js.map +1 -1
- package/dist/scripts/lib/surface.js +55 -0
- package/dist/scripts/lib/surface.js.map +1 -1
- package/dist/scripts/lib/workspace-live-page.js +90 -0
- package/dist/scripts/lib/workspace-live-page.js.map +1 -0
- package/dist/scripts/lib/workspace-live.js +216 -0
- package/dist/scripts/lib/workspace-live.js.map +1 -0
- package/dist/scripts/lib/workspace.js +406 -0
- package/dist/scripts/lib/workspace.js.map +1 -0
- package/dist/scripts/migrate.js +10 -0
- package/dist/scripts/migrate.js.map +1 -0
- package/dist/scripts/schema/registry.js +12 -0
- package/dist/scripts/schema/registry.js.map +1 -1
- package/dist/scripts/workspace.js +10 -0
- package/dist/scripts/workspace.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.APPROVALS_FILE = void 0;
|
|
37
|
+
exports.approvalSettings = approvalSettings;
|
|
38
|
+
exports.gitIdentity = gitIdentity;
|
|
39
|
+
exports.changeSchema = changeSchema;
|
|
40
|
+
exports.readRecords = readRecords;
|
|
41
|
+
exports.changeApprovals = changeApprovals;
|
|
42
|
+
exports.approveLayers = approveLayers;
|
|
43
|
+
exports.missingApprovals = missingApprovals;
|
|
44
|
+
const fs = __importStar(require("node:fs"));
|
|
45
|
+
const path = __importStar(require("node:path"));
|
|
46
|
+
const node_child_process_1 = require("node:child_process");
|
|
47
|
+
const YamlLite_1 = require("../../packages/core/src/domain/YamlLite");
|
|
48
|
+
const ChangeLayers_1 = require("../../packages/core/src/domain/ChangeLayers");
|
|
49
|
+
const Approvals_1 = require("../../packages/core/src/domain/Approvals");
|
|
50
|
+
/**
|
|
51
|
+
* The project side of roles and approvals (REQ-310..315, ADR-0043): the
|
|
52
|
+
* settings in `harness.config.yaml`, the git identity of whoever approves, and
|
|
53
|
+
* `approvals.json` in the change folder — which moves to the archive with it.
|
|
54
|
+
*/
|
|
55
|
+
exports.APPROVALS_FILE = "approvals.json";
|
|
56
|
+
const changeDir = (projectDir, id) => path.join(projectDir, "docs", "specs", "changes", id);
|
|
57
|
+
function read(file) {
|
|
58
|
+
try {
|
|
59
|
+
return fs.readFileSync(file, "utf8");
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/** `roles:` and `approvals:` of `harness.config.yaml`; the defaults without one. */
|
|
66
|
+
function approvalSettings(projectDir) {
|
|
67
|
+
const text = read(path.join(projectDir, "harness.config.yaml"));
|
|
68
|
+
const parsed = text ? (0, YamlLite_1.parseYamlLite)(text) : {};
|
|
69
|
+
return (0, Approvals_1.readApprovalSettings)(parsed && typeof parsed === "object" && !Array.isArray(parsed)
|
|
70
|
+
? parsed
|
|
71
|
+
: {});
|
|
72
|
+
}
|
|
73
|
+
/** Who runs the command, as git knows them in this project. */
|
|
74
|
+
function gitIdentity(projectDir) {
|
|
75
|
+
const get = (key) => ((0, node_child_process_1.spawnSync)("git", ["config", key], { cwd: projectDir, encoding: "utf8" }).stdout || "").trim();
|
|
76
|
+
return { name: get("user.name"), email: get("user.email") };
|
|
77
|
+
}
|
|
78
|
+
/** The change's schema: `layered` from 1.0 on, `spec-driven` for a 0.27 change. */
|
|
79
|
+
function changeSchema(projectDir, id) {
|
|
80
|
+
const yaml = read(path.join(changeDir(projectDir, id), "change.yaml")) || "";
|
|
81
|
+
return (/^schema:\s*(\S+)/m.exec(yaml) || [])[1] || "spec-driven";
|
|
82
|
+
}
|
|
83
|
+
/** Each layer and its text, or null when it is missing or still as scaffolded. */
|
|
84
|
+
function layerTexts(projectDir, id) {
|
|
85
|
+
const dir = changeDir(projectDir, id);
|
|
86
|
+
return ChangeLayers_1.LAYERS.map((l) => {
|
|
87
|
+
const file = l.id === "discover" && !fs.existsSync(path.join(dir, l.file)) ? ChangeLayers_1.LEGACY_DISCOVER : l.file;
|
|
88
|
+
const text = read(path.join(dir, file));
|
|
89
|
+
const written = text !== null && !(0, ChangeLayers_1.isUntouchedLayer)(l.id, text, id);
|
|
90
|
+
return { id: l.id, owner: l.owner, file, text: written ? text : null };
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
function readRecords(projectDir, id) {
|
|
94
|
+
const text = read(path.join(changeDir(projectDir, id), exports.APPROVALS_FILE));
|
|
95
|
+
if (!text)
|
|
96
|
+
return [];
|
|
97
|
+
try {
|
|
98
|
+
const parsed = JSON.parse(text);
|
|
99
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
return [];
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function changeApprovals(projectDir, id) {
|
|
106
|
+
const settings = approvalSettings(projectDir);
|
|
107
|
+
const records = readRecords(projectDir, id);
|
|
108
|
+
const layers = (0, Approvals_1.layerApprovals)(layerTexts(projectDir, id), records, settings);
|
|
109
|
+
const schema = changeSchema(projectDir, id);
|
|
110
|
+
// A change with none of its layers written — a delta and nothing else — is
|
|
111
|
+
// approved as 0.27 approved it: by the `approved:` line `change approve` writes.
|
|
112
|
+
const line = approvedLine(projectDir, id);
|
|
113
|
+
const anyWritten = layers.some((l) => l.present);
|
|
114
|
+
const approved = anyWritten ? (0, Approvals_1.changeApproved)(layers) : Boolean(line);
|
|
115
|
+
const dates = layers.flatMap((l) => l.approvals.map((a) => a.at)).sort();
|
|
116
|
+
return {
|
|
117
|
+
change: id,
|
|
118
|
+
schema,
|
|
119
|
+
required: (0, Approvals_1.approvalsRequired)(schema, settings),
|
|
120
|
+
layers,
|
|
121
|
+
approved,
|
|
122
|
+
approvedAt: !approved ? "" : anyWritten ? dates[dates.length - 1] || "" : line,
|
|
123
|
+
recorded: records.length > 0,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/** The date on the `approved:` line of `change.yaml`, or "". */
|
|
127
|
+
function approvedLine(projectDir, id) {
|
|
128
|
+
const yaml = read(path.join(changeDir(projectDir, id), "change.yaml")) || "";
|
|
129
|
+
return (/^approved:\s*(\S+)/m.exec(yaml) || [])[1] || "";
|
|
130
|
+
}
|
|
131
|
+
/** Keep `approved:` in `change.yaml` in step with the approvals: written once all are in. */
|
|
132
|
+
function syncApprovedLine(projectDir, id, date) {
|
|
133
|
+
const file = path.join(changeDir(projectDir, id), "change.yaml");
|
|
134
|
+
const yaml = read(file) || "";
|
|
135
|
+
const without = yaml.replace(/^approved:.*\n?/m, "");
|
|
136
|
+
const next = date ? `${without.replace(/\n*$/, "\n")}approved: ${date}\n` : without;
|
|
137
|
+
if (next !== yaml)
|
|
138
|
+
fs.writeFileSync(file, next, "utf8");
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Record the person's approval of the given layers — or, with `null`, of every
|
|
142
|
+
* written layer they own (REQ-311). Refuses a layer that is not written or
|
|
143
|
+
* whose owning role the person does not hold, naming the role and its people.
|
|
144
|
+
*/
|
|
145
|
+
function approveLayers(projectDir, id, layers, today, who = gitIdentity(projectDir)) {
|
|
146
|
+
if (!fs.existsSync(changeDir(projectDir, id))) {
|
|
147
|
+
return { ok: false, code: "change_not_found", message: `No open change ${id}.` };
|
|
148
|
+
}
|
|
149
|
+
const settings = approvalSettings(projectDir);
|
|
150
|
+
const texts = layerTexts(projectDir, id);
|
|
151
|
+
const present = texts.filter((t) => t.text !== null);
|
|
152
|
+
const person = who.email || who.name || "this git identity";
|
|
153
|
+
const ownerOf = (owner) => {
|
|
154
|
+
const people = settings.roles[owner] || [];
|
|
155
|
+
return `the ${owner} role${people.length ? ` (${people.join(", ")})` : ""}`;
|
|
156
|
+
};
|
|
157
|
+
let targets;
|
|
158
|
+
if (layers) {
|
|
159
|
+
targets = [];
|
|
160
|
+
for (const l of layers) {
|
|
161
|
+
const t = texts.find((x) => x.id === l);
|
|
162
|
+
if (!t) {
|
|
163
|
+
return {
|
|
164
|
+
ok: false,
|
|
165
|
+
code: "approve_unknown_layer",
|
|
166
|
+
message: `${l} is not a layer: discover, design or tasks.`,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
if (t.text === null) {
|
|
170
|
+
return {
|
|
171
|
+
ok: false,
|
|
172
|
+
code: "approve_layer_missing",
|
|
173
|
+
message: `${id} has no ${t.file} written yet: there is nothing of the ${l} to approve.`,
|
|
174
|
+
fix: `Write ${t.file}, then approve it.`,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
if (!(0, Approvals_1.holdsRole)(settings, t.owner, who)) {
|
|
178
|
+
return {
|
|
179
|
+
ok: false,
|
|
180
|
+
code: "approve_not_owner",
|
|
181
|
+
message: `${person} cannot approve the ${l} of ${id}: it belongs to ${ownerOf(t.owner)}.`,
|
|
182
|
+
fix: `Have someone in the ${t.owner} role run specgate change approve ${id} --layer ${l}, or name ${person} under roles.${t.owner} in harness.config.yaml.`,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
targets.push(t);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
targets = present.filter((t) => (0, Approvals_1.holdsRole)(settings, t.owner, who));
|
|
190
|
+
if (present.length > 0 && targets.length === 0) {
|
|
191
|
+
return {
|
|
192
|
+
ok: false,
|
|
193
|
+
code: "approve_not_owner",
|
|
194
|
+
message: `${person} holds none of the roles that own the layers of ${id}: ${present
|
|
195
|
+
.map((t) => `${t.id} → ${t.owner}`)
|
|
196
|
+
.join(", ")}.`,
|
|
197
|
+
fix: "Name them under roles: in harness.config.yaml, or have the owners approve.",
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
const records = readRecords(projectDir, id);
|
|
202
|
+
for (const t of targets) {
|
|
203
|
+
const hash = (0, Approvals_1.contentHash)(t.text);
|
|
204
|
+
const key = (who.email || who.name).toLowerCase();
|
|
205
|
+
const already = records.some((r) => r.layer === t.id && r.hash === hash && (r.by.email || r.by.name).toLowerCase() === key);
|
|
206
|
+
if (!already)
|
|
207
|
+
records.push({ layer: t.id, by: who, role: t.owner, hash, at: today });
|
|
208
|
+
}
|
|
209
|
+
if (targets.length > 0) {
|
|
210
|
+
fs.writeFileSync(path.join(changeDir(projectDir, id), exports.APPROVALS_FILE), `${JSON.stringify(records, null, 2)}\n`, "utf8");
|
|
211
|
+
}
|
|
212
|
+
const after = changeApprovals(projectDir, id);
|
|
213
|
+
// A 0.27 change with none of the layers written is approved as 0.27 did it.
|
|
214
|
+
const date = present.length === 0 ? today : after.approvedAt;
|
|
215
|
+
syncApprovedLine(projectDir, id, date);
|
|
216
|
+
return {
|
|
217
|
+
ok: true,
|
|
218
|
+
change: id,
|
|
219
|
+
approved: date,
|
|
220
|
+
layers: targets.map((t) => t.id),
|
|
221
|
+
pending: after.layers.filter((l) => l.present && !l.approved).map((l) => l.layer),
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
/** Why the harness must not build the change yet, or null when it may (REQ-315). */
|
|
225
|
+
function missingApprovals(projectDir, id) {
|
|
226
|
+
const state = changeApprovals(projectDir, id);
|
|
227
|
+
if (!state.required || state.approved)
|
|
228
|
+
return null;
|
|
229
|
+
const waiting = state.layers.filter((l) => l.present && !l.approved);
|
|
230
|
+
const what = waiting.length
|
|
231
|
+
? waiting
|
|
232
|
+
.map((l) => `${l.layer} (${l.approvals.length} of ${l.quorum} approval(s), by the ${l.owner} role)`)
|
|
233
|
+
.join(", ")
|
|
234
|
+
: "nobody approved it";
|
|
235
|
+
const layer = waiting[0];
|
|
236
|
+
return {
|
|
237
|
+
message: `${id} is not approved: ${what}.`,
|
|
238
|
+
fix: layer
|
|
239
|
+
? `specgate change approve ${id} --layer ${layer.layer}, by the ${layer.owner} role — or approvals: { required: never } in harness.config.yaml for the 0.27 behaviour.`
|
|
240
|
+
: `specgate change approve ${id} — or approvals: { required: never } in harness.config.yaml for the 0.27 behaviour.`,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
//# sourceMappingURL=approvals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"approvals.js","sourceRoot":"","sources":["../../../scripts/lib/approvals.ts"],"names":[],"mappings":"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"}
|
|
@@ -42,6 +42,7 @@ const fs = __importStar(require("node:fs"));
|
|
|
42
42
|
const path = __importStar(require("node:path"));
|
|
43
43
|
const Clarification_1 = require("../../packages/core/src/domain/Clarification");
|
|
44
44
|
const DraftCommand_1 = require("../cli/commands/spec/DraftCommand");
|
|
45
|
+
const approvals_1 = require("./approvals");
|
|
45
46
|
/**
|
|
46
47
|
* A person's review of a draft change (REQ-206, REQ-207): approving it, which
|
|
47
48
|
* Build waits for, and asking for a change in their own words.
|
|
@@ -58,10 +59,19 @@ function read(file) {
|
|
|
58
59
|
return undefined;
|
|
59
60
|
}
|
|
60
61
|
}
|
|
61
|
-
/**
|
|
62
|
+
/**
|
|
63
|
+
* When the change was approved, or "" while it is not. A 1.0 change, and any
|
|
64
|
+
* change with recorded approvals, is approved only while every written layer's
|
|
65
|
+
* approvals match its text (REQ-314); a 0.27 change without any reads the
|
|
66
|
+
* `approved:` line it always had.
|
|
67
|
+
*/
|
|
62
68
|
function approvedOn(projectDir, id) {
|
|
63
69
|
const yaml = read(path.join(changeDir(projectDir, id), "change.yaml")) || "";
|
|
64
|
-
|
|
70
|
+
const line = (/^approved:\s*(\S+)/m.exec(yaml) || [])[1] || "";
|
|
71
|
+
const state = (0, approvals_1.changeApprovals)(projectDir, id);
|
|
72
|
+
if (state.schema === "layered" || state.recorded)
|
|
73
|
+
return state.approved ? state.approvedAt : "";
|
|
74
|
+
return line;
|
|
65
75
|
}
|
|
66
76
|
/** What stops a change from being approved: checklist errors and open questions. */
|
|
67
77
|
function approvalBlockers(projectDir, id) {
|
|
@@ -84,9 +94,12 @@ function approvalBlockers(projectDir, id) {
|
|
|
84
94
|
}
|
|
85
95
|
return out;
|
|
86
96
|
}
|
|
87
|
-
/**
|
|
88
|
-
|
|
89
|
-
|
|
97
|
+
/**
|
|
98
|
+
* Record that a person approved the change (REQ-206): the layers they own, or
|
|
99
|
+
* the one named (REQ-311). `approved` is the date once every layer is in, ""
|
|
100
|
+
* while some still wait.
|
|
101
|
+
*/
|
|
102
|
+
function approveChange(projectDir, id, today, layer) {
|
|
90
103
|
if (!fs.existsSync(changeDir(projectDir, id))) {
|
|
91
104
|
return { ok: false, code: "change_not_found", message: `No open change ${id}.` };
|
|
92
105
|
}
|
|
@@ -99,12 +112,7 @@ function approveChange(projectDir, id, today) {
|
|
|
99
112
|
blockers,
|
|
100
113
|
};
|
|
101
114
|
}
|
|
102
|
-
|
|
103
|
-
const next = /^approved:/m.test(yaml)
|
|
104
|
-
? yaml.replace(/^approved:.*$/m, `approved: ${today}`)
|
|
105
|
-
: `${yaml.replace(/\n*$/, "\n")}approved: ${today}\n`;
|
|
106
|
-
fs.writeFileSync(file, next, "utf8");
|
|
107
|
-
return { ok: true, change: id, approved: today };
|
|
115
|
+
return (0, approvals_1.approveLayers)(projectDir, id, layer ? [layer] : null, today);
|
|
108
116
|
}
|
|
109
117
|
const NOTES_HEADER = "| Date | Requirement | Request |";
|
|
110
118
|
function cell(text) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"change-review.js","sourceRoot":"","sources":["../../../scripts/lib/change-review.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"change-review.js","sourceRoot":"","sources":["../../../scripts/lib/change-review.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The project's interface contracts and the requirements that cite them
|
|
4
|
+
* (REQ-335, REQ-336).
|
|
5
|
+
*
|
|
6
|
+
* A contract is an OpenAPI or AsyncAPI document anywhere in the project, or
|
|
7
|
+
* any file an `api=` reference names. A reference is read off the
|
|
8
|
+
* `specgate:trace` comment of a requirement in spec.md or a capability spec.
|
|
9
|
+
*/
|
|
10
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
13
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
14
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
15
|
+
}
|
|
16
|
+
Object.defineProperty(o, k2, desc);
|
|
17
|
+
}) : (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
o[k2] = m[k];
|
|
20
|
+
}));
|
|
21
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
22
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
23
|
+
}) : function(o, v) {
|
|
24
|
+
o["default"] = v;
|
|
25
|
+
});
|
|
26
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
27
|
+
var ownKeys = function(o) {
|
|
28
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
29
|
+
var ar = [];
|
|
30
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
31
|
+
return ar;
|
|
32
|
+
};
|
|
33
|
+
return ownKeys(o);
|
|
34
|
+
};
|
|
35
|
+
return function (mod) {
|
|
36
|
+
if (mod && mod.__esModule) return mod;
|
|
37
|
+
var result = {};
|
|
38
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
39
|
+
__setModuleDefault(result, mod);
|
|
40
|
+
return result;
|
|
41
|
+
};
|
|
42
|
+
})();
|
|
43
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
exports.apiCitations = apiCitations;
|
|
45
|
+
exports.projectContracts = projectContracts;
|
|
46
|
+
exports.apiReferenceProblems = apiReferenceProblems;
|
|
47
|
+
exports.contractReport = contractReport;
|
|
48
|
+
const fs = __importStar(require("node:fs"));
|
|
49
|
+
const path = __importStar(require("node:path"));
|
|
50
|
+
const ApiContract_1 = require("../../packages/core/src/domain/ApiContract");
|
|
51
|
+
const SpecParser_1 = require("../../packages/core/src/domain/SpecParser");
|
|
52
|
+
const ChangeWorkspace_1 = require("../../packages/core/src/infrastructure/ChangeWorkspace");
|
|
53
|
+
const diagnostics_1 = require("./diagnostics");
|
|
54
|
+
const SKIP = new Set([
|
|
55
|
+
".git",
|
|
56
|
+
"node_modules",
|
|
57
|
+
"dist",
|
|
58
|
+
"target",
|
|
59
|
+
"build",
|
|
60
|
+
".next",
|
|
61
|
+
"coverage",
|
|
62
|
+
".harness",
|
|
63
|
+
]);
|
|
64
|
+
const CANDIDATE = /\.(ya?ml|json)$/i;
|
|
65
|
+
/** Every requirement's `api=` references, from spec.md and the capability specs. */
|
|
66
|
+
function apiCitations(projectDir) {
|
|
67
|
+
const files = [path.join(projectDir, "spec.md")];
|
|
68
|
+
const caps = path.join(projectDir, ChangeWorkspace_1.CAPABILITIES_DIR);
|
|
69
|
+
if (fs.existsSync(caps)) {
|
|
70
|
+
for (const e of fs.readdirSync(caps, { withFileTypes: true })) {
|
|
71
|
+
if (e.isDirectory())
|
|
72
|
+
files.push(path.join(caps, e.name, "spec.md"));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const out = [];
|
|
76
|
+
for (const f of files) {
|
|
77
|
+
if (!fs.existsSync(f))
|
|
78
|
+
continue;
|
|
79
|
+
let requirement = "";
|
|
80
|
+
const lines = fs.readFileSync(f, "utf8").split(/\r?\n/);
|
|
81
|
+
for (let i = 0; i < lines.length; i++) {
|
|
82
|
+
const h = /^#{2,4}\s+(?:Requirement:\s*)?(REQ-\d+)\b/.exec(lines[i]);
|
|
83
|
+
if (h) {
|
|
84
|
+
requirement = h[1];
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (!requirement || !/<!--\s*specgate:trace\b/.test(lines[i]))
|
|
88
|
+
continue;
|
|
89
|
+
let comment = lines[i];
|
|
90
|
+
while (!comment.includes("-->") && i + 1 < lines.length)
|
|
91
|
+
comment += `\n${lines[++i]}`;
|
|
92
|
+
const api = (0, SpecParser_1.parseTraceComment)(comment).api;
|
|
93
|
+
if (!api)
|
|
94
|
+
continue;
|
|
95
|
+
for (const ref of api
|
|
96
|
+
.split(",")
|
|
97
|
+
.map((s) => s.trim())
|
|
98
|
+
.filter(Boolean)) {
|
|
99
|
+
out.push({ requirement, ref });
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return out;
|
|
104
|
+
}
|
|
105
|
+
/** The contracts: every OpenAPI/AsyncAPI file found, plus those cited by path. */
|
|
106
|
+
function projectContracts(projectDir, cited = apiCitations(projectDir)) {
|
|
107
|
+
const found = {};
|
|
108
|
+
const read = (rel) => {
|
|
109
|
+
const abs = path.join(projectDir, rel);
|
|
110
|
+
let text;
|
|
111
|
+
try {
|
|
112
|
+
text = fs.readFileSync(abs, "utf8");
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
if (!(0, ApiContract_1.contractKind)(text))
|
|
118
|
+
return;
|
|
119
|
+
found[rel.replace(/\\/g, "/")] = (0, ApiContract_1.contractOperations)(text, rel);
|
|
120
|
+
};
|
|
121
|
+
const walk = (rel, depth) => {
|
|
122
|
+
if (depth > 6)
|
|
123
|
+
return;
|
|
124
|
+
let entries;
|
|
125
|
+
try {
|
|
126
|
+
entries = fs.readdirSync(path.join(projectDir, rel), { withFileTypes: true });
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
for (const e of entries) {
|
|
132
|
+
if (SKIP.has(e.name) || e.name.startsWith("."))
|
|
133
|
+
continue;
|
|
134
|
+
const p = rel ? `${rel}/${e.name}` : e.name;
|
|
135
|
+
if (e.isDirectory())
|
|
136
|
+
walk(p, depth + 1);
|
|
137
|
+
else if (CANDIDATE.test(e.name) && /openapi|asyncapi|swagger|contract|api/i.test(p))
|
|
138
|
+
read(p);
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
walk("", 0);
|
|
142
|
+
for (const c of cited) {
|
|
143
|
+
const { file } = (0, ApiContract_1.parseApiRef)(c.ref);
|
|
144
|
+
const norm = file.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
145
|
+
if (norm && !found[norm] && fs.existsSync(path.join(projectDir, norm)))
|
|
146
|
+
read(norm);
|
|
147
|
+
}
|
|
148
|
+
return found;
|
|
149
|
+
}
|
|
150
|
+
/** `validate`'s findings: each reference that does not resolve (REQ-335). */
|
|
151
|
+
function apiReferenceProblems(projectDir) {
|
|
152
|
+
const cited = apiCitations(projectDir);
|
|
153
|
+
if (cited.length === 0)
|
|
154
|
+
return [];
|
|
155
|
+
const contracts = projectContracts(projectDir, cited);
|
|
156
|
+
const problems = [];
|
|
157
|
+
for (const c of cited) {
|
|
158
|
+
const r = (0, ApiContract_1.resolveApiRef)(c.ref, contracts);
|
|
159
|
+
if (r.ok)
|
|
160
|
+
continue;
|
|
161
|
+
problems.push(r.reason === "contract_missing"
|
|
162
|
+
? (0, diagnostics_1.error)("api_contract_missing", `${c.requirement} cites api=${c.ref}, and ${r.file} is not a contract in this project.`, {
|
|
163
|
+
target: c.requirement,
|
|
164
|
+
fix: `Correct the path in ${c.requirement}'s specgate:trace comment, or add the contract.`,
|
|
165
|
+
})
|
|
166
|
+
: (0, diagnostics_1.error)("api_operation_missing", `${c.requirement} cites api=${c.ref}, which is not an operation of ${r.file || "any contract in this project"}.`, {
|
|
167
|
+
target: c.requirement,
|
|
168
|
+
fix: `Correct the operation in ${c.requirement}'s specgate:trace comment, or add it to the contract.`,
|
|
169
|
+
}));
|
|
170
|
+
}
|
|
171
|
+
return problems;
|
|
172
|
+
}
|
|
173
|
+
/** `specgate contract check` (REQ-336). */
|
|
174
|
+
function contractReport(projectDir) {
|
|
175
|
+
const cited = apiCitations(projectDir);
|
|
176
|
+
const contracts = projectContracts(projectDir, cited);
|
|
177
|
+
const status = apiReferenceProblems(projectDir);
|
|
178
|
+
const citedBy = new Map();
|
|
179
|
+
for (const c of cited) {
|
|
180
|
+
const r = (0, ApiContract_1.resolveApiRef)(c.ref, contracts);
|
|
181
|
+
if (!r.ok)
|
|
182
|
+
continue;
|
|
183
|
+
const key = `${r.file}#${r.operation.pointer}`;
|
|
184
|
+
citedBy.set(key, [...(citedBy.get(key) || []), c.requirement]);
|
|
185
|
+
}
|
|
186
|
+
const report = { contracts: [] };
|
|
187
|
+
for (const [file, ops] of Object.entries(contracts).sort(([a], [b]) => a.localeCompare(b))) {
|
|
188
|
+
const entry = {
|
|
189
|
+
file,
|
|
190
|
+
kind: ops[0]?.kind || "",
|
|
191
|
+
operations: ops.length,
|
|
192
|
+
cited: [],
|
|
193
|
+
uncited: [],
|
|
194
|
+
};
|
|
195
|
+
for (const op of ops) {
|
|
196
|
+
const by = citedBy.get(`${file}#${op.pointer}`);
|
|
197
|
+
if (by)
|
|
198
|
+
entry.cited.push(`${op.label} — ${[...new Set(by)].join(", ")}`);
|
|
199
|
+
else {
|
|
200
|
+
entry.uncited.push(op.label);
|
|
201
|
+
status.push((0, diagnostics_1.warning)("api_operation_uncited", `${file}: ${op.label} is cited by no requirement.`, {
|
|
202
|
+
target: op.operationId || op.pointer,
|
|
203
|
+
fix: `Specify it: a requirement whose specgate:trace says api=${file}#${op.operationId || op.pointer}.`,
|
|
204
|
+
}));
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
report.contracts.push(entry);
|
|
208
|
+
}
|
|
209
|
+
return { report, status };
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=contracts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contracts.js","sourceRoot":"","sources":["../../../scripts/lib/contracts.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCH,oCAiCC;AAGD,4CAsCC;AAGD,oDA6BC;AAaD,wCAuCC;AA7LD,4CAA8B;AAC9B,gDAAkC;AAClC,4EAMoD;AACpD,0EAA8E;AAC9E,4FAA0F;AAC1F,+CAAgE;AAOhE,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC;IACnB,MAAM;IACN,cAAc;IACd,MAAM;IACN,QAAQ;IACR,OAAO;IACP,OAAO;IACP,UAAU;IACV,UAAU;CACX,CAAC,CAAC;AACH,MAAM,SAAS,GAAG,kBAAkB,CAAC;AAErC,oFAAoF;AACpF,SAAgB,YAAY,CAAC,UAAkB;IAC7C,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC;IACjD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,kCAAgB,CAAC,CAAC;IACrD,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;YAC9D,IAAI,CAAC,CAAC,WAAW,EAAE;gBAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;QACtE,CAAC;IACH,CAAC;IACD,MAAM,GAAG,GAAkB,EAAE,CAAC;IAC9B,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;YAAE,SAAS;QAChC,IAAI,WAAW,GAAG,EAAE,CAAC;QACrB,MAAM,KAAK,GAAG,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACxD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,MAAM,CAAC,GAAG,2CAA2C,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YACrE,IAAI,CAAC,EAAE,CAAC;gBACN,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;gBACnB,SAAS;YACX,CAAC;YACD,IAAI,CAAC,WAAW,IAAI,CAAC,yBAAyB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;gBAAE,SAAS;YACxE,IAAI,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YACvB,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM;gBAAE,OAAO,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YACtF,MAAM,GAAG,GAAG,IAAA,8BAAiB,EAAC,OAAO,CAAC,CAAC,GAAG,CAAC;YAC3C,IAAI,CAAC,GAAG;gBAAE,SAAS;YACnB,KAAK,MAAM,GAAG,IAAI,GAAG;iBAClB,KAAK,CAAC,GAAG,CAAC;iBACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;iBACpB,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;gBACnB,GAAG,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC;YACjC,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,kFAAkF;AAClF,SAAgB,gBAAgB,CAC9B,UAAkB,EAClB,QAAuB,YAAY,CAAC,UAAU,CAAC;IAE/C,MAAM,KAAK,GAAmC,EAAE,CAAC;IACjD,MAAM,IAAI,GAAG,CAAC,GAAW,EAAE,EAAE;QAC3B,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;QACvC,IAAI,IAAY,CAAC;QACjB,IAAI,CAAC;YACH,IAAI,GAAG,EAAE,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QACtC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO;QACT,CAAC;QACD,IAAI,CAAC,IAAA,0BAAY,EAAC,IAAI,CAAC;YAAE,OAAO;QAChC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,GAAG,IAAA,gCAAkB,EAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACjE,CAAC,CAAC;IACF,MAAM,IAAI,GAAG,CAAC,GAAW,EAAE,KAAa,EAAE,EAAE;QAC1C,IAAI,KAAK,GAAG,CAAC;YAAE,OAAO;QACtB,IAAI,OAAoB,CAAC;QACzB,IAAI,CAAC;YACH,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,CAAC,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAChF,CAAC;QAAC,MAAM,CAAC;YACP,OAAO;QACT,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;gBAAE,SAAS;YACzD,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YAC5C,IAAI,CAAC,CAAC,WAAW,EAAE;gBAAE,IAAI,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;iBACnC,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,wCAAwC,CAAC,IAAI,CAAC,CAAC,CAAC;gBAAE,IAAI,CAAC,CAAC,CAAC,CAAC;QAC/F,CAAC;IACH,CAAC,CAAC;IACF,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IACZ,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,MAAM,EAAE,IAAI,EAAE,GAAG,IAAA,yBAAW,EAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACpC,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC3D,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;YAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACrF,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,6EAA6E;AAC7E,SAAgB,oBAAoB,CAAC,UAAkB;IACrD,MAAM,KAAK,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;IACvC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAClC,MAAM,SAAS,GAAG,gBAAgB,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IACtD,MAAM,QAAQ,GAAiB,EAAE,CAAC;IAClC,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,MAAM,CAAC,GAAG,IAAA,2BAAa,EAAC,CAAC,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAC1C,IAAI,CAAC,CAAC,EAAE;YAAE,SAAS;QACnB,QAAQ,CAAC,IAAI,CACX,CAAC,CAAC,MAAM,KAAK,kBAAkB;YAC7B,CAAC,CAAC,IAAA,mBAAK,EACH,sBAAsB,EACtB,GAAG,CAAC,CAAC,WAAW,cAAc,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,IAAI,qCAAqC,EACvF;gBACE,MAAM,EAAE,CAAC,CAAC,WAAW;gBACrB,GAAG,EAAE,uBAAuB,CAAC,CAAC,WAAW,iDAAiD;aAC3F,CACF;YACH,CAAC,CAAC,IAAA,mBAAK,EACH,uBAAuB,EACvB,GAAG,CAAC,CAAC,WAAW,cAAc,CAAC,CAAC,GAAG,kCAAkC,CAAC,CAAC,IAAI,IAAI,8BAA8B,GAAG,EAChH;gBACE,MAAM,EAAE,CAAC,CAAC,WAAW;gBACrB,GAAG,EAAE,4BAA4B,CAAC,CAAC,WAAW,uDAAuD;aACtG,CACF,CACN,CAAC;IACJ,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAYD,2CAA2C;AAC3C,SAAgB,cAAc,CAAC,UAAkB;IAI/C,MAAM,KAAK,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;IACvC,MAAM,SAAS,GAAG,gBAAgB,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IACtD,MAAM,MAAM,GAAiB,oBAAoB,CAAC,UAAU,CAAC,CAAC;IAC9D,MAAM,OAAO,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC5C,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,MAAM,CAAC,GAAG,IAAA,2BAAa,EAAC,CAAC,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAC1C,IAAI,CAAC,CAAC,CAAC,EAAE;YAAE,SAAS;QACpB,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;QAC/C,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;IACjE,CAAC;IACD,MAAM,MAAM,GAAmB,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;IACjD,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3F,MAAM,KAAK,GAAG;YACZ,IAAI;YACJ,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,EAAE;YACxB,UAAU,EAAE,GAAG,CAAC,MAAM;YACtB,KAAK,EAAE,EAAc;YACrB,OAAO,EAAE,EAAc;SACxB,CAAC;QACF,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;YACrB,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;YAChD,IAAI,EAAE;gBAAE,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,KAAK,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;iBACpE,CAAC;gBACJ,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;gBAC7B,MAAM,CAAC,IAAI,CACT,IAAA,qBAAO,EAAC,uBAAuB,EAAE,GAAG,IAAI,KAAK,EAAE,CAAC,KAAK,8BAA8B,EAAE;oBACnF,MAAM,EAAE,EAAE,CAAC,WAAW,IAAI,EAAE,CAAC,OAAO;oBACpC,GAAG,EAAE,2DAA2D,IAAI,IAAI,EAAE,CAAC,WAAW,IAAI,EAAE,CAAC,OAAO,GAAG;iBACxG,CAAC,CACH,CAAC;YACJ,CAAC;QACH,CAAC;QACD,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAC5B,CAAC"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Behaviour changed without a specification (REQ-333, REQ-334).
|
|
4
|
+
*
|
|
5
|
+
* A commit since the base drifts when it changes production code, its message
|
|
6
|
+
* names no requirement, and no test file it changes names one: a person
|
|
7
|
+
* patched the product and the specification never heard of it. The harness's
|
|
8
|
+
* commits name their requirement, so they never drift.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.isProductionFile = isProductionFile;
|
|
12
|
+
exports.driftSince = driftSince;
|
|
13
|
+
exports.driftFindings = driftFindings;
|
|
14
|
+
const node_child_process_1 = require("node:child_process");
|
|
15
|
+
const diagnostics_1 = require("./diagnostics");
|
|
16
|
+
const quality_run_1 = require("./quality-run");
|
|
17
|
+
const REQ = /\bREQ-\d+\b/;
|
|
18
|
+
const SOURCE = /\.(ts|tsx|js|jsx|mjs|cjs|java|kt|scala|groovy|py|go|rs|cs|fs|rb|php|swift|vue|svelte|sql|c|cc|cpp|h|hpp)$/i;
|
|
19
|
+
const NOT_PRODUCTION = [
|
|
20
|
+
/(^|\/)(tests?|__tests__|__mocks__|spec|specs|e2e|fixtures|testdata)\//i,
|
|
21
|
+
/(^|\/)src\/(test|it|integrationTest)\//i,
|
|
22
|
+
/\.(test|spec|e2e|stories)\.[^/]+$/i,
|
|
23
|
+
/(Test|Tests|IT|Spec)\.(java|kt|scala|groovy|cs)$/,
|
|
24
|
+
/(^|\/)(docs|features|\.github|\.specgate|\.harness)\//,
|
|
25
|
+
/(^|[/.])(eslint|prettier|vite|vitest|jest|playwright|next|webpack|rollup|tailwind|postcss|babel|tsup)\.config\.[^/]+$/i,
|
|
26
|
+
/(^|\/)build\.gradle(\.kts)?$|(^|\/)settings\.gradle(\.kts)?$/,
|
|
27
|
+
];
|
|
28
|
+
function isProductionFile(file) {
|
|
29
|
+
const f = file.replace(/\\/g, "/");
|
|
30
|
+
return SOURCE.test(f) && !NOT_PRODUCTION.some((re) => re.test(f));
|
|
31
|
+
}
|
|
32
|
+
function isTestFile(file) {
|
|
33
|
+
const f = file.replace(/\\/g, "/");
|
|
34
|
+
return NOT_PRODUCTION.slice(0, 4).some((re) => re.test(f));
|
|
35
|
+
}
|
|
36
|
+
function git(dir, args) {
|
|
37
|
+
return (0, node_child_process_1.spawnSync)("git", ["-C", dir, ...args], { encoding: "utf8", maxBuffer: 64 * 1024 * 1024 });
|
|
38
|
+
}
|
|
39
|
+
function driftSince(projectDir, explicitBase = "") {
|
|
40
|
+
const base = (0, quality_run_1.baseOf)(projectDir, explicitBase);
|
|
41
|
+
if (!base)
|
|
42
|
+
return { base: "", commits: [] };
|
|
43
|
+
const list = git(projectDir, ["rev-list", "--no-merges", "--reverse", `${base}..HEAD`]);
|
|
44
|
+
if (list.status !== 0)
|
|
45
|
+
return { base, commits: [] };
|
|
46
|
+
const commits = [];
|
|
47
|
+
for (const sha of (list.stdout || "").split("\n").filter(Boolean)) {
|
|
48
|
+
const message = git(projectDir, ["log", "-1", "--format=%B", sha]).stdout || "";
|
|
49
|
+
if (REQ.test(message))
|
|
50
|
+
continue;
|
|
51
|
+
const files = (git(projectDir, ["diff-tree", "--no-commit-id", "--name-only", "-r", "--root", sha]).stdout ||
|
|
52
|
+
"")
|
|
53
|
+
.split("\n")
|
|
54
|
+
.filter(Boolean);
|
|
55
|
+
const production = files.filter(isProductionFile);
|
|
56
|
+
if (production.length === 0)
|
|
57
|
+
continue;
|
|
58
|
+
const namedByATest = files.filter(isTestFile).some((f) => {
|
|
59
|
+
const shown = git(projectDir, ["show", `${sha}:${f}`]);
|
|
60
|
+
return shown.status === 0 && REQ.test(shown.stdout || "");
|
|
61
|
+
});
|
|
62
|
+
if (namedByATest)
|
|
63
|
+
continue;
|
|
64
|
+
commits.push({
|
|
65
|
+
sha: sha.slice(0, 12),
|
|
66
|
+
subject: message.split("\n")[0].trim(),
|
|
67
|
+
files: production,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
return { base, commits };
|
|
71
|
+
}
|
|
72
|
+
/** One finding per drifting commit; errors when the project gates on drift. */
|
|
73
|
+
function driftFindings(report, gate) {
|
|
74
|
+
const make = gate ? diagnostics_1.error : diagnostics_1.warning;
|
|
75
|
+
return report.commits.map((c) => make("spec_drift", `${c.sha} "${c.subject}" changes ${c.files.join(", ")} and names no requirement, nor does any test it changes.`, {
|
|
76
|
+
target: c.sha,
|
|
77
|
+
fix: 'Name the requirement it serves in the commit and a test, or specify the behaviour first: specgate new "<behaviour>".',
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=drift.js.map
|