Skip to content

Commit

Permalink
feat(core): support nx config for commitlint
Browse files Browse the repository at this point in the history
Signed-off-by: Emilien Escalle <emilien.escalle@escemi.com>
  • Loading branch information
neilime committed Aug 29, 2024
1 parent 2c90538 commit b4caebc
Show file tree
Hide file tree
Showing 14 changed files with 402 additions and 24 deletions.
28 changes: 28 additions & 0 deletions packages/core/src/__snapshots__/core.spec.e2e.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,32 @@ Applying migration "core - 20240329200200-eslint-ignore"...
Migration "core - 20240329200200-eslint-ignore" applied!
Applying migration "core - 20240412185500-eslint-config"...
Migration "core - 20240412185500-eslint-config" applied!
Applying migration "core - 20240617094000-config-nx-scopes"...
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
success Saved 2 new dependencies.
info Direct dependencies
├─ @commitlint/config-nx-scopes@19.3.1
└─ @ts-dev-tools/core@1.7.0
info All dependencies
├─ @commitlint/config-nx-scopes@19.3.1
└─ @ts-dev-tools/core@1.7.0
$ ts-dev-tools install
Updating ts-dev-tools installation...
Applying migration "core - 20240617094000-config-nx-scopes"...
Migration "core - 20240617094000-config-nx-scopes" applied!
Symlinking dev dependencies...
Symlinking dev dependencies done!
Checking for duplicate dev dependencies...
Some dev dependencies are unnecessarily installed as their are already required by "@ts-dev-tools/core":
- typescript
Check for duplicate dev dependencies done!
Installation done!
Migration "core - 20240617094000-config-nx-scopes" applied!
Symlinking dev dependencies...
Symlinking dev dependencies done!
Checking for duplicate dev dependencies...
Expand All @@ -32,6 +58,8 @@ Applying migration "core - 20240329200200-eslint-ignore"...
Migration "core - 20240329200200-eslint-ignore" applied!
Applying migration "core - 20240412185500-eslint-config"...
Migration "core - 20240412185500-eslint-config" applied!
Applying migration "core - 20240617094000-config-nx-scopes"...
Migration "core - 20240617094000-config-nx-scopes" applied!
Symlinking dev dependencies...
Symlinking dev dependencies done!
Checking for duplicate dev dependencies...
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/core.spec.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ describe(`E2E - ${packageToTest}`, () => {
await createTestMonorepoProjectDir(testMonorepoProjectDir, async (projectDir) => {
await safeExec(testMonorepoProjectDir, `cp -r ${testProjectTmpDir} ${projectDir}`);
await safeExec(projectDir, `yarn install`);
await safeExec(testMonorepoProjectDir, `npx lerna init --no-progress`);
});
}, 200000);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { PackageJson } from "../../services/PackageJson";
import {
createTestProjectDirWithFixtures,
removeTestProjectDir,
restorePackageJson,
} from "../../tests/project";
import { up } from "./20240617094000-config-nx-scopes";

describe("Migration 20240617094000-config-nx-scopes", () => {
let testProjectDir: string;

beforeAll(() => {
testProjectDir = createTestProjectDirWithFixtures(__filename);
});

afterAll(() => {
removeTestProjectDir(__filename);
});

describe("Up", () => {
afterEach(() => {
restorePackageJson(__filename);
});

it("should apply migration", async () => {
await up(testProjectDir);

const packageJsonContent = PackageJson.fromDirPath(testProjectDir).getContent();

expect(packageJsonContent).toMatchSnapshot();
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { MigrationUpFunction } from "../../services/MigrationsService";
import { PackageJson } from "../../services/PackageJson";
import { PackageManagerService } from "../../services/PackageManagerService";

export const up: MigrationUpFunction = async (absoluteProjectDir: string): Promise<void> => {
const packageToInstall = "@commitlint/config-nx-scopes";
const nxDeps = ["@nrwl/workspace", "nx", "lerna"];

// Check if project is using nx or lerna
const packageJson = PackageJson.fromDirPath(absoluteProjectDir);
const hasNx = nxDeps.some((dep) => packageJson.hasDependency(dep));

if (!hasNx) {
return;
}

// Ensure that package is installed
if (!(await PackageManagerService.isPackageInstalled(packageToInstall, absoluteProjectDir))) {
await PackageManagerService.addDevPackage(packageToInstall, absoluteProjectDir);
}

// Update commitlint config
const commitlint = {
extends: [packageToInstall],
};

packageJson.merge({
commitlint,
});
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Migration 20240617094000-config-nx-scopes Up should apply migration 1`] = `
{
"license": "MIT",
"version": "1.0.0",
}
`;
6 changes: 4 additions & 2 deletions packages/core/src/services/MigrationsService.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { readdirSync, unlinkSync } from "fs";
import { existsSync, readdirSync, unlinkSync } from "fs";
import { resolve } from "path";

import { PackageJson } from "../services/PackageJson";
Expand Down Expand Up @@ -42,7 +42,9 @@ export class MigrationsService {
throw error;
}

unlinkSync(packageJsonBackupPath);
if (existsSync(packageJsonBackupPath)) {
unlinkSync(packageJsonBackupPath);
}
}

private static getAvailableMigrations(
Expand Down
27 changes: 27 additions & 0 deletions packages/core/src/services/PackageJson.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,33 @@ describe("PackageJson", () => {
});
});

describe("hasDependency", () => {
afterEach(() => {
restorePackageJson(__filename);
});

it("should return true if the given package name is installed", () => {
const packageJson = PackageJson.fromDirPath(testProjectDir);
packageJson.merge({
dependencies: {
"test-dependency": "1.0.0",
},
});

const hasDependency = packageJson.hasDependency("test-dependency");

expect(hasDependency).toBe(true);
});

it("should return false if the given package name is not installed", () => {
const packageJson = PackageJson.fromDirPath(testProjectDir);

const hasDependency = packageJson.hasDependency("test-dependency");

expect(hasDependency).toBe(false);
});
});

describe("merge", () => {
afterEach(() => {
restorePackageJson(__filename);
Expand Down
4 changes: 4 additions & 0 deletions packages/core/src/services/PackageJson.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ export class PackageJson {
);
}

hasDependency(packageName: string): boolean {
return this.getAllDependenciesPackageNames().includes(packageName);
}

merge(update: PackageJsonContent): void {
this.content = PackageJsonMerge.merge(this.getContent(), update);
this.write();
Expand Down
113 changes: 96 additions & 17 deletions packages/core/src/services/PackageManagerService.spec.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,112 @@
import { writeFileSync } from "fs";
import { join } from "path";

import { createTestProjectDirWithFixtures, removeTestProjectDir } from "../tests/project";
import { safeExec } from "../tests/cli";
import { createTestProjectDir, removeTestProjectDir } from "../tests/project";
import { PackageJson } from "./PackageJson";
import { PackageManagerService, PackageManagerType } from "./PackageManagerService";

describe("PackageManagerService", () => {
let testProjectDir: string;

beforeAll(() => {
testProjectDir = createTestProjectDirWithFixtures(__filename);
});
describe("detectPackageManager", () => {
beforeEach(async () => {
testProjectDir = createTestProjectDir(__filename);
});

afterAll(() => {
removeTestProjectDir(__filename);
});
afterEach(() => {
removeTestProjectDir(__filename);
});

describe("detectPackageManager", () => {
it("should retrieve the default package manager when no one is detectable", () => {
const packageManager = PackageManagerService.detectPackageManager(testProjectDir);

expect(packageManager).toEqual(PackageManagerType.npm);
});
});

it("should retrieve the yarn package manager when yarn.lock file exists", () => {
writeFileSync(join(testProjectDir, "yarn.lock"), "test");
describe.each([PackageManagerType.npm, PackageManagerType.yarn])(
`with package manager %s`,
(packageManagerType) => {
const packageTypeTestFileName = __filename.replace(
".spec.ts",
`-${packageManagerType}.spec.ts`
);
beforeEach(async () => {
testProjectDir = createTestProjectDir(packageTypeTestFileName);
await safeExec(testProjectDir, `${packageManagerType} init --yes`);
await safeExec(testProjectDir, `${packageManagerType} install --silent`);
});

const packageManager = PackageManagerService.detectPackageManager(testProjectDir);
afterEach(() => {
removeTestProjectDir(packageTypeTestFileName);
});

expect(packageManager).toEqual(PackageManagerType.yarn);
});
});
describe("detectPackageManager", () => {
it("should retrieve the current package manager", () => {
const packageManager = PackageManagerService.detectPackageManager(testProjectDir);

expect(packageManager).toEqual(packageManagerType);
});
});

describe("isPackageInstalled", () => {
it("should return false if package is not installed", async () => {
const isInstalled = await PackageManagerService.isPackageInstalled(
"test-package",
testProjectDir
);

expect(isInstalled).toBeFalsy();
});

it("should return true if package is installed", async () => {
await PackageManagerService.addDevPackage("test-package", testProjectDir);

const isInstalled = await PackageManagerService.isPackageInstalled(
"test-package",
testProjectDir
);

expect(isInstalled).toBeTruthy();
});
});

describe("isMonorepo", () => {
it("should return false if project is not a monorepo", async () => {
const isMonorepo = await PackageManagerService.isMonorepo(testProjectDir);

expect(isMonorepo).toBeFalsy();
});

it("should return true if project is a monorepo", async () => {
await PackageJson.fromDirPath(testProjectDir).merge({
private: true,
workspaces: ["packages/*"],
});

const testPackageDir = `${testProjectDir}/packages/test-package`;

await safeExec(testProjectDir, `mkdir -p packages/test-package`);
await safeExec(testPackageDir, `${packageManagerType} init --yes`);

const isMonorepo = await PackageManagerService.isMonorepo(testProjectDir);

expect(isMonorepo).toBeTruthy();
});
});

describe("addDevPackage", () => {
it("should add a dev package", async () => {
expect(
await PackageManagerService.isPackageInstalled("test-package", testProjectDir)
).toBeFalsy();

await PackageManagerService.addDevPackage("test-package", testProjectDir);

expect(
await PackageManagerService.isPackageInstalled("test-package", testProjectDir)
).toBeTruthy();
});
});
},
10000
);
});
Loading

0 comments on commit b4caebc

Please sign in to comment.