Skip to content

Commit

Permalink
Autodetect Berry (#19)
Browse files Browse the repository at this point in the history
  • Loading branch information
finn-orsini authored Jun 27, 2022
1 parent 4a20c3a commit 3f1fd52
Show file tree
Hide file tree
Showing 11 changed files with 96 additions and 29 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ This changelog format is largely based on [Keep A Changelog](https://keepachange

#### 🔨 Chores & Documentation

## [0.3.0] - 2022-06-27

#### 🚀 New Features & Enhancements

- Add detection and support for Yarn Berry

## [0.2.0] - 2022-05-16

#### 🚀 New Features & Enhancements
Expand Down
2 changes: 1 addition & 1 deletion ONE-VERSION.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,4 @@ Although using the same specifier, the entries resolve to two different versions

- This library currently only operates on declared dependencies. That is the `dependencies`, `devDependencies`, and `peerDependencies` specified by a workspace - **not** any transitive dependencies.
- Resolutions are not yet taken into account.
- Package manager is selected based on the lockfile name in the root of the repo.
- Package manager is selected based on the lockfile name in the root of the repo. Berry is chosen over Yarn classic if a `.yarnrc.yml` file exists at the root of the repo.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ One Version to bring them all, and in the darkness bind them.<sup>1</sup>

**🚨 Enforcement**: Require all workspaces in a monorepo to conform to the [One-Version rule](#one-version-rule).

**📦 Supports multiple package managers**: Support for `yarn` and `pnpm` workspaces.
**📦 Supports multiple package managers**: Support for `yarn` classic, `yarn` berry, and `pnpm` workspaces.

**💥 Coordinated upgrades**: Coming Soon!

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@wayfair/one-version",
"version": "0.2.0",
"version": "0.3.0",
"description": "Opinionated Monorepo Dependency Management CLI",
"bin": "src/index.js",
"main": "src/index.js",
Expand Down
3 changes: 2 additions & 1 deletion src/check.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Note: Currently enforces the specifications match exactly, i.e. `^17` != `17`.
const chalk = require("chalk");
const { parseConfig, detectPackageManager } = require("./shared/util");
const { format } = require("./format-output");
const { checkYarn } = require("./yarn/check");
const { checkYarn, checkBerry } = require("./yarn/check");
const { checkPnpm } = require("./pnpm/check");
const {
UNABLE_TO_DETECT_PACKAGE_MANAGER_ERROR,
Expand All @@ -16,6 +16,7 @@ const {
const PACKAGE_MANGER_API = {
pnpm: checkPnpm,
yarn: checkYarn,
berry: checkBerry,
};

const getCheckPackageApi = (packageManager) => {
Expand Down
34 changes: 22 additions & 12 deletions src/shared/__tests__/util.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ const {
} = require("../util");
const fs = require("fs");

jest.mock('fs', () => ({
...jest.requireActual('fs'),
jest.mock("fs", () => ({
...jest.requireActual("fs"),
existsSync: jest.fn(),
}));

Expand Down Expand Up @@ -127,20 +127,30 @@ describe("findDuplicateDependencies", () => {
});

it("returns pnpm if pnpm-lock.yml exists", () => {
fs.existsSync.mockReturnValueOnce(true);
const packageManager = detectPackageManager({pnpm: "pnpm-lock.yaml",});
expect(packageManager).toBe('pnpm');
// first check for yarn.lock, then pnpm
fs.existsSync.mockReturnValueOnce(false).mockReturnValueOnce(true);
const packageManager = detectPackageManager();
expect(packageManager).toBe("pnpm");
});

it("returns pnpm if yarn.lock exists", () => {
fs.existsSync.mockReturnValueOnce(true);
const packageManager = detectPackageManager({yarn: "yarn.lock"});
expect(packageManager).toBe('yarn');
it("returns yarn if yarn.lock exists", () => {
// first check for yarn.lock, then yarnrc
fs.existsSync.mockReturnValueOnce(true).mockReturnValueOnce(false);
const packageManager = detectPackageManager();
expect(packageManager).toBe("yarn");
});

it("returns berry if yarn.lock and .yarnrc.yml exist", () => {
// first check for yarn.lock, then yarnrc
fs.existsSync.mockReturnValueOnce(true).mockReturnValueOnce(true);
const packageManager = detectPackageManager();
expect(packageManager).toBe("berry");
});

it("returns empty if package manager is not detected", () => {
fs.existsSync.mockReturnValueOnce(true);
const packageManager = detectPackageManager({});
expect(packageManager).toBe('');
// first check for yarn.lock, then pnpm
fs.existsSync.mockReturnValueOnce(false).mockReturnValueOnce(false);
const packageManager = detectPackageManager();
expect(packageManager).toBe("");
});
});
11 changes: 6 additions & 5 deletions src/shared/constants.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
const CONFIG_FILE = "oneversion.config.json";

const LOCKFILES = {
yarn: "yarn.lock",
pnpm: "pnpm-lock.yaml",
};
const YARN_LOCK = "yarn.lock";
const PNPM_LOCK = "pnpm-lock.yaml";
const YARN_RC = ".yarnrc.yml";

const DEPENDENCY_TYPES = {
DIRECT: "direct",
Expand All @@ -19,9 +18,11 @@ const NO_CHECK_API_ERROR = `'check' api not supported for package manager:`;

module.exports = {
CONFIG_FILE,
LOCKFILES,
DEPENDENCY_TYPES,
UNABLE_TO_DETECT_PACKAGE_MANAGER_ERROR,
FAILED_CHECK_ERROR,
NO_CHECK_API_ERROR,
YARN_LOCK,
PNPM_LOCK,
YARN_RC,
};
20 changes: 15 additions & 5 deletions src/shared/util.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
const { readFileSync, existsSync } = require("fs");
const path = require("path");
const { DEPENDENCY_TYPES, CONFIG_FILE, LOCKFILES } = require("./constants");
const {
DEPENDENCY_TYPES,
CONFIG_FILE,
YARN_RC,
YARN_LOCK,
PNPM_LOCK,
} = require("./constants");

/**
* Parse a config file if it exists
Expand Down Expand Up @@ -158,11 +164,15 @@ const findDuplicateDependencies = (dependencies, overrides) => {
/**
* Detect the package manager being used by the project
*/
const detectPackageManager = (lockfiles = LOCKFILES) => {
for (const [packageManager, lockfile] of Object.entries(lockfiles)) {
if (existsSync(lockfile)) {
return packageManager;
const detectPackageManager = () => {
if (existsSync(YARN_LOCK)) {
if (existsSync(YARN_RC)) {
return "berry";
}
return "yarn";
}
if (existsSync(PNPM_LOCK)) {
return "pnpm";
}
return "";
};
Expand Down
24 changes: 24 additions & 0 deletions src/yarn/berry-api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const { execSync } = require("child_process");

const getWorkspaces = () => {
// http://ndjson.org/
const ndJSONWorkspaces = execSync("yarn workspaces list --json", {
stdio: "pipe",
}).toString();

const workspaces = ndJSONWorkspaces
.replace(/\n*$/, "") // strip out trailing new line
.split("\n") // split on new line
.map((str) => JSON.parse(str)); // parse each workspace

return workspaces.map(({ location, name }) => ({
name,
path: location,
}));
};

const berryApi = {
getWorkspaces,
};

module.exports = berryApi;
21 changes: 18 additions & 3 deletions src/yarn/check.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,26 @@ const {
findDuplicateDependencies,
transformDependencies,
} = require("../shared/util");
const { getWorkspaces } = require("./get-workspaces");
const classicApi = require("./classic-api");
const berryApi = require("./berry-api");

const checkYarn = ({ overrides, getPackageRoots = getWorkspaces }) => {
const checkYarn = ({
overrides,
getPackageRoots = classicApi.getWorkspaces,
}) => {
const workspaces = getPackageRoots();
return _baseYarnCheck({ workspaces, overrides });
};

const checkBerry = ({
overrides,
getPackageRoots = berryApi.getWorkspaces,
}) => {
const workspaces = getPackageRoots();
return _baseYarnCheck({ workspaces, overrides });
};

const _baseYarnCheck = ({ workspaces, overrides }) => {
const packageDeps = workspaces.map(({ path }) => getPackageDeps(path));

const dependenciesByNameAndVersion = transformDependencies(packageDeps);
Expand All @@ -19,4 +34,4 @@ const checkYarn = ({ overrides, getPackageRoots = getWorkspaces }) => {
return { duplicateDependencies };
};

module.exports = { checkYarn };
module.exports = { checkYarn, checkBerry };
File renamed without changes.

0 comments on commit 3f1fd52

Please sign in to comment.