@mmnto/cli 2.0.0 → 2.1.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/commands/describe.d.ts +13 -1
- package/dist/commands/describe.d.ts.map +1 -1
- package/dist/commands/describe.js +29 -1
- package/dist/commands/describe.js.map +1 -1
- package/dist/commands/describe.test.js +86 -3
- package/dist/commands/describe.test.js.map +1 -1
- package/dist/commands/init-templates.d.ts +2 -2
- package/dist/commands/init-templates.d.ts.map +1 -1
- package/dist/commands/init-templates.js +2 -2
- package/dist/commands/install-hooks.d.ts.map +1 -1
- package/dist/commands/install-hooks.js +159 -27
- package/dist/commands/install-hooks.js.map +1 -1
- package/dist/commands/install-hooks.test.js +460 -12
- package/dist/commands/install-hooks.test.js.map +1 -1
- package/dist/commands/legs.d.ts +35 -7
- package/dist/commands/legs.d.ts.map +1 -1
- package/dist/commands/legs.js +26 -7
- package/dist/commands/legs.js.map +1 -1
- package/dist/commands/legs.test.js +87 -0
- package/dist/commands/legs.test.js.map +1 -1
- package/dist/commands/release-train-shape.test.d.ts +2 -0
- package/dist/commands/release-train-shape.test.d.ts.map +1 -0
- package/dist/commands/release-train-shape.test.js +226 -0
- package/dist/commands/release-train-shape.test.js.map +1 -0
- package/dist/commands/tools-hook-parity.test.js +200 -0
- package/dist/commands/tools-hook-parity.test.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import * as os from 'node:os';
|
|
4
|
+
import * as path from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
|
7
|
+
// Executed regression cases for tools/release-train-shape.sh — the legs-gate CI
|
|
8
|
+
// arm's one exemption (mmnto-ai/totem#2779). The workflow pins the script's
|
|
9
|
+
// invocation (tools-hook-parity.test.ts); this file runs the script against a
|
|
10
|
+
// throwaway git repository and reads what it writes to $GITHUB_OUTPUT, so the
|
|
11
|
+
// rule "exempt only when the diff is exactly the release train's work" is
|
|
12
|
+
// proven by execution, case by case, including the bypass Greptile named on
|
|
13
|
+
// mmnto-ai/totem#2780: deleting a pending changeset without consuming them all.
|
|
14
|
+
const REPO_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../..');
|
|
15
|
+
const SCRIPT = path.join(REPO_ROOT, 'tools', 'release-train-shape.sh');
|
|
16
|
+
// A changeset body long enough that git's rename detection would pair its
|
|
17
|
+
// deletion with an ADDED file of the same text (the first-release case below
|
|
18
|
+
// reuses it verbatim): the script disables rename detection, so the pair must
|
|
19
|
+
// still read as D + A and stay exempt (the leg's F3 on mmnto-ai/totem#2780).
|
|
20
|
+
const CHANGESET_A = [
|
|
21
|
+
'---',
|
|
22
|
+
'"@example/y": minor',
|
|
23
|
+
'---',
|
|
24
|
+
'',
|
|
25
|
+
'Add the first feature of package y, with enough prose that a rename',
|
|
26
|
+
'heuristic would call the deleted changeset and the new CHANGELOG the same file.',
|
|
27
|
+
'',
|
|
28
|
+
].join(String.fromCharCode(10));
|
|
29
|
+
// A POSIX bash that is not WSL (a WSL bash cannot run against a Windows temp
|
|
30
|
+
// path; the ubuntu and macos legs of the matrix run these cases regardless).
|
|
31
|
+
function bashUsable() {
|
|
32
|
+
const probe = spawnSync('bash', ['-c', 'uname -r'], { encoding: 'utf-8', timeout: 5000 });
|
|
33
|
+
if (probe.status !== 0)
|
|
34
|
+
return false;
|
|
35
|
+
return !/microsoft/i.test(probe.stdout);
|
|
36
|
+
}
|
|
37
|
+
const BASH_OK = bashUsable();
|
|
38
|
+
function git(cwd, ...args) {
|
|
39
|
+
const r = spawnSync('git', args, { cwd, encoding: 'utf-8' });
|
|
40
|
+
if (r.status !== 0)
|
|
41
|
+
throw new Error(`git ${args.join(' ')} failed: ${r.stderr}`);
|
|
42
|
+
return r.stdout;
|
|
43
|
+
}
|
|
44
|
+
function write(cwd, rel, content) {
|
|
45
|
+
const abs = path.join(cwd, rel);
|
|
46
|
+
fs.mkdirSync(path.dirname(abs), { recursive: true });
|
|
47
|
+
fs.writeFileSync(abs, content, 'utf-8');
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Run the script with HEAD at `cwd`'s checkout against `base`; read
|
|
51
|
+
* $GITHUB_OUTPUT. The output file lives OUTSIDE the fixture repository, or the
|
|
52
|
+
* next scenario's `git add -A` would commit it and read it as a changed path.
|
|
53
|
+
*/
|
|
54
|
+
function shape(cwd, base) {
|
|
55
|
+
const outFile = path.join(fs.mkdtempSync(path.join(os.tmpdir(), 'totem-gh-output-')), 'out');
|
|
56
|
+
fs.writeFileSync(outFile, '', 'utf-8');
|
|
57
|
+
const r = spawnSync('bash', [SCRIPT, base], {
|
|
58
|
+
cwd,
|
|
59
|
+
encoding: 'utf-8',
|
|
60
|
+
env: { ...process.env, GITHUB_OUTPUT: outFile },
|
|
61
|
+
});
|
|
62
|
+
return { status: r.status, exempt: fs.readFileSync(outFile, 'utf-8').trim(), log: r.stdout };
|
|
63
|
+
}
|
|
64
|
+
describe.skipIf(!BASH_OK)('tools/release-train-shape.sh (mmnto-ai/totem#2779)', () => {
|
|
65
|
+
let repo = '';
|
|
66
|
+
beforeAll(() => {
|
|
67
|
+
repo = fs.mkdtempSync(path.join(os.tmpdir(), 'totem-release-train-'));
|
|
68
|
+
git(repo, 'init', '-q', '-b', 'main');
|
|
69
|
+
git(repo, 'config', 'user.email', 'test@example.invalid');
|
|
70
|
+
git(repo, 'config', 'user.name', 'test');
|
|
71
|
+
git(repo, 'config', 'commit.gpgsign', 'false');
|
|
72
|
+
git(repo, 'config', 'core.autocrlf', 'false');
|
|
73
|
+
// The base: two pending changesets, the README and config beside them, one
|
|
74
|
+
// workspace package with a CHANGELOG, one without (its first release ADDS
|
|
75
|
+
// one), the private root package.json, an owed doctrine file, and a path
|
|
76
|
+
// carrying whitespace.
|
|
77
|
+
write(repo, '.changeset/README.md', 'readme');
|
|
78
|
+
write(repo, '.changeset/config.json', '{}');
|
|
79
|
+
write(repo, '.changeset/a.md', CHANGESET_A);
|
|
80
|
+
write(repo, '.changeset/b.md', 'b');
|
|
81
|
+
write(repo, 'packages/x/package.json', '{"version":"1.0.0"}');
|
|
82
|
+
write(repo, 'packages/x/CHANGELOG.md', '# x');
|
|
83
|
+
write(repo, 'packages/y/package.json', '{"version":"0.0.0"}');
|
|
84
|
+
write(repo, 'package.json', '{"private":true}');
|
|
85
|
+
write(repo, 'doctrine/d.md', 'd');
|
|
86
|
+
write(repo, 'packages/x/CHANGELOG.md more', 'space');
|
|
87
|
+
git(repo, 'add', '-A');
|
|
88
|
+
git(repo, 'commit', '-q', '-m', 'base');
|
|
89
|
+
git(repo, 'branch', 'base');
|
|
90
|
+
// A second base with nothing pending.
|
|
91
|
+
git(repo, 'checkout', '-q', '-b', 'base-empty');
|
|
92
|
+
fs.rmSync(path.join(repo, '.changeset/a.md'));
|
|
93
|
+
fs.rmSync(path.join(repo, '.changeset/b.md'));
|
|
94
|
+
git(repo, 'add', '-A');
|
|
95
|
+
git(repo, 'commit', '-q', '-m', 'base-empty');
|
|
96
|
+
git(repo, 'checkout', '-q', 'base');
|
|
97
|
+
});
|
|
98
|
+
afterAll(() => {
|
|
99
|
+
if (repo.length > 0)
|
|
100
|
+
fs.rmSync(repo, { recursive: true, force: true });
|
|
101
|
+
});
|
|
102
|
+
let caseNo = 0;
|
|
103
|
+
/** Branch from `from`, apply `mutate`, commit, and run the script against `from`. */
|
|
104
|
+
function scenario(from, mutate) {
|
|
105
|
+
caseNo += 1;
|
|
106
|
+
git(repo, 'checkout', '-q', '-b', `case-${caseNo}`, from);
|
|
107
|
+
mutate();
|
|
108
|
+
git(repo, 'add', '-A');
|
|
109
|
+
git(repo, 'commit', '-q', '--allow-empty', '-m', `case ${caseNo}`);
|
|
110
|
+
return shape(repo, from);
|
|
111
|
+
}
|
|
112
|
+
const consumeAll = () => {
|
|
113
|
+
fs.rmSync(path.join(repo, '.changeset/a.md'));
|
|
114
|
+
fs.rmSync(path.join(repo, '.changeset/b.md'));
|
|
115
|
+
};
|
|
116
|
+
const renderX = () => {
|
|
117
|
+
write(repo, 'packages/x/CHANGELOG.md', '# x\n\n## 1.1.0');
|
|
118
|
+
write(repo, 'packages/x/package.json', '{"version":"1.1.0"}');
|
|
119
|
+
};
|
|
120
|
+
it('the release train: every pending changeset consumed, CHANGELOG and package.json rendered — exempt', () => {
|
|
121
|
+
const r = scenario('base', () => {
|
|
122
|
+
consumeAll();
|
|
123
|
+
renderX();
|
|
124
|
+
});
|
|
125
|
+
expect(r.status).toBe(0);
|
|
126
|
+
expect(r.exempt).toBe('exempt=true');
|
|
127
|
+
expect(r.log).toContain('::notice title=totem legs gate SKIPPED::');
|
|
128
|
+
});
|
|
129
|
+
it("a new package's first release ADDS its CHANGELOG (mmnto-ai/totem#2514), even one rename detection would pair with the deleted changeset — exempt", () => {
|
|
130
|
+
const r = scenario('base', () => {
|
|
131
|
+
consumeAll();
|
|
132
|
+
write(repo, 'packages/y/CHANGELOG.md', CHANGESET_A);
|
|
133
|
+
write(repo, 'packages/y/package.json', '{"version":"0.1.0"}');
|
|
134
|
+
});
|
|
135
|
+
expect(r.status).toBe(0);
|
|
136
|
+
expect(r.exempt).toBe('exempt=true');
|
|
137
|
+
expect(r.log).not.toContain('paths outside the shape');
|
|
138
|
+
});
|
|
139
|
+
it('nothing pending at the merge base, yet CHANGELOG and package.json rewritten — not exempt (the train writes nothing when it has nothing to consume)', () => {
|
|
140
|
+
const r = scenario('base-empty', () => {
|
|
141
|
+
write(repo, 'packages/x/CHANGELOG.md', '# TOTALLY FABRICATED');
|
|
142
|
+
write(repo, 'packages/x/package.json', '{"version":"9.9.9"}');
|
|
143
|
+
});
|
|
144
|
+
expect(r.status).toBe(0);
|
|
145
|
+
expect(r.exempt).toBe('exempt=false');
|
|
146
|
+
expect(r.log).toContain('nothing pending at the merge base');
|
|
147
|
+
});
|
|
148
|
+
it('the script parses (bash -n) — the only shell gate this repo runs on it', () => {
|
|
149
|
+
const r = spawnSync('bash', ['-n', SCRIPT], { encoding: 'utf-8' });
|
|
150
|
+
expect(r.status).toBe(0);
|
|
151
|
+
});
|
|
152
|
+
it('deleting a SUBSET of the pending changesets (the bypass Greptile named) — not exempt', () => {
|
|
153
|
+
const r = scenario('base', () => {
|
|
154
|
+
fs.rmSync(path.join(repo, '.changeset/a.md'));
|
|
155
|
+
renderX();
|
|
156
|
+
});
|
|
157
|
+
expect(r.status).toBe(0);
|
|
158
|
+
expect(r.exempt).toBe('exempt=false');
|
|
159
|
+
expect(r.log).toContain('not exactly the pending set');
|
|
160
|
+
});
|
|
161
|
+
it('deletions only, nothing rendered — not exempt', () => {
|
|
162
|
+
const r = scenario('base', consumeAll);
|
|
163
|
+
expect(r.status).toBe(0);
|
|
164
|
+
expect(r.exempt).toBe('exempt=false');
|
|
165
|
+
expect(r.log).toContain('no CHANGELOG rendered');
|
|
166
|
+
});
|
|
167
|
+
it('deleting .changeset/README.md beside the train — not exempt', () => {
|
|
168
|
+
const r = scenario('base', () => {
|
|
169
|
+
consumeAll();
|
|
170
|
+
renderX();
|
|
171
|
+
fs.rmSync(path.join(repo, '.changeset/README.md'));
|
|
172
|
+
});
|
|
173
|
+
expect(r.status).toBe(0);
|
|
174
|
+
expect(r.exempt).toBe('exempt=false');
|
|
175
|
+
// README is never pending, so its deletion is a mismatch of rule 2.
|
|
176
|
+
expect(r.log).toContain('not exactly the pending set');
|
|
177
|
+
});
|
|
178
|
+
it('the train plus an added owed doctrine file — not exempt', () => {
|
|
179
|
+
const r = scenario('base', () => {
|
|
180
|
+
consumeAll();
|
|
181
|
+
renderX();
|
|
182
|
+
write(repo, 'doctrine/new-rule.md', 'new');
|
|
183
|
+
});
|
|
184
|
+
expect(r.exempt).toBe('exempt=false');
|
|
185
|
+
expect(r.log).toContain('doctrine/new-rule.md');
|
|
186
|
+
});
|
|
187
|
+
it('the train plus the private root package.json — not exempt', () => {
|
|
188
|
+
const r = scenario('base', () => {
|
|
189
|
+
consumeAll();
|
|
190
|
+
renderX();
|
|
191
|
+
write(repo, 'package.json', '{"private":true,"x":1}');
|
|
192
|
+
});
|
|
193
|
+
expect(r.status).toBe(0);
|
|
194
|
+
expect(r.exempt).toBe('exempt=false');
|
|
195
|
+
expect(r.log).toContain('paths outside the shape');
|
|
196
|
+
expect(r.log).toMatch(/^M\s+package\.json$/m);
|
|
197
|
+
});
|
|
198
|
+
it('the train plus a path carrying whitespace — not exempt', () => {
|
|
199
|
+
const r = scenario('base', () => {
|
|
200
|
+
consumeAll();
|
|
201
|
+
renderX();
|
|
202
|
+
write(repo, 'packages/x/CHANGELOG.md more', 'changed');
|
|
203
|
+
});
|
|
204
|
+
expect(r.status).toBe(0);
|
|
205
|
+
expect(r.exempt).toBe('exempt=false');
|
|
206
|
+
expect(r.log).toContain('paths outside the shape');
|
|
207
|
+
expect(r.log).toContain('packages/x/CHANGELOG.md more');
|
|
208
|
+
});
|
|
209
|
+
it('an empty diff while changesets are pending — not exempt', () => {
|
|
210
|
+
const r = scenario('base', () => undefined);
|
|
211
|
+
expect(r.status).toBe(0);
|
|
212
|
+
expect(r.exempt).toBe('exempt=false');
|
|
213
|
+
expect(r.log).toContain('not exactly the pending set');
|
|
214
|
+
});
|
|
215
|
+
it('an empty diff with nothing pending — exempt (nothing to judge)', () => {
|
|
216
|
+
const r = scenario('base-empty', () => undefined);
|
|
217
|
+
expect(r.status).toBe(0);
|
|
218
|
+
expect(r.exempt).toBe('exempt=true');
|
|
219
|
+
});
|
|
220
|
+
it('a base ref that does not resolve — the derivation fails, nothing is written (fail-closed)', () => {
|
|
221
|
+
const r = shape(repo, 'no-such-ref');
|
|
222
|
+
expect(r.status).not.toBe(0);
|
|
223
|
+
expect(r.exempt).toBe('');
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
//# sourceMappingURL=release-train-shape.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"release-train-shape.test.js","sourceRoot":"","sources":["../../src/commands/release-train-shape.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAEnE,gFAAgF;AAChF,4EAA4E;AAC5E,8EAA8E;AAC9E,8EAA8E;AAC9E,0EAA0E;AAC1E,4EAA4E;AAC5E,gFAAgF;AAEhF,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC;AAC5F,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,EAAE,wBAAwB,CAAC,CAAC;AACvE,0EAA0E;AAC1E,6EAA6E;AAC7E,8EAA8E;AAC9E,6EAA6E;AAC7E,MAAM,WAAW,GAAG;IAClB,KAAK;IACL,qBAAqB;IACrB,KAAK;IACL,EAAE;IACF,qEAAqE;IACrE,iFAAiF;IACjF,EAAE;CACH,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC;AAEhC,6EAA6E;AAC7E,6EAA6E;AAC7E,SAAS,UAAU;IACjB,MAAM,KAAK,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,UAAU,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1F,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACrC,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;AAC1C,CAAC;AACD,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;AAE7B,SAAS,GAAG,CAAC,GAAW,EAAE,GAAG,IAAc;IACzC,MAAM,CAAC,GAAG,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IAC7D,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;IACjF,OAAO,CAAC,CAAC,MAAM,CAAC;AAClB,CAAC;AAED,SAAS,KAAK,CAAC,GAAW,EAAE,GAAW,EAAE,OAAe;IACtD,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAChC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACrD,EAAE,CAAC,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AAC1C,CAAC;AAQD;;;;GAIG;AACH,SAAS,KAAK,CAAC,GAAW,EAAE,IAAY;IACtC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,kBAAkB,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAC7F,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;IACvC,MAAM,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE;QAC1C,GAAG;QACH,QAAQ,EAAE,OAAO;QACjB,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,aAAa,EAAE,OAAO,EAAE;KAChD,CAAC,CAAC;IACH,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;AAC/F,CAAC;AAED,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,oDAAoD,EAAE,GAAG,EAAE;IACnF,IAAI,IAAI,GAAG,EAAE,CAAC;IAEd,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,sBAAsB,CAAC,CAAC,CAAC;QACtE,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;QACtC,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,sBAAsB,CAAC,CAAC;QAC1D,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;QACzC,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,gBAAgB,EAAE,OAAO,CAAC,CAAC;QAC/C,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,eAAe,EAAE,OAAO,CAAC,CAAC;QAC9C,2EAA2E;QAC3E,0EAA0E;QAC1E,yEAAyE;QACzE,uBAAuB;QACvB,KAAK,CAAC,IAAI,EAAE,sBAAsB,EAAE,QAAQ,CAAC,CAAC;QAC9C,KAAK,CAAC,IAAI,EAAE,wBAAwB,EAAE,IAAI,CAAC,CAAC;QAC5C,KAAK,CAAC,IAAI,EAAE,iBAAiB,EAAE,WAAW,CAAC,CAAC;QAC5C,KAAK,CAAC,IAAI,EAAE,iBAAiB,EAAE,GAAG,CAAC,CAAC;QACpC,KAAK,CAAC,IAAI,EAAE,yBAAyB,EAAE,qBAAqB,CAAC,CAAC;QAC9D,KAAK,CAAC,IAAI,EAAE,yBAAyB,EAAE,KAAK,CAAC,CAAC;QAC9C,KAAK,CAAC,IAAI,EAAE,yBAAyB,EAAE,qBAAqB,CAAC,CAAC;QAC9D,KAAK,CAAC,IAAI,EAAE,cAAc,EAAE,kBAAkB,CAAC,CAAC;QAChD,KAAK,CAAC,IAAI,EAAE,eAAe,EAAE,GAAG,CAAC,CAAC;QAClC,KAAK,CAAC,IAAI,EAAE,8BAA8B,EAAE,OAAO,CAAC,CAAC;QACrD,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;QACvB,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;QACxC,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;QAC5B,sCAAsC;QACtC,GAAG,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,YAAY,CAAC,CAAC;QAChD,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC;QAC9C,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC;QAC9C,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;QACvB,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,YAAY,CAAC,CAAC;QAC9C,GAAG,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,GAAG,EAAE;QACZ,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;YAAE,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACzE,CAAC,CAAC,CAAC;IAEH,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,qFAAqF;IACrF,SAAS,QAAQ,CAAC,IAAY,EAAE,MAAkB;QAChD,MAAM,IAAI,CAAC,CAAC;QACZ,GAAG,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,MAAM,EAAE,EAAE,IAAI,CAAC,CAAC;QAC1D,MAAM,EAAE,CAAC;QACT,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;QACvB,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,QAAQ,MAAM,EAAE,CAAC,CAAC;QACnE,OAAO,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC3B,CAAC;IACD,MAAM,UAAU,GAAG,GAAS,EAAE;QAC5B,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC;QAC9C,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAChD,CAAC,CAAC;IACF,MAAM,OAAO,GAAG,GAAS,EAAE;QACzB,KAAK,CAAC,IAAI,EAAE,yBAAyB,EAAE,iBAAiB,CAAC,CAAC;QAC1D,KAAK,CAAC,IAAI,EAAE,yBAAyB,EAAE,qBAAqB,CAAC,CAAC;IAChE,CAAC,CAAC;IAEF,EAAE,CAAC,mGAAmG,EAAE,GAAG,EAAE;QAC3G,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,GAAG,EAAE;YAC9B,UAAU,EAAE,CAAC;YACb,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACzB,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACrC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,0CAA0C,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kJAAkJ,EAAE,GAAG,EAAE;QAC1J,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,GAAG,EAAE;YAC9B,UAAU,EAAE,CAAC;YACb,KAAK,CAAC,IAAI,EAAE,yBAAyB,EAAE,WAAW,CAAC,CAAC;YACpD,KAAK,CAAC,IAAI,EAAE,yBAAyB,EAAE,qBAAqB,CAAC,CAAC;QAChE,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACzB,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACrC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,yBAAyB,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oJAAoJ,EAAE,GAAG,EAAE;QAC5J,MAAM,CAAC,GAAG,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;YACpC,KAAK,CAAC,IAAI,EAAE,yBAAyB,EAAE,sBAAsB,CAAC,CAAC;YAC/D,KAAK,CAAC,IAAI,EAAE,yBAAyB,EAAE,qBAAqB,CAAC,CAAC;QAChE,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACzB,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACtC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,mCAAmC,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wEAAwE,EAAE,GAAG,EAAE;QAChF,MAAM,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;QACnE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC3B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sFAAsF,EAAE,GAAG,EAAE;QAC9F,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,GAAG,EAAE;YAC9B,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC;YAC9C,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACzB,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACtC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,6BAA6B,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QACvC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACzB,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACtC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,uBAAuB,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACrE,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,GAAG,EAAE;YAC9B,UAAU,EAAE,CAAC;YACb,OAAO,EAAE,CAAC;YACV,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,sBAAsB,CAAC,CAAC,CAAC;QACrD,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACzB,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACtC,oEAAoE;QACpE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,6BAA6B,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;QACjE,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,GAAG,EAAE;YAC9B,UAAU,EAAE,CAAC;YACb,OAAO,EAAE,CAAC;YACV,KAAK,CAAC,IAAI,EAAE,sBAAsB,EAAE,KAAK,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACtC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,sBAAsB,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,GAAG,EAAE;YAC9B,UAAU,EAAE,CAAC;YACb,OAAO,EAAE,CAAC;YACV,KAAK,CAAC,IAAI,EAAE,cAAc,EAAE,wBAAwB,CAAC,CAAC;QACxD,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACzB,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACtC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,yBAAyB,CAAC,CAAC;QACnD,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,sBAAsB,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,GAAG,EAAE;YAC9B,UAAU,EAAE,CAAC;YACb,OAAO,EAAE,CAAC;YACV,KAAK,CAAC,IAAI,EAAE,8BAA8B,EAAE,SAAS,CAAC,CAAC;QACzD,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACzB,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACtC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,yBAAyB,CAAC,CAAC;QACnD,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,8BAA8B,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;QACjE,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC5C,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACzB,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACtC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,6BAA6B,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE;QACxE,MAAM,CAAC,GAAG,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAClD,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACzB,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2FAA2F,EAAE,GAAG,EAAE;QACnG,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;QACrC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC7B,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
1
2
|
import * as fs from 'node:fs';
|
|
2
3
|
import * as path from 'node:path';
|
|
3
4
|
import { fileURLToPath } from 'node:url';
|
|
@@ -24,6 +25,94 @@ const RENDER = { tier: TIER, totemDir: TOTEM_DIR, fallbackCmd: FALLBACK_CMD };
|
|
|
24
25
|
function readTool(hook) {
|
|
25
26
|
return fs.readFileSync(path.join(TOOLS_DIR, hook), 'utf-8');
|
|
26
27
|
}
|
|
28
|
+
// Named once: the newline is BUILT, never authored as an escape (the banked
|
|
29
|
+
// heredoc decode trap), and `indexOf`'s -1 reads as a sentinel only by
|
|
30
|
+
// convention (CodeRabbit on mmnto-ai/totem#2780).
|
|
31
|
+
const LF = String.fromCharCode(10);
|
|
32
|
+
const NOT_FOUND = -1;
|
|
33
|
+
const GATE_STEP_NAME = 'totem legs gate (HARD';
|
|
34
|
+
const RELEASE_TRAIN_STEP_NAME = 'release-train check';
|
|
35
|
+
function readLintWorkflow() {
|
|
36
|
+
return fs.readFileSync(path.join(REPO_ROOT, '.github', 'workflows', 'lint.yml'), 'utf-8');
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* ONE step's YAML — from the `- name:` line whose name starts with `namePrefix`
|
|
40
|
+
* to the next step's `- name:` — comment lines dropped: the NEXT step's leading
|
|
41
|
+
* comment sits inside the slice and legitimately discusses `continue-on-error`;
|
|
42
|
+
* only YAML keys count. Empty when no step carries that name. Every assertion
|
|
43
|
+
* on a step's own `if:` / `id:` / `run:` reads its slice, never the whole
|
|
44
|
+
* workflow, so a decoy elsewhere cannot satisfy it (Greptile P2 and CodeRabbit
|
|
45
|
+
* on mmnto-ai/totem#2780).
|
|
46
|
+
*/
|
|
47
|
+
function stepNamed(workflow, namePrefix) {
|
|
48
|
+
// Scoped to the `lint` job and comments dropped FIRST, so neither a `#` line
|
|
49
|
+
// carrying `- name: …` (the leg's F7 on mmnto-ai/totem#2780) nor a decoy step
|
|
50
|
+
// in another job (CodeRabbit, same PR) can anchor the slice; and EXACTLY one
|
|
51
|
+
// step may carry the name — a second one would let the wrong step satisfy
|
|
52
|
+
// every assertion below.
|
|
53
|
+
const job = lintJobOf(workflow);
|
|
54
|
+
const marker = '- name: ' + namePrefix;
|
|
55
|
+
const stepStart = job.indexOf(marker);
|
|
56
|
+
if (stepStart === NOT_FOUND)
|
|
57
|
+
return '';
|
|
58
|
+
if (job.indexOf(marker, stepStart + 1) !== NOT_FOUND)
|
|
59
|
+
return '';
|
|
60
|
+
const nextStep = job.indexOf('- name:', stepStart + 1);
|
|
61
|
+
return job.slice(stepStart, nextStep === NOT_FOUND ? job.length : nextStep);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* The `lint` job's YAML — from its key to the next top-level job key (two-space
|
|
65
|
+
* indent) or the end of the file — comment lines dropped. Empty when the job is
|
|
66
|
+
* missing. Every step and header lookup reads this slice, never the file.
|
|
67
|
+
*/
|
|
68
|
+
function lintJobOf(workflow) {
|
|
69
|
+
const clean = dropComments(workflow);
|
|
70
|
+
const jobIdx = clean.indexOf(LF + ' lint:' + LF);
|
|
71
|
+
if (jobIdx === NOT_FOUND)
|
|
72
|
+
return '';
|
|
73
|
+
const nextJob = clean.slice(jobIdx + 1).search(/\n {2}[A-Za-z0-9_-]+:\n/);
|
|
74
|
+
return clean.slice(jobIdx, nextJob === NOT_FOUND ? clean.length : jobIdx + 1 + nextJob);
|
|
75
|
+
}
|
|
76
|
+
/** The non-empty, trimmed lines of a step's `run: |` block, in order. */
|
|
77
|
+
function runLinesOf(step) {
|
|
78
|
+
const runIdx = step.indexOf('run: |');
|
|
79
|
+
if (runIdx === NOT_FOUND)
|
|
80
|
+
return [];
|
|
81
|
+
return step
|
|
82
|
+
.slice(runIdx + 'run: |'.length)
|
|
83
|
+
.split(LF)
|
|
84
|
+
.map((line) => line.trim())
|
|
85
|
+
.filter((line) => line.length > 0);
|
|
86
|
+
}
|
|
87
|
+
function gateStepOf(workflow) {
|
|
88
|
+
return stepNamed(workflow, GATE_STEP_NAME);
|
|
89
|
+
}
|
|
90
|
+
/** The `if:` lines of one step slice, trimmed — exactly one is the contract. */
|
|
91
|
+
function ifLinesOf(step) {
|
|
92
|
+
return step
|
|
93
|
+
.split(LF)
|
|
94
|
+
.map((line) => line.trim())
|
|
95
|
+
.filter((line) => line.startsWith('if:'));
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* The `lint` job's header — from its key to its `steps:` — comment lines
|
|
99
|
+
* dropped, so an assertion on the job-level env predicate reads YAML keys and
|
|
100
|
+
* never a `#` decoy carrying the same text (the leg's F3 on
|
|
101
|
+
* mmnto-ai/totem#2780). Empty when the job or its steps key is missing.
|
|
102
|
+
*/
|
|
103
|
+
function lintJobHeaderOf(workflow) {
|
|
104
|
+
const job = lintJobOf(workflow);
|
|
105
|
+
const stepsIdx = job.indexOf(LF + ' steps:');
|
|
106
|
+
if (stepsIdx === NOT_FOUND)
|
|
107
|
+
return '';
|
|
108
|
+
return job.slice(0, stepsIdx);
|
|
109
|
+
}
|
|
110
|
+
function dropComments(yaml) {
|
|
111
|
+
return yaml
|
|
112
|
+
.split(LF)
|
|
113
|
+
.filter((line) => !line.trim().startsWith('#'))
|
|
114
|
+
.join(LF);
|
|
115
|
+
}
|
|
27
116
|
describe('tools/ hook scripts match the CLI template builders (mmnto-ai/totem#2404)', () => {
|
|
28
117
|
it('resolves the pnpm-based fallback command for this repo', () => {
|
|
29
118
|
expect(FALLBACK_CMD).toBe('pnpm dlx @mmnto/cli');
|
|
@@ -38,4 +127,115 @@ describe('tools/ hook scripts match the CLI template builders (mmnto-ai/totem#24
|
|
|
38
127
|
expect(readTool('post-merge')).toBe(buildHookContent(RENDER));
|
|
39
128
|
});
|
|
40
129
|
});
|
|
130
|
+
// The repo's own legs-gate CI arm (mmnto-ai/totem#2771; the `legs-gate` parity
|
|
131
|
+
// row, arm (a)). Two things the arm depends on that nothing else asserts: the
|
|
132
|
+
// artifacts ignore must RE-INCLUDE the deposit directory, or every deposit is
|
|
133
|
+
// unstageable and the required `Totem Lint` check goes permanently red; and
|
|
134
|
+
// the workflow step must invoke the BUILT entry before the lint step's
|
|
135
|
+
// `--depth=1` fetch, which shallows the checkout. Both are read from the repo's
|
|
136
|
+
// files, so an edit that narrows the ignore or moves the step fails here first.
|
|
137
|
+
describe("the repo's own legs-gate CI arm posture (mmnto-ai/totem#2771)", () => {
|
|
138
|
+
const gitOk = spawnSync('git', ['--version'], { encoding: 'utf-8' }).status === 0;
|
|
139
|
+
const checkIgnore = (relPath) => spawnSync('git', ['check-ignore', '-q', relPath], { cwd: REPO_ROOT, encoding: 'utf-8' }).status;
|
|
140
|
+
it.skipIf(!gitOk)('.gitignore re-includes .totem/artifacts/legs/ and keeps its siblings ignored', () => {
|
|
141
|
+
// check-ignore: 0 = ignored, 1 = not ignored. A deposit path must be stageable.
|
|
142
|
+
expect(checkIgnore('.totem/artifacts/legs/' + 'a'.repeat(40) + '.json')).toBe(1);
|
|
143
|
+
expect(checkIgnore('.totem/artifacts/runs/x.json')).toBe(0);
|
|
144
|
+
expect(checkIgnore('.totem/artifacts/panels/x.json')).toBe(0);
|
|
145
|
+
expect(checkIgnore('.totem/artifacts/verdicts/x.json')).toBe(0);
|
|
146
|
+
});
|
|
147
|
+
it("this repo's config never softens the CI arm: hooks.legsOwed.enforce is not 'advisory' here", () => {
|
|
148
|
+
// The gate reads the knob in CI too, so `enforce: 'advisory'` would turn the
|
|
149
|
+
// hard step into a green no-op while the row's presence checks still read
|
|
150
|
+
// arm (a) as adopted (the leg's F5; Greptile on mmnto-ai/totem#2772). A repo
|
|
151
|
+
// adopting the CI arm leaves the knob unset or sets 'block'; this pins ours.
|
|
152
|
+
const config = fs.readFileSync(path.join(REPO_ROOT, 'totem.config.ts'), 'utf-8');
|
|
153
|
+
expect(config).not.toMatch(/enforce\s*:\s*['"]advisory['"]/);
|
|
154
|
+
});
|
|
155
|
+
it('the lint workflow runs the built gate as a hard step before the --depth=1 fetch', () => {
|
|
156
|
+
const workflow = readLintWorkflow();
|
|
157
|
+
const gateIdx = workflow.indexOf('node packages/cli/dist/index.js legs gate');
|
|
158
|
+
// The fetch COMMAND, not the flag: the gate step's own comment names
|
|
159
|
+
// `--depth=1` while explaining why it runs first.
|
|
160
|
+
const shallowIdx = workflow.indexOf('git fetch origin "$BASE_REF" --depth=1');
|
|
161
|
+
expect(gateIdx).toBeGreaterThan(NOT_FOUND);
|
|
162
|
+
expect(shallowIdx).toBeGreaterThan(NOT_FOUND);
|
|
163
|
+
expect(gateIdx).toBeLessThan(shallowIdx);
|
|
164
|
+
// The bin-shim form cannot resolve in a job that builds the CLI it calls.
|
|
165
|
+
expect(workflow).not.toContain('pnpm exec totem legs gate');
|
|
166
|
+
// The WHOLE step, from its name to the next step's: the base fetch precedes
|
|
167
|
+
// the gate inside it, and no continue-on-error sits anywhere in it — a
|
|
168
|
+
// trailing one after `run:` would soften the step just as well.
|
|
169
|
+
const step = gateStepOf(workflow);
|
|
170
|
+
const baseFetchIdx = step.indexOf('git fetch origin "$BASE_REF"');
|
|
171
|
+
expect(baseFetchIdx).toBeGreaterThan(NOT_FOUND);
|
|
172
|
+
expect(baseFetchIdx).toBeLessThan(step.indexOf('node packages/cli/dist/index.js legs gate'));
|
|
173
|
+
expect(step).not.toContain('--depth=1');
|
|
174
|
+
expect(step).not.toContain('continue-on-error');
|
|
175
|
+
// The run block is EXACTLY the base fetch and the bare gate: a `|| true`, a
|
|
176
|
+
// `;` or a trailing `&&` on the gate line would neuter it while every
|
|
177
|
+
// assertion above still passes (the leg's F7 on mmnto-ai/totem#2780).
|
|
178
|
+
expect(runLinesOf(step)).toEqual([
|
|
179
|
+
'git fetch origin "$BASE_REF"',
|
|
180
|
+
'node packages/cli/dist/index.js legs gate',
|
|
181
|
+
]);
|
|
182
|
+
});
|
|
183
|
+
it('the gate step is skipped ONLY for the release train — exact branch name AND same repository AND the release-train diff shape — and either outcome is announced (mmnto-ai/totem#2779)', () => {
|
|
184
|
+
const workflow = readLintWorkflow();
|
|
185
|
+
// The branch SELECTOR is defined ONCE, at job level, and the assertion reads
|
|
186
|
+
// the job header with comments dropped — a `#` decoy carrying the same text
|
|
187
|
+
// must not satisfy it. Both halves are load-bearing: the exact name (a
|
|
188
|
+
// prefix test is widenable by any author; GitHub's `==` and `startsWith`
|
|
189
|
+
// are both case-insensitive, so case is not the distinction) and the same
|
|
190
|
+
// repository (a fork's `head_ref` is the bare branch name).
|
|
191
|
+
const header = lintJobHeaderOf(workflow);
|
|
192
|
+
expect(header).not.toBe('');
|
|
193
|
+
expect(header).toContain("LEGS_GATE_RELEASE_TRAIN: ${{ github.event.pull_request.head.repo.full_name == github.repository && github.head_ref == 'changeset-release/main' }}");
|
|
194
|
+
// The selector only picks the branch. The check step, gated on it, derives
|
|
195
|
+
// the diff's SHAPE and exempts only what the action writes — a deleted
|
|
196
|
+
// .changeset/*.md (never its README), an added or modified
|
|
197
|
+
// packages/<pkg>/CHANGELOG.md (a new package's first release ADDS one:
|
|
198
|
+
// mmnto-ai/totem#2514), a modified packages/<pkg>/package.json — so a
|
|
199
|
+
// writer who pushes anything else onto the release branch meets the gate
|
|
200
|
+
// (Greptile's P1 on mmnto-ai/totem#2780). Every assertion reads the check
|
|
201
|
+
// step's own slice, and the run block is pinned EXACTLY, in order: which
|
|
202
|
+
// branch writes `exempt=true` is the mechanism (swapping the branches
|
|
203
|
+
// passed a looser test — the leg's F3), `set -euo pipefail` under
|
|
204
|
+
// `shell: bash` is what makes a failed diff abort instead of reading as
|
|
205
|
+
// an empty, in-shape list (F2), the whole-line anchors are what keep a
|
|
206
|
+
// whitespace-carrying path out of shape (F4), and every filter consumes
|
|
207
|
+
// its whole input — a `grep -q` under pipefail SIGPIPEs the echo on a
|
|
208
|
+
// large diff and the README guard reads false (pass-4 F1).
|
|
209
|
+
const check = stepNamed(workflow, RELEASE_TRAIN_STEP_NAME);
|
|
210
|
+
expect(check).not.toBe('');
|
|
211
|
+
expect(check).toContain('id: release_train');
|
|
212
|
+
expect(check).toContain('shell: bash');
|
|
213
|
+
expect(ifLinesOf(check)).toEqual(["if: ${{ env.LEGS_GATE_RELEASE_TRAIN == 'true' }}"]);
|
|
214
|
+
// The run block is EXACTLY the base fetch and the script, in that order,
|
|
215
|
+
// under `set -euo pipefail`; the script's own rules are executed case by
|
|
216
|
+
// case in release-train-shape.test.ts, and its whole text is a tracked
|
|
217
|
+
// file, so what this pin buys is that the step runs THAT script and nothing
|
|
218
|
+
// softens or bypasses it here.
|
|
219
|
+
expect(runLinesOf(check)).toEqual([
|
|
220
|
+
'set -euo pipefail',
|
|
221
|
+
'git fetch origin "$BASE_REF"',
|
|
222
|
+
'bash tools/release-train-shape.sh "origin/$BASE_REF"',
|
|
223
|
+
]);
|
|
224
|
+
expect(check).not.toContain('continue-on-error');
|
|
225
|
+
expect(fs.existsSync(path.join(REPO_ROOT, 'tools', 'release-train-shape.sh'))).toBe(true);
|
|
226
|
+
// The gate reads the check's OUTPUT, and exactly that: a skipped check
|
|
227
|
+
// writes no output and '' != 'true' runs the gate — fail-closed. Any other
|
|
228
|
+
// condition — a prefix match, `if: false`, a value the PR author controls —
|
|
229
|
+
// softens the floor while `Totem Lint` stays green, which the
|
|
230
|
+
// `continue-on-error` assertion above cannot see.
|
|
231
|
+
const step = gateStepOf(workflow);
|
|
232
|
+
expect(step).not.toBe('');
|
|
233
|
+
expect(ifLinesOf(step)).toEqual(["if: ${{ steps.release_train.outputs.exempt != 'true' }}"]);
|
|
234
|
+
expect(step).not.toContain('startsWith(');
|
|
235
|
+
// The check precedes the gate — an output read before it is written is ''.
|
|
236
|
+
const checkIdx = workflow.indexOf('- name: ' + RELEASE_TRAIN_STEP_NAME);
|
|
237
|
+
expect(checkIdx).toBeGreaterThan(NOT_FOUND);
|
|
238
|
+
expect(checkIdx).toBeLessThan(workflow.indexOf('- name: ' + GATE_STEP_NAME));
|
|
239
|
+
});
|
|
240
|
+
});
|
|
41
241
|
//# sourceMappingURL=tools-hook-parity.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools-hook-parity.test.js","sourceRoot":"","sources":["../../src/commands/tools-hook-parity.test.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,oBAAoB,CAAC;AAE5B,oFAAoF;AACpF,sFAAsF;AACtF,oFAAoF;AACpF,uFAAuF;AACvF,kFAAkF;AAClF,qFAAqF;AACrF,wEAAwE;AAExE,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC;AAC5F,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;AAEhD,uFAAuF;AACvF,mFAAmF;AACnF,+DAA+D;AAC/D,MAAM,IAAI,GAAG,UAAmB,CAAC;AACjC,qFAAqF;AACrF,kFAAkF;AAClF,MAAM,SAAS,GAAG,QAAQ,CAAC;AAC3B,MAAM,YAAY,GAAG,kBAAkB,CAAC,SAAS,CAAC,CAAC;AACnD,MAAM,MAAM,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,CAAC;AAE9E,SAAS,QAAQ,CAAC,IAAY;IAC5B,OAAO,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;AAC9D,CAAC;AAED,QAAQ,CAAC,2EAA2E,EAAE,GAAG,EAAE;IACzF,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;QACzE,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACrE,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+DAA+D,EAAE,GAAG,EAAE;QACvE,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"tools-hook-parity.test.js","sourceRoot":"","sources":["../../src/commands/tools-hook-parity.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mmnto/cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Totem: local-first toolkit that keeps AI-agent work queryable, enforceable, and derivable as plain files in your codebase",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"smol-toml": "^1.6.1",
|
|
29
29
|
"yaml": "^2.4.0",
|
|
30
30
|
"zod": "^3.24.0",
|
|
31
|
-
"@mmnto/totem": "2.
|
|
31
|
+
"@mmnto/totem": "2.1.0"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@anthropic-ai/sdk": "^0.98.0",
|