Files
wehub-resource-sync 426e9eeabd
Voice Workbench / headless workbench (mocked backends) (push) Has been cancelled
Voice Workbench / real acoustic lane (nightly, provisioned only) (push) Has been cancelled
ci / test (push) Has been cancelled
ci / lint-and-format (push) Has been cancelled
ci / build (push) Has been cancelled
ci / dev-startup (push) Has been cancelled
gitleaks / gitleaks (push) Has been cancelled
Markdown Links / Relative Markdown Links (push) Has been cancelled
Quality (Extended) / Homepage Build (PR smoke) (push) Has been cancelled
Quality (Extended) / Comment-only diff guard (push) Has been cancelled
Quality (Extended) / Format + Type Safety Ratchet (push) Has been cancelled
Quality (Extended) / Develop Gate (secret scan + UI determinism) (push) Has been cancelled
Quality (Extended) / Develop Gate (lint) (push) Has been cancelled
Chat shell gestures / Chat shell gesture + parity e2e (push) Has been cancelled
Cloud Gateway Discord / Test (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx @biomejs/biome check packages/lifeops-bench/src, benchmark-lint) (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx vitest run --config packages/lifeops-bench/vitest.config.ts --root packages/lifeops-bench --passWithNoTests, benchmark-tests) (push) Has been cancelled
Build Agent Image / build-and-push (push) Has been cancelled
Dev Smoke / bun run dev onboarding chat (push) Has been cancelled
Dev Smoke / Vite HMR dependency-level smoke (push) Has been cancelled
Electrobun Submodule Guard / electrobun gitlink is fetchable (push) Has been cancelled
Publish @elizaos/example-code / check_npm (push) Has been cancelled
Publish @elizaos/example-code / publish_npm (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / verify_version (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / publish_npm (push) Has been cancelled
Sandbox Live Smoke / Sandbox live smoke (push) Has been cancelled
Snap Build & Test / Build Snap (amd64) (push) Has been cancelled
Snap Build & Test / Build Snap (arm64) (push) Has been cancelled
Test Packaging / elizaos CLI global-install smoke (node + bun) (push) Has been cancelled
Cloud Gateway Webhook / Test (push) Has been cancelled
Cloud Tests / lint-and-types (push) Has been cancelled
Cloud Tests / unit-tests (push) Has been cancelled
Cloud Tests / integration-tests (push) Has been cancelled
Cloud Tests / e2e-tests (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Apps Worker (Product 2) / Determine environment (push) Has been cancelled
Deploy Apps Worker (Product 2) / Deploy apps worker to apps-control host (${{ needs.determine-env.outputs.environment }}) (push) Has been cancelled
Deploy Eliza Provisioning Worker / Determine environment (push) Has been cancelled
Deploy Eliza Provisioning Worker / Deploy worker to Hetzner host (${{ needs.determine-env.outputs.environment }} @ ${{ needs.determine-env.outputs.deployment_sha }}) (push) Has been cancelled
Dev Smoke / Classify changed paths (push) Has been cancelled
supply-chain / sbom (push) Has been cancelled
supply-chain / vulnerability-scan (push) Has been cancelled
Build, Push & Deploy to Phala Cloud / build-and-push (push) Has been cancelled
Test Packaging / Validate Packaging Configs (push) Has been cancelled
Test Packaging / Build & Test PyPI Package (push) Has been cancelled
Test Packaging / PyPI on Python ${{ matrix.python }} (push) Has been cancelled
Test Packaging / Pack & Test JS Tarballs (push) Has been cancelled
UI Fixture E2E / ui-fixture-e2e (push) Has been cancelled
UI Fixture E2E / fixture-e2e (push) Has been cancelled
UI Story Gate / story-gate (push) Has been cancelled
vault-ci / test (macos-latest) (push) Has been cancelled
vault-ci / test (ubuntu-latest) (push) Has been cancelled
vault-ci / test (windows-latest) (push) Has been cancelled
vault-ci / app-core wiring tests (push) Has been cancelled
verify-patches / verify patches/CHECKSUMS.sha256 (push) Has been cancelled
Voice Benchmark Smoke / voice-emotion fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voiceagentbench fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench-quality unit smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench TypeScript unit (no audio) (push) Has been cancelled
Voice Benchmark Smoke / voice bench smoke summary (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/app-core test bun run --cwd packages/elizaos test bun run --cwd packages/cloud/shared test], app-and-cli) (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/scenario-runner test bun run --cwd packages/vault test bun run --cwd packages/security test bun run --cwd plugins/plugin-coding-tools test], framework-packages) (push) Has been cancelled
Windows CI / windows ([bun run --cwd plugins/plugin-elizacloud test bun run --cwd plugins/plugin-discord test bun run --cwd plugins/plugin-anthropic test bun run --cwd plugins/plugin-openai test bun run --cwd plugins/plugin-app-control test bun run --cwd plugins/pl… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run build --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/agent --concurrency=4 node packages/scripts/run-bash-linux-only.mjs scripts/verify-riscv64-buildpaths.sh node packages/scripts/run… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run typecheck --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/cloud-shared --concurrency=4 bun run --cwd packages/core test bun run --cwd packages/shared test], core-runtime, 75) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:43:05 +08:00

273 lines
9.0 KiB
TypeScript

/**
* Unit + live-repo-parity tests for the workspace/submodule discovery seam
* (packages/scripts/lib/workspaces.mjs). Synthetic cases exercise glob
* semantics against throwaway temp trees; parity cases assert the lib agrees
* with the real repo's package.json and .gitmodules. Deterministic, no network.
*/
import { afterEach, describe, expect, test } from "bun:test";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { fileURLToPath } from "node:url";
import {
expandWorkspaceGlobs,
listPackages,
listSubmodules,
listWorkspaceDirs,
} from "../lib/workspaces.mjs";
const REPO_ROOT = path.resolve(
path.dirname(fileURLToPath(import.meta.url)),
"../../..",
);
const tempRoots: string[] = [];
afterEach(() => {
while (tempRoots.length > 0) {
const root = tempRoots.pop();
if (root) fs.rmSync(root, { recursive: true, force: true });
}
});
function makeRepo(): string {
const root = fs.mkdtempSync(path.join(os.tmpdir(), "workspaces-lib-"));
tempRoots.push(root);
return root;
}
function writeFile(root: string, relativePath: string, content: string): void {
const filePath = path.join(root, relativePath);
fs.mkdirSync(path.dirname(filePath), { recursive: true });
fs.writeFileSync(filePath, content);
}
function writePackage(root: string, dir: string, name?: string): void {
writeFile(
root,
path.join(dir, "package.json"),
JSON.stringify(name ? { name } : {}, null, 2),
);
}
function writeRootPackage(root: string, workspaces: string[]): void {
writeFile(
root,
"package.json",
JSON.stringify({ type: "module", workspaces }, null, 2),
);
}
describe("expandWorkspaceGlobs — glob semantics", () => {
test("simple `*` matches one segment of directories", () => {
const root = makeRepo();
fs.mkdirSync(path.join(root, "packages/a"), { recursive: true });
fs.mkdirSync(path.join(root, "packages/b"), { recursive: true });
fs.mkdirSync(path.join(root, "packages/a/nested"), { recursive: true });
const dirs = expandWorkspaceGlobs(["packages/*"], { repoRoot: root });
expect(dirs).toEqual(["packages/a", "packages/b"]);
});
test("nested `*/*` matches exactly two segments deep", () => {
const root = makeRepo();
fs.mkdirSync(path.join(root, "packages/group/one"), { recursive: true });
fs.mkdirSync(path.join(root, "packages/group/two"), { recursive: true });
fs.mkdirSync(path.join(root, "packages/solo"), { recursive: true });
const dirs = expandWorkspaceGlobs(["packages/*/*"], { repoRoot: root });
expect(dirs).toEqual(["packages/group/one", "packages/group/two"]);
});
test("`**` matches any depth including the base directory", () => {
const root = makeRepo();
fs.mkdirSync(path.join(root, "packages/a/deep/deeper"), {
recursive: true,
});
fs.mkdirSync(path.join(root, "packages/b"), { recursive: true });
const dirs = expandWorkspaceGlobs(["packages/**"], { repoRoot: root });
expect(dirs).toEqual([
"packages",
"packages/a",
"packages/a/deep",
"packages/a/deep/deeper",
"packages/b",
]);
});
test("`*` skips hidden and build-output dirs (e.g. a stray `.next` marker)", () => {
const root = makeRepo();
fs.mkdirSync(path.join(root, "examples/real"), { recursive: true });
// A Next.js build dir carries a `{"type":"commonjs"}` package.json marker;
// it is not a workspace member and must not be matched by a `*` segment.
fs.mkdirSync(path.join(root, "examples/real/.next"), { recursive: true });
fs.mkdirSync(path.join(root, "examples/real/dist"), { recursive: true });
expect(expandWorkspaceGlobs(["examples/*"], { repoRoot: root })).toEqual([
"examples/real",
]);
expect(expandWorkspaceGlobs(["examples/*/*"], { repoRoot: root })).toEqual(
[],
);
});
test("negation subtracts an earlier match (exclude-wins)", () => {
const root = makeRepo();
fs.mkdirSync(path.join(root, "packages/keep"), { recursive: true });
fs.mkdirSync(path.join(root, "packages/feed"), { recursive: true });
const dirs = expandWorkspaceGlobs(["packages/*", "!packages/feed"], {
repoRoot: root,
});
expect(dirs).toEqual(["packages/keep"]);
});
test("later positive pattern re-adds a previously negated dir (last-match-wins)", () => {
const root = makeRepo();
fs.mkdirSync(path.join(root, "packages/feed"), { recursive: true });
const dirs = expandWorkspaceGlobs(
["packages/*", "!packages/feed", "packages/feed"],
{ repoRoot: root },
);
expect(dirs).toEqual(["packages/feed"]);
});
});
describe("listWorkspaceDirs — package.json filtering", () => {
test("keeps only directories that contain a package.json", () => {
const root = makeRepo();
writeRootPackage(root, ["packages/*"]);
writePackage(root, "packages/real", "@x/real");
fs.mkdirSync(path.join(root, "packages/empty"), { recursive: true });
expect(listWorkspaceDirs({ repoRoot: root })).toEqual(["packages/real"]);
});
test("hidden and build dirs are skipped by `**` traversal", () => {
const root = makeRepo();
writeRootPackage(root, ["packages/**"]);
writePackage(root, "packages", "@x/packages-root");
writePackage(root, "packages/live", "@x/live");
writePackage(root, "packages/live/node_modules/dep", "dep");
writePackage(root, "packages/live/dist", "dist-pkg");
writePackage(root, "packages/.hidden", "hidden-pkg");
expect(listWorkspaceDirs({ repoRoot: root })).toEqual([
"packages",
"packages/live",
]);
});
test("negation excludes a workspace with a package.json", () => {
const root = makeRepo();
writeRootPackage(root, ["packages/*", "!packages/feed"]);
writePackage(root, "packages/core", "@x/core");
writePackage(root, "packages/feed", "@x/feed");
expect(listWorkspaceDirs({ repoRoot: root })).toEqual(["packages/core"]);
});
});
describe("listPackages — name mapping", () => {
test("maps each workspace dir to { name, dir, packageJson }", () => {
const root = makeRepo();
writeRootPackage(root, ["packages/*"]);
writePackage(root, "packages/alpha", "@x/alpha");
writePackage(root, "packages/beta");
const packages = listPackages({ repoRoot: root });
expect(packages).toEqual([
{
name: "@x/alpha",
dir: "packages/alpha",
packageJson: { name: "@x/alpha" },
},
{ name: undefined, dir: "packages/beta", packageJson: {} },
]);
});
});
describe("listSubmodules — .gitmodules parsing", () => {
test("parses path/url/branch and marks initialization state", () => {
const root = makeRepo();
writeFile(
root,
".gitmodules",
[
'[submodule "vendor/checked-out"]',
"\t# a comment line that must be ignored",
"\tpath = vendor/checked-out",
"\turl = https://example.com/a.git",
"\tbranch = main",
"",
'[submodule "vendor/placeholder"]',
"\tpath = vendor/placeholder",
"\turl = https://example.com/b.git",
"",
].join("\n"),
);
writeFile(root, "vendor/checked-out/.git", "gitdir: ../../.git/modules/x");
fs.mkdirSync(path.join(root, "vendor/placeholder"), { recursive: true });
expect(listSubmodules({ repoRoot: root })).toEqual([
{
path: "vendor/checked-out",
url: "https://example.com/a.git",
branch: "main",
initialized: true,
},
{
path: "vendor/placeholder",
url: "https://example.com/b.git",
branch: undefined,
initialized: false,
},
]);
});
test("returns an empty list when .gitmodules is absent", () => {
const root = makeRepo();
expect(listSubmodules({ repoRoot: root })).toEqual([]);
});
});
describe("live-repo parity", () => {
test("plugin-sql appears in listPackages with a matching dir", () => {
const pkg = listPackages({ repoRoot: REPO_ROOT }).find(
(p) => p.name === "@elizaos/plugin-sql",
);
expect(pkg).toBeDefined();
expect(pkg?.dir).toBe("plugins/plugin-sql");
});
test("packages/feed is excluded from listWorkspaceDirs", () => {
const dirs = listWorkspaceDirs({ repoRoot: REPO_ROOT });
expect(dirs).not.toContain("packages/feed");
});
test("no duplicate package names across the workspace", () => {
const names = listPackages({ repoRoot: REPO_ROOT })
.map((p) => p.name)
.filter((name): name is string => Boolean(name));
const seen = new Map<string, number>();
for (const name of names) seen.set(name, (seen.get(name) ?? 0) + 1);
const duplicates = [...seen.entries()].filter(([, count]) => count > 1);
expect(duplicates).toEqual([]);
});
test("listSubmodules entries match .gitmodules declarations", () => {
const gitmodules = fs.readFileSync(
path.join(REPO_ROOT, ".gitmodules"),
"utf8",
);
const declaredPaths = [...gitmodules.matchAll(/^\s*path\s*=\s*(.+)$/gm)].map(
(m) => m[1].trim(),
);
const libPaths = listSubmodules({ repoRoot: REPO_ROOT }).map((s) => s.path);
expect(libPaths.sort()).toEqual([...declaredPaths].sort());
});
});