fix: `rush.json` is missed in repos using Rush + Yarn (#100)

* fix: Rush is not correctly detected in some setups

In certain repos, Rush is set up to be run in postinstall so people
can't avoid running the correct thing. This means that the repo is
littered with lock files from other package managers. `workspace-tools`
fails to detect Rush because it finds these lock files first.

* add/fix tests

* move gpg fix out of real code
This commit is contained in:
Tommy Nguyen 2022-04-09 17:50:27 +02:00 коммит произвёл GitHub
Родитель e0a79ffe0a
Коммит b99f6f82a6
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
6 изменённых файлов: 68 добавлений и 10 удалений

Просмотреть файл

@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "Fix Rush not being detected correctly. When Rush is set up to use Yarn or pnpm, the lock file for the latter are found first.",
"packageName": "workspace-tools",
"email": "4123478+tido64@users.noreply.github.com",
"dependentChangeType": "patch"
}

Просмотреть файл

@ -0,0 +1,8 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
pnpm@^6.0:
version "6.32.4"
resolved "https://registry.yarnpkg.com/pnpm/-/pnpm-6.32.4.tgz#74d486f3563d8e4476141b43af18dd08c9291961"
integrity sha512-rOG+VpOzs6g/MR5HWc8KTlLAx3ljdRJCMQwSg1DE/hzAaqF/Y2zIHH0u6dZw/XnRb9w1U8rOs9MJT9jMt7e+Qw==

Просмотреть файл

@ -2,7 +2,7 @@ import path from "path";
import fs from "fs";
import { cleanupFixtures, setupFixture, setupLocalRemote } from "../helpers/setupFixture";
import { stageAndCommit, git, gitFailFast } from "../git";
import { stageAndCommit, git } from "../git";
import { getChangedPackages } from "../workspaces/getChangedPackages";
describe("getChangedPackages()", () => {
@ -111,7 +111,7 @@ describe("getChangedPackages()", () => {
// assert
expect(changedPkgs).toContain("package-a");
});
it("can detect changes inside a file that has been committed in a different branch in a nested monorepo", () => {
// arrange
const root = path.join(setupFixture("monorepo-nested"), "monorepo");

Просмотреть файл

@ -1,6 +1,7 @@
import path from "path";
import { cleanupFixtures, setupFixture } from "../helpers/setupFixture";
import { getWorkspaceImplementation } from "../workspaces/implementations";
import { getYarnWorkspaces } from "../workspaces/implementations/yarn";
import { getPnpmWorkspaces } from "../workspaces/implementations/pnpm";
import { getRushWorkspaces } from "../workspaces/implementations/rush";
@ -15,6 +16,9 @@ describe("getWorkspaces", () => {
describe("yarn", () => {
it("gets the name and path of the workspaces", () => {
const packageRoot = setupFixture("monorepo");
expect(getWorkspaceImplementation(packageRoot, {})).toBe("yarn");
const workspacesPackageInfo = getYarnWorkspaces(packageRoot);
const packageAPath = path.join(packageRoot, "packages", "package-a");
@ -28,6 +32,9 @@ describe("getWorkspaces", () => {
it("gets the name and path of the workspaces against a packages spec of an individual package", () => {
const packageRoot = setupFixture("monorepo-globby");
expect(getWorkspaceImplementation(packageRoot, {})).toBe("yarn");
const workspacesPackageInfo = getYarnWorkspaces(packageRoot);
const packageAPath = path.join(packageRoot, "packages", "package-a");
@ -45,6 +52,9 @@ describe("getWorkspaces", () => {
describe("pnpm", () => {
it("gets the name and path of the workspaces", () => {
const packageRoot = setupFixture("monorepo-pnpm");
expect(getWorkspaceImplementation(packageRoot, {})).toBe("pnpm");
const workspacesPackageInfo = getPnpmWorkspaces(packageRoot);
const packageAPath = path.join(packageRoot, "packages", "package-a");
@ -57,9 +67,30 @@ describe("getWorkspaces", () => {
});
});
describe("rush", () => {
describe("rush + pnpm", () => {
it("gets the name and path of the workspaces", () => {
const packageRoot = setupFixture("monorepo-rush-pnpm");
expect(getWorkspaceImplementation(packageRoot, {})).toBe("rush");
const workspacesPackageInfo = getRushWorkspaces(packageRoot);
const packageAPath = path.join(packageRoot, "packages", "package-a");
const packageBPath = path.join(packageRoot, "packages", "package-b");
expect(workspacesPackageInfo).toMatchObject([
{ name: "package-a", path: packageAPath },
{ name: "package-b", path: packageBPath },
]);
});
});
describe("rush + yarn", () => {
it("gets the name and path of the workspaces", () => {
const packageRoot = setupFixture("monorepo-rush-yarn");
expect(getWorkspaceImplementation(packageRoot, {})).toBe("rush");
const workspacesPackageInfo = getRushWorkspaces(packageRoot);
const packageAPath = path.join(packageRoot, "packages", "package-a");
@ -75,6 +106,9 @@ describe("getWorkspaces", () => {
describe("npm", () => {
it("gets the name and path of the workspaces", () => {
const packageRoot = setupFixture("monorepo-npm");
expect(getWorkspaceImplementation(packageRoot, {})).toBe("npm");
const workspacesPackageInfo = getNpmWorkspaces(packageRoot);
const packageAPath = path.join(packageRoot, "packages", "package-a");
@ -88,6 +122,9 @@ describe("getWorkspaces", () => {
it("gets the name and path of the workspaces using the shorthand configuration", () => {
const packageRoot = setupFixture("monorepo-shorthand");
expect(getWorkspaceImplementation(packageRoot, {})).toBe("npm");
const workspacesPackageInfo = getNpmWorkspaces(packageRoot);
const packageAPath = path.join(packageRoot, "packages", "package-a");
@ -104,7 +141,10 @@ describe("getWorkspaces", () => {
describe("lerna", () => {
it("gets the name and path of the workspaces", async () => {
const packageRoot = await setupFixture("monorepo-lerna-npm");
const packageRoot = setupFixture("monorepo-lerna-npm");
expect(getWorkspaceImplementation(packageRoot, {})).toBe("lerna");
const workspacesPackageInfo = getLernaWorkspaces(packageRoot);
const packageAPath = path.join(packageRoot, "packages", "package-a");

Просмотреть файл

@ -1,7 +1,6 @@
import path from "path";
import findUp from "find-up";
import fs from "fs-extra";
import fsExtra from "fs-extra";
import tmp from "tmp";
import { init, stageAndCommit, gitFailFast } from "../git";
@ -39,6 +38,9 @@ export function setupFixture(fixtureName: string) {
init(cwd, "test@test.email", "test user");
// Ensure GPG signing doesn't interfere with tests
gitFailFast(["config", "commit.gpgsign", "false"], { cwd });
// Make the 'main' branch the default in the test repo
// ensure that the configuration for this repo does not collide
// with any global configuration the user had made, so we have

Просмотреть файл

@ -6,16 +6,17 @@ export interface ImplementationAndLockFile {
implementation: WorkspaceImplementations | undefined;
lockFile: string;
}
const cache: { [cwd: string]: ImplementationAndLockFile } = {};
const workspaceCache: { [cwd: string]: ImplementationAndLockFile } = {};
export function getWorkspaceImplementationAndLockFile(
cwd: string
cwd: string,
cache = workspaceCache
): { implementation: WorkspaceImplementations | undefined; lockFile: string } | undefined {
if (cache[cwd]) {
return cache[cwd];
}
const lockFile = findUp.sync(["lerna.json", "yarn.lock", "pnpm-workspace.yaml", "rush.json", "package-lock.json"], {
const lockFile = findUp.sync(["lerna.json", "rush.json", "yarn.lock", "pnpm-workspace.yaml", "package-lock.json"], {
cwd,
});
@ -63,6 +64,6 @@ export function getWorkspaceImplementationAndLockFile(
return cache[cwd];
}
export function getWorkspaceImplementation(cwd: string): WorkspaceImplementations | undefined {
return getWorkspaceImplementationAndLockFile(cwd)?.implementation;
export function getWorkspaceImplementation(cwd: string, cache = workspaceCache): WorkspaceImplementations | undefined {
return getWorkspaceImplementationAndLockFile(cwd, cache)?.implementation;
}