diff --git a/packages/turbo-workspaces/__tests__/managers.test.ts b/packages/turbo-workspaces/__tests__/managers.test.ts index 73c50735a46fc..280290395b3bd 100644 --- a/packages/turbo-workspaces/__tests__/managers.test.ts +++ b/packages/turbo-workspaces/__tests__/managers.test.ts @@ -114,7 +114,7 @@ describe("managers", () => { expect(packageJson?.packageManager?.split("@")[0]).toEqual( fixtureManager ); - if (fixtureType === "basic") { + if (fixtureType === "monorepo") { if (fixtureManager === "pnpm") { expect(project.paths.workspaceConfig).toBeDefined(); if (project.paths.workspaceConfig) { @@ -135,7 +135,7 @@ describe("managers", () => { } } else { expect(packageJson?.packageManager).toBeUndefined(); - if (fixtureType === "basic") { + if (fixtureType === "monorepo") { expect(packageJson?.workspaces).toBeUndefined(); if (fixtureManager === "pnpm") { @@ -223,6 +223,86 @@ describe("managers", () => { ); }); + describe("read - alternate workspace format", () => { + test.each(generateReadMatrix())( + "reads $toManager workspaces using alternate format from $fixtureManager $fixtureType project - (shouldThrow: $shouldThrow)", + async ({ fixtureManager, fixtureType, toManager, shouldThrow }) => { + const { root, directoryName, readJson, write } = useFixture({ + fixture: `./${fixtureManager}/${fixtureType}`, + }); + + // alter the fixtures package.json to use the alternate workspace format + const packageJsonPath = path.join(root, "package.json"); + const packageJson = readJson(packageJsonPath); + if (packageJson && packageJson.workspaces) { + packageJson.workspaces = { + packages: packageJson.workspaces as Array, + }; + write(packageJsonPath, JSON.stringify(packageJson, null, 2)); + } + + const read = async () => + MANAGERS[toManager].read({ workspaceRoot: root }); + if (shouldThrow) { + if (toManager === "pnpm") { + expect(read).rejects.toThrow(`Not a pnpm project`); + } else if (toManager === "yarn") { + expect(read).rejects.toThrow(`Not a yarn project`); + } else if (toManager === "npm") { + expect(read).rejects.toThrow(`Not an npm project`); + } + return; + } + const project = await MANAGERS[toManager].read({ + workspaceRoot: root, + }); + + expect(project.name).toEqual( + fixtureType === "monorepo" ? `${toManager}-workspaces` : toManager + ); + expect(project.packageManager).toEqual(toManager); + + // paths + expect(project.paths.root).toMatch( + new RegExp(`^.*\/${directoryName}$`) + ); + expect(project.paths.packageJson).toMatch( + new RegExp(`^.*\/${directoryName}\/package.json$`) + ); + + if (fixtureManager === "pnpm") { + new RegExp(`^.*\/${directoryName}\/pnpm-lock.yaml$`); + } else if (fixtureManager === "yarn") { + new RegExp(`^.*\/${directoryName}\/yarn.lock$`); + } else if (fixtureManager === "npm") { + new RegExp(`^.*\/${directoryName}\/package-lock.json$`); + } else { + throw new Error("Invalid fixtureManager"); + } + + if (fixtureType === "non-monorepo") { + expect(project.workspaceData.workspaces).toEqual([]); + expect(project.workspaceData.globs).toEqual([]); + } else { + expect(project.workspaceData.globs).toEqual(["apps/*", "packages/*"]); + project.workspaceData.workspaces.forEach((workspace) => { + const type = ["web", "docs"].includes(workspace.name) + ? "apps" + : "packages"; + expect(workspace.paths.packageJson).toMatch( + new RegExp( + `^.*${directoryName}\/${type}\/${workspace.name}\/package.json$` + ) + ); + expect(workspace.paths.root).toMatch( + new RegExp(`^.*${directoryName}\/${type}\/${workspace.name}$`) + ); + }); + } + } + ); + }); + describe("clean", () => { test.each(generateCleanMatrix())( "cleans $fixtureManager $fixtureType project (interactive=$interactive, dry=$dry)", diff --git a/packages/turbo-workspaces/__tests__/test-utils.ts b/packages/turbo-workspaces/__tests__/test-utils.ts index 4d6c7c91446ed..3cbd1410196a3 100644 --- a/packages/turbo-workspaces/__tests__/test-utils.ts +++ b/packages/turbo-workspaces/__tests__/test-utils.ts @@ -1,7 +1,10 @@ import { PackageManager } from "../src/types"; const PACKAGE_MANAGERS: Array = ["pnpm", "npm", "yarn"]; -const REPO_TYPES = ["monorepo", "non-monorepo"]; +const REPO_TYPES: Array<"monorepo" | "non-monorepo"> = [ + "monorepo", + "non-monorepo", +]; const BOOLEAN_OPTIONS = [true, false]; export function generateConvertMatrix() { diff --git a/packages/turbo-workspaces/jest.config.js b/packages/turbo-workspaces/jest.config.js index e9a8cc9265452..8d3a0bc2ed622 100644 --- a/packages/turbo-workspaces/jest.config.js +++ b/packages/turbo-workspaces/jest.config.js @@ -9,10 +9,10 @@ module.exports = { collectCoverage: true, coverageThreshold: { global: { - branches: 83, + branches: 82, functions: 87, - lines: 93, - statements: 93, + lines: 92, + statements: 92, }, }, verbose: process.env.RUNNER_DEBUG === "1", diff --git a/packages/turbo-workspaces/src/managers/npm.ts b/packages/turbo-workspaces/src/managers/npm.ts index 26fd76a1f7aad..c480a274e1128 100644 --- a/packages/turbo-workspaces/src/managers/npm.ts +++ b/packages/turbo-workspaces/src/managers/npm.ts @@ -19,6 +19,7 @@ import { expandWorkspaces, getWorkspacePackageManager, expandPaths, + parseWorkspacePackages, } from "../utils"; /** @@ -48,6 +49,9 @@ async function read(args: ReadArgs): Promise { const packageJson = getPackageJson(args); const { name, description } = getWorkspaceInfo(args); + const workspaceGlobs = parseWorkspacePackages({ + workspaces: packageJson.workspaces, + }); return { name, description, @@ -57,9 +61,9 @@ async function read(args: ReadArgs): Promise { lockFile: "package-lock.json", }), workspaceData: { - globs: packageJson.workspaces || [], + globs: workspaceGlobs, workspaces: expandWorkspaces({ - workspaceGlobs: packageJson.workspaces, + workspaceGlobs: workspaceGlobs, ...args, }), }, diff --git a/packages/turbo-workspaces/src/managers/yarn.ts b/packages/turbo-workspaces/src/managers/yarn.ts index 9bef53f1b8a93..a3e8b236fd2ba 100644 --- a/packages/turbo-workspaces/src/managers/yarn.ts +++ b/packages/turbo-workspaces/src/managers/yarn.ts @@ -18,6 +18,7 @@ import { expandPaths, expandWorkspaces, getWorkspacePackageManager, + parseWorkspacePackages, } from "../utils"; /** @@ -47,6 +48,9 @@ async function read(args: ReadArgs): Promise { const packageJson = getPackageJson(args); const { name, description } = getWorkspaceInfo(args); + const workspaceGlobs = parseWorkspacePackages({ + workspaces: packageJson.workspaces, + }); return { name, description, @@ -56,9 +60,9 @@ async function read(args: ReadArgs): Promise { lockFile: "yarn.lock", }), workspaceData: { - globs: packageJson.workspaces || [], + globs: workspaceGlobs, workspaces: expandWorkspaces({ - workspaceGlobs: packageJson.workspaces, + workspaceGlobs, ...args, }), }, diff --git a/packages/turbo-workspaces/src/types.ts b/packages/turbo-workspaces/src/types.ts index 9240f09eb5642..96990c9cdfb63 100644 --- a/packages/turbo-workspaces/src/types.ts +++ b/packages/turbo-workspaces/src/types.ts @@ -48,7 +48,7 @@ export type PackageJsonDependencies = { export type PackageJson = PackageJsonDependencies & { name?: string; description?: string; - workspaces?: Array; + workspaces?: { packages: Array } | Array; packageManager?: string; }; diff --git a/packages/turbo-workspaces/src/utils.ts b/packages/turbo-workspaces/src/utils.ts index 829020366958c..ea766a3098e90 100644 --- a/packages/turbo-workspaces/src/utils.ts +++ b/packages/turbo-workspaces/src/utils.ts @@ -131,6 +131,22 @@ function expandPaths({ return paths; } +function parseWorkspacePackages({ + workspaces, +}: { + workspaces: PackageJson["workspaces"]; +}): Array { + if (!workspaces) { + return []; + } + + if ("packages" in workspaces) { + return workspaces.packages; + } + + return workspaces; +} + function expandWorkspaces({ workspaceRoot, workspaceGlobs, @@ -191,6 +207,7 @@ export { getWorkspaceInfo, expandPaths, expandWorkspaces, + parseWorkspacePackages, getPnpmWorkspaces, directoryInfo, getMainStep,