mirror of
https://github.com/affaan-m/ECC.git
synced 2026-09-28 12:35:13 +02:00
test(release): cover final review blockers
This commit is contained in:
@@ -86,6 +86,15 @@ for (const workflowPath of workflowPaths) {
|
||||
);
|
||||
});
|
||||
|
||||
test(`${workflowPath} disables generated additions to reviewed release notes`, () => {
|
||||
const publish = jobBlock(source, 'publish');
|
||||
assert.match(
|
||||
publish,
|
||||
/body_path:\s*release_body\.md[\s\S]{0,160}generate_release_notes:\s*false/
|
||||
);
|
||||
assert.doesNotMatch(publish, /generate_release_notes:\s*(?:true|\$\{\{)/);
|
||||
});
|
||||
|
||||
test(`${workflowPath} uploads the one packed tgz as the release artifact`, () => {
|
||||
const verify = jobBlock(source, 'verify', 'lifecycle');
|
||||
const packIndex = verify.indexOf('name: Pack npm artifact');
|
||||
|
||||
@@ -83,6 +83,11 @@ function runTests() {
|
||||
assert.deepStrictEqual(kimi.scopes, [
|
||||
{ id: 'project', targetId: 'kimi', root: './.kimi-code' },
|
||||
]);
|
||||
|
||||
const opencode = getHarnessCapability('opencode');
|
||||
assert.match(opencode.destinationResolution, /OPENCODE_CONFIG_DIR/);
|
||||
assert.match(opencode.destinationResolution, /XDG_CONFIG_HOME/);
|
||||
assert.match(opencode.destinationResolution, /~\/\.config\/opencode/);
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('keeps every advanced target attached to its registered root and scope', () => {
|
||||
|
||||
@@ -68,6 +68,7 @@ try {
|
||||
const first = makePlan(root, 'first-module', 'FIRST.md');
|
||||
const second = makePlan(root, 'second-module', 'SECOND.md');
|
||||
applyInstallPlan(first);
|
||||
fs.writeFileSync(first.operations[0].destinationPath, 'user-modified\n');
|
||||
applyInstallPlan(second);
|
||||
|
||||
const state = readInstallState(first.installStatePath);
|
||||
@@ -79,9 +80,13 @@ try {
|
||||
|
||||
const result = uninstallInstalledStates({ projectRoot: root, targets: ['cursor'] });
|
||||
assert.strictEqual(result.summary.errorCount, 0);
|
||||
assert.ok(!fs.existsSync(first.operations[0].destinationPath));
|
||||
assert.strictEqual(
|
||||
fs.readFileSync(first.operations[0].destinationPath, 'utf8'),
|
||||
'user-modified\n',
|
||||
'selective reinstall must not claim modified retained content'
|
||||
);
|
||||
assert.ok(!fs.existsSync(second.operations[0].destinationPath));
|
||||
console.log(' ✓ selective reinstall preserves cumulative ownership and uninstall removes it');
|
||||
console.log(' ✓ selective reinstall preserves cumulative ownership without claiming user changes');
|
||||
passed += 1;
|
||||
} catch (error) {
|
||||
console.log(` ✗ ${error.message}`);
|
||||
@@ -90,5 +95,38 @@ try {
|
||||
fs.rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
const partialRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'ecc-partial-non-claude-'));
|
||||
try {
|
||||
const copied = makePlan(partialRoot, 'copied-module', 'COPIED.md');
|
||||
const missing = makePlan(partialRoot, 'missing-module', 'MISSING.md');
|
||||
fs.rmSync(missing.operations[0].sourcePath);
|
||||
const partialPlan = {
|
||||
...copied,
|
||||
operations: [copied.operations[0], missing.operations[0]],
|
||||
statePreview: {
|
||||
...copied.statePreview,
|
||||
operations: [copied.operations[0], missing.operations[0]],
|
||||
},
|
||||
};
|
||||
|
||||
assert.throws(() => applyInstallPlan(partialPlan), /ENOENT/);
|
||||
assert.ok(fs.existsSync(copied.operations[0].destinationPath));
|
||||
const checkpoint = readInstallState(copied.installStatePath);
|
||||
assert.ok(checkpoint.operations.some(operation => (
|
||||
operation.destinationPath === copied.operations[0].destinationPath
|
||||
)));
|
||||
|
||||
const result = uninstallInstalledStates({ projectRoot: partialRoot, targets: ['cursor'] });
|
||||
assert.strictEqual(result.summary.errorCount, 0);
|
||||
assert.ok(!fs.existsSync(copied.operations[0].destinationPath));
|
||||
console.log(' ✓ failed non-Claude install checkpoints managed files for uninstall');
|
||||
passed += 1;
|
||||
} catch (error) {
|
||||
console.log(` ✗ ${error.message}`);
|
||||
failed += 1;
|
||||
} finally {
|
||||
fs.rmSync(partialRoot, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
console.log(`\nResults: Passed: ${passed}, Failed: ${failed}`);
|
||||
process.exit(failed > 0 ? 1 : 0);
|
||||
|
||||
@@ -629,8 +629,8 @@ function runTests() {
|
||||
if (test('resolves qwen adapter root and install-state path from home dir', () => {
|
||||
const adapter = getInstallTargetAdapter('qwen');
|
||||
const homeDir = '/Users/example';
|
||||
const root = adapter.resolveRoot({ homeDir });
|
||||
const statePath = adapter.getInstallStatePath({ homeDir });
|
||||
const root = adapter.resolveRoot({ homeDir, env: {} });
|
||||
const statePath = adapter.getInstallStatePath({ homeDir, env: {} });
|
||||
|
||||
assert.strictEqual(adapter.id, 'qwen-home');
|
||||
assert.strictEqual(adapter.target, 'qwen');
|
||||
@@ -639,6 +639,35 @@ function runTests() {
|
||||
assert.strictEqual(statePath, path.join(homeDir, '.qwen', 'ecc-install-state.json'));
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('opencode adapter honors config overrides in priority order', () => {
|
||||
const adapter = getInstallTargetAdapter('opencode');
|
||||
const homeDir = '/Users/example';
|
||||
const xdgRoot = path.join(homeDir, 'xdg');
|
||||
const explicitRoot = path.join(homeDir, 'custom-opencode');
|
||||
|
||||
assert.strictEqual(
|
||||
adapter.resolveRoot({
|
||||
homeDir,
|
||||
env: {
|
||||
XDG_CONFIG_HOME: xdgRoot,
|
||||
OPENCODE_CONFIG_DIR: explicitRoot,
|
||||
},
|
||||
}),
|
||||
explicitRoot
|
||||
);
|
||||
assert.strictEqual(
|
||||
adapter.resolveRoot({ homeDir, env: { XDG_CONFIG_HOME: xdgRoot } }),
|
||||
path.join(xdgRoot, 'opencode')
|
||||
);
|
||||
assert.strictEqual(
|
||||
adapter.getInstallStatePath({
|
||||
homeDir,
|
||||
env: { OPENCODE_CONFIG_DIR: explicitRoot },
|
||||
}),
|
||||
path.join(explicitRoot, 'ecc-install-state.json')
|
||||
);
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('qwen adapter supports lookup by target and adapter id', () => {
|
||||
const byTarget = getInstallTargetAdapter('qwen');
|
||||
const byId = getInstallTargetAdapter('qwen-home');
|
||||
|
||||
@@ -184,6 +184,38 @@ test('opencode reader splits command array and reads environment', () => {
|
||||
assert.strictEqual(records.find(r => r.name === 'disabledtool').enabled, false);
|
||||
});
|
||||
|
||||
test('opencode reader honors OPENCODE_CONFIG_DIR before XDG_CONFIG_HOME', () => {
|
||||
const home = tmpHome();
|
||||
const explicitRoot = path.join(home, 'explicit-opencode');
|
||||
const xdgRoot = path.join(home, 'xdg');
|
||||
for (const root of [explicitRoot, path.join(xdgRoot, 'opencode')]) {
|
||||
fs.mkdirSync(root, { recursive: true });
|
||||
fs.writeFileSync(path.join(root, 'opencode.json'), JSON.stringify({
|
||||
mcp: {
|
||||
[root === explicitRoot ? 'explicit' : 'xdg']: {
|
||||
type: 'local',
|
||||
command: ['node'],
|
||||
},
|
||||
},
|
||||
}), 'utf8');
|
||||
}
|
||||
|
||||
const explicit = readOpencodeMcp({
|
||||
homeDir: home,
|
||||
env: {
|
||||
OPENCODE_CONFIG_DIR: explicitRoot,
|
||||
XDG_CONFIG_HOME: xdgRoot,
|
||||
},
|
||||
});
|
||||
assert.deepStrictEqual(explicit.map(record => record.name), ['explicit']);
|
||||
|
||||
const xdg = readOpencodeMcp({
|
||||
homeDir: home,
|
||||
env: { XDG_CONFIG_HOME: xdgRoot },
|
||||
});
|
||||
assert.deepStrictEqual(xdg.map(record => record.name), ['xdg']);
|
||||
});
|
||||
|
||||
test('collectMcpInventory merges harnesses, detects fragmentation + drift, redacts secrets', () => {
|
||||
const home = tmpHome();
|
||||
// claude + opencode agree on github (consistent); codex github uses a
|
||||
|
||||
@@ -66,6 +66,11 @@ for (const workflow of [
|
||||
assert.match(content, /docs\/releases\/\$\{RELEASE_VERSION\}\/release-notes\.md/);
|
||||
});
|
||||
|
||||
test(`${workflow} publishes only the reviewed release notes`, () => {
|
||||
assert.match(content, /body_path:\s*release_body\.md[\s\S]{0,160}generate_release_notes:\s*false/);
|
||||
assert.doesNotMatch(content, /generate_release_notes:\s*(?:true|\$\{\{)/);
|
||||
});
|
||||
|
||||
test(`${workflow} publishes new tag versions to npm`, () => {
|
||||
assert.match(content, /ECC_RELEASE_PACKAGE:\s*\$\{\{ needs\.verify\.outputs\.package_file \}\}/);
|
||||
assert.match(content, /npm publish "\.\/\$\{ECC_RELEASE_PACKAGE\}" --access public --provenance/);
|
||||
@@ -85,6 +90,10 @@ for (const workflow of [
|
||||
});
|
||||
}
|
||||
|
||||
test('reusable release workflow has no generated-notes input', () => {
|
||||
assert.doesNotMatch(load('.github/workflows/reusable-release.yml'), /generate-notes:/);
|
||||
});
|
||||
|
||||
if (failed > 0) {
|
||||
console.log(`\nFailed: ${failed}`);
|
||||
process.exit(1);
|
||||
|
||||
Reference in New Issue
Block a user