mirror of
https://github.com/affaan-m/ECC.git
synced 2026-09-06 17:57:52 +02:00
test(release): add ECC 2.2 readiness regressions
This commit is contained in:
@@ -161,6 +161,15 @@ test('packed lifecycle invokes installed public bins, including setup help', ()
|
||||
assert.doesNotMatch(lifecycleRunnerSource, /node_modules.*scripts.*ecc\.js/);
|
||||
});
|
||||
|
||||
test('packed lifecycle validates canonical Antigravity and OpenCode installs', () => {
|
||||
assert.match(lifecycleRunnerSource, /'--target', 'antigravity'/);
|
||||
assert.match(lifecycleRunnerSource, /path\.join\(projectDir, '\.agents'\)/);
|
||||
assert.match(lifecycleRunnerSource, /'--target', 'opencode'/);
|
||||
assert.match(lifecycleRunnerSource, /path\.join\(homeDir, '\.config', 'opencode'\)/);
|
||||
assert.match(lifecycleRunnerSource, /doctor.*antigravity/s);
|
||||
assert.match(lifecycleRunnerSource, /doctor.*opencode/s);
|
||||
});
|
||||
|
||||
test('packed lifecycle installs and verifies the opt-in Ito distribution surface', () => {
|
||||
assert.match(
|
||||
lifecycleRunnerSource,
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
'use strict';
|
||||
|
||||
const assert = require('assert');
|
||||
const fs = require('fs');
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
|
||||
const { applyInstallPlan } = require('../../scripts/lib/install/apply');
|
||||
const { readInstallState } = require('../../scripts/lib/install-state');
|
||||
const { uninstallInstalledStates } = require('../../scripts/lib/install-lifecycle');
|
||||
|
||||
function makePlan(root, moduleId, fileName) {
|
||||
const targetRoot = path.join(root, '.cursor');
|
||||
const installStatePath = path.join(targetRoot, 'ecc-install-state.json');
|
||||
const sourcePath = path.join(root, 'source', moduleId, fileName);
|
||||
const destinationPath = path.join(targetRoot, 'skills', moduleId, fileName);
|
||||
fs.mkdirSync(path.dirname(sourcePath), { recursive: true });
|
||||
fs.writeFileSync(sourcePath, `${moduleId}\n`);
|
||||
const operation = {
|
||||
kind: 'copy-file',
|
||||
moduleId,
|
||||
sourcePath,
|
||||
sourceRelativePath: path.join('skills', moduleId, fileName),
|
||||
destinationPath,
|
||||
strategy: 'preserve-relative-path',
|
||||
ownership: 'managed',
|
||||
scaffoldOnly: false,
|
||||
};
|
||||
return {
|
||||
mode: 'manifest',
|
||||
target: 'cursor',
|
||||
adapter: { id: 'cursor-project', target: 'cursor', kind: 'project' },
|
||||
targetRoot,
|
||||
installRoot: targetRoot,
|
||||
installStatePath,
|
||||
operations: [operation],
|
||||
statePreview: {
|
||||
schemaVersion: 'ecc.install.v1',
|
||||
installedAt: new Date().toISOString(),
|
||||
target: {
|
||||
id: 'cursor-project',
|
||||
target: 'cursor',
|
||||
kind: 'project',
|
||||
root: targetRoot,
|
||||
installStatePath,
|
||||
},
|
||||
request: {
|
||||
profile: null,
|
||||
modules: [moduleId],
|
||||
includeComponents: [],
|
||||
excludeComponents: [],
|
||||
legacyLanguages: [],
|
||||
legacyMode: false,
|
||||
},
|
||||
resolution: { selectedModules: [moduleId], skippedModules: [] },
|
||||
source: { manifestVersion: 1 },
|
||||
operations: [operation],
|
||||
},
|
||||
warnings: [],
|
||||
};
|
||||
}
|
||||
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'ecc-selective-reinstall-'));
|
||||
try {
|
||||
const first = makePlan(root, 'first-module', 'FIRST.md');
|
||||
const second = makePlan(root, 'second-module', 'SECOND.md');
|
||||
applyInstallPlan(first);
|
||||
applyInstallPlan(second);
|
||||
|
||||
const state = readInstallState(first.installStatePath);
|
||||
assert.deepStrictEqual(
|
||||
new Set(state.operations.map(operation => operation.moduleId)),
|
||||
new Set(['first-module', 'second-module']),
|
||||
'a later selective install must preserve earlier managed ownership'
|
||||
);
|
||||
|
||||
const result = uninstallInstalledStates({ projectRoot: root, targets: ['cursor'] });
|
||||
assert.strictEqual(result.summary.errorCount, 0);
|
||||
assert.ok(!fs.existsSync(first.operations[0].destinationPath));
|
||||
assert.ok(!fs.existsSync(second.operations[0].destinationPath));
|
||||
console.log(' ✓ selective reinstall preserves cumulative ownership and uninstall removes it');
|
||||
} finally {
|
||||
fs.rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
@@ -1073,8 +1073,11 @@ function runTests() {
|
||||
assert.strictEqual(adapter.id, 'opencode-home');
|
||||
assert.strictEqual(adapter.target, 'opencode');
|
||||
assert.strictEqual(adapter.kind, 'home');
|
||||
assert.strictEqual(root, path.join(homeDir, '.opencode'));
|
||||
assert.strictEqual(statePath, path.join(homeDir, '.opencode', 'ecc-install-state.json'));
|
||||
assert.strictEqual(root, path.join(homeDir, '.config', 'opencode'));
|
||||
assert.strictEqual(
|
||||
statePath,
|
||||
path.join(homeDir, '.config', 'opencode', 'ecc-install-state.json')
|
||||
);
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('opencode adapter validate reports an error when compiled plugin is missing', () => {
|
||||
|
||||
@@ -175,6 +175,27 @@ function writeManagedState(plan, overrides = {}) {
|
||||
}
|
||||
});
|
||||
|
||||
await test('rejects managed preflight plans without an install-state path', () => {
|
||||
const root = tempDir('ecc-guided-missing-state-');
|
||||
try {
|
||||
const source = path.join(root, 'source.md');
|
||||
writeFile(source, 'ecc\n');
|
||||
const plan = managedPlan(root, [{
|
||||
kind: 'copy-file',
|
||||
sourcePath: source,
|
||||
destinationPath: path.join(root, 'AGENTS.md'),
|
||||
}]);
|
||||
delete plan.installStatePath;
|
||||
|
||||
assert.throws(
|
||||
() => preflightManagedPlan(plan),
|
||||
/install-state path is required/i
|
||||
);
|
||||
} finally {
|
||||
fs.rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
await test('rejects valid install-state from a different managed target identity', () => {
|
||||
const root = tempDir('ecc-guided-forged-target-');
|
||||
try {
|
||||
|
||||
@@ -201,6 +201,7 @@ function main() {
|
||||
"schemas/install-state.schema.json",
|
||||
"schemas/memory.schema.json",
|
||||
"skills/backend-patterns/SKILL.md",
|
||||
"skills/skill-comply/SKILL.md",
|
||||
"skills/unified-memory/SKILL.md",
|
||||
]) {
|
||||
assert.ok(
|
||||
@@ -214,7 +215,6 @@ function main() {
|
||||
"examples/CLAUDE.md",
|
||||
"plugins/README.md",
|
||||
"scripts/ci/catalog.js",
|
||||
"skills/skill-comply/SKILL.md",
|
||||
]) {
|
||||
assert.ok(
|
||||
!packagedPaths.has(excludedPath),
|
||||
@@ -231,6 +231,10 @@ function main() {
|
||||
!/\.py[cod]$/.test(packagedPath),
|
||||
`npm pack should not include Python bytecode file ${packagedPath}`
|
||||
)
|
||||
assert.ok(
|
||||
!packagedPath.includes(".pytest_cache/"),
|
||||
`npm pack should not include pytest cache path ${packagedPath}`
|
||||
)
|
||||
}
|
||||
}],
|
||||
]
|
||||
|
||||
@@ -51,6 +51,18 @@ for (const workflow of [
|
||||
test(`${workflow} checks whether the tagged npm version already exists`, () => {
|
||||
assert.match(content, /Check npm publish state/);
|
||||
assert.match(content, /npm view "\$\{PACKAGE_NAME\}@\$\{PACKAGE_VERSION\}" version/);
|
||||
assert.match(content, /E404/);
|
||||
assert.match(content, /npm registry lookup failed/i);
|
||||
});
|
||||
|
||||
test(`${workflow} requires the release commit to equal origin main`, () => {
|
||||
assert.match(content, /git fetch origin main --no-tags/);
|
||||
assert.match(content, /git rev-parse origin\/main/);
|
||||
assert.match(content, /release commit.*origin\/main/i);
|
||||
});
|
||||
|
||||
test(`${workflow} uses the reviewed 2.2 release notes`, () => {
|
||||
assert.match(content, /docs\/releases\/2\.2\.0\/RELEASE_NOTES\.md/);
|
||||
});
|
||||
|
||||
test(`${workflow} publishes new tag versions to npm`, () => {
|
||||
@@ -59,15 +71,15 @@ for (const workflow of [
|
||||
assert.match(content, /NODE_AUTH_TOKEN:\s*\$\{\{\s*secrets\.NPM_TOKEN\s*\}\}/);
|
||||
});
|
||||
|
||||
test(`${workflow} creates the GitHub Release before publishing to npm`, () => {
|
||||
test(`${workflow} publishes to npm before creating the GitHub Release`, () => {
|
||||
const releaseIndex = content.indexOf('name: Create GitHub Release');
|
||||
const publishIndex = content.indexOf('name: Publish npm package');
|
||||
|
||||
assert.ok(releaseIndex >= 0, `${workflow} should create a GitHub Release`);
|
||||
assert.ok(publishIndex >= 0, `${workflow} should publish the npm package`);
|
||||
assert.ok(
|
||||
releaseIndex < publishIndex,
|
||||
`${workflow} should not publish to npm until GitHub Release creation has succeeded`
|
||||
publishIndex < releaseIndex,
|
||||
`${workflow} should publish the verified package before creating the GitHub Release`
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user