feat(core): add bun package manager (#22602)
Bun uses yarn lock for it's binary file. Running the binary will produce the content of a yarn lock file (v1) Other option is to use the -y command on add and install. This will create a yarn lock file and then createLockFile can just modify the yarn.lock file instead? This is the PR made from #19113 and pushed due to #22402 being closed. PS Bun feels more stable since the PR was first created! This PR will resolve #22283 and start of #21075
This commit is contained in:
parent
383be1f7d4
commit
80702b59c7
@ -129,7 +129,7 @@ Do you want Nx Cloud to make your CI fast?
|
||||
|
||||
Type: `string`
|
||||
|
||||
Choices: [npm, pnpm, yarn]
|
||||
Choices: [bun, npm, pnpm, yarn]
|
||||
|
||||
Default: `npm`
|
||||
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
# Type alias: PackageManager
|
||||
|
||||
Ƭ **PackageManager**: `"yarn"` \| `"pnpm"` \| `"npm"`
|
||||
Ƭ **PackageManager**: `"yarn"` \| `"pnpm"` \| `"npm"` \| `"bun"`
|
||||
|
||||
@ -129,7 +129,7 @@ Do you want Nx Cloud to make your CI fast?
|
||||
|
||||
Type: `string`
|
||||
|
||||
Choices: [npm, pnpm, yarn]
|
||||
Choices: [bun, npm, pnpm, yarn]
|
||||
|
||||
Default: `npm`
|
||||
|
||||
|
||||
@ -53,7 +53,7 @@
|
||||
"packageManager": {
|
||||
"description": "The package manager used to install dependencies.",
|
||||
"type": "string",
|
||||
"enum": ["npm", "yarn", "pnpm"]
|
||||
"enum": ["npm", "yarn", "pnpm", "bun"]
|
||||
},
|
||||
"framework": {
|
||||
"description": "The framework which the application is using",
|
||||
|
||||
@ -59,7 +59,7 @@
|
||||
"packageManager": {
|
||||
"description": "The package manager used to install dependencies.",
|
||||
"type": "string",
|
||||
"enum": ["npm", "yarn", "pnpm"]
|
||||
"enum": ["npm", "yarn", "pnpm", "bun"]
|
||||
},
|
||||
"framework": {
|
||||
"description": "The framework which the application is using",
|
||||
|
||||
@ -171,6 +171,19 @@ export function getPackageManagerCommand({
|
||||
list: 'pnpm ls --depth 10',
|
||||
runLerna: `pnpm exec lerna`,
|
||||
},
|
||||
bun: {
|
||||
createWorkspace: `bunx create-nx-workspace@${publishedVersion}`,
|
||||
run: (script: string, args: string) => `bun run ${script} -- ${args}`,
|
||||
runNx: `bunx nx`,
|
||||
runNxSilent: `bunx nx`,
|
||||
runUninstalledPackage: `bunx --yes`,
|
||||
install: 'bun install',
|
||||
ciInstall: 'bun install --no-cache',
|
||||
addProd: 'bun install',
|
||||
addDev: 'bun install -D',
|
||||
list: 'bun pm ls',
|
||||
runLerna: `bunx lerna`,
|
||||
},
|
||||
}[packageManager.trim() as PackageManager];
|
||||
}
|
||||
|
||||
|
||||
@ -78,7 +78,7 @@ export function newProject({
|
||||
packages,
|
||||
}: {
|
||||
name?: string;
|
||||
packageManager?: 'npm' | 'yarn' | 'pnpm';
|
||||
packageManager?: 'npm' | 'yarn' | 'pnpm' | 'bun';
|
||||
unsetProjectNameAndRootFormat?: boolean;
|
||||
readonly packages?: Array<NxPackage>;
|
||||
} = {}): string {
|
||||
@ -240,7 +240,7 @@ export function runCreateWorkspace(
|
||||
appName?: string;
|
||||
style?: string;
|
||||
base?: string;
|
||||
packageManager?: 'npm' | 'yarn' | 'pnpm';
|
||||
packageManager?: 'npm' | 'yarn' | 'pnpm' | 'bun';
|
||||
extraArgs?: string;
|
||||
useDetectedPm?: boolean;
|
||||
cwd?: string;
|
||||
@ -358,7 +358,7 @@ export function runCreatePlugin(
|
||||
extraArgs,
|
||||
useDetectedPm = false,
|
||||
}: {
|
||||
packageManager?: 'npm' | 'yarn' | 'pnpm';
|
||||
packageManager?: 'npm' | 'yarn' | 'pnpm' | 'bun';
|
||||
extraArgs?: string;
|
||||
useDetectedPm?: boolean;
|
||||
}
|
||||
@ -543,6 +543,11 @@ export function newLernaWorkspace({
|
||||
...json.resolutions,
|
||||
...overrides,
|
||||
};
|
||||
} else if (packageManager === 'bun') {
|
||||
json.overrides = {
|
||||
...json.resolutions,
|
||||
...overrides,
|
||||
};
|
||||
} else {
|
||||
json.overrides = overrides;
|
||||
}
|
||||
|
||||
@ -23,7 +23,9 @@ export function getPublishedVersion(): string {
|
||||
}
|
||||
|
||||
export function detectPackageManager(dir: string = ''): PackageManager {
|
||||
return existsSync(join(dir, 'yarn.lock'))
|
||||
return existsSync(join(dir, 'bun.lockb'))
|
||||
? 'bun'
|
||||
: existsSync(join(dir, 'yarn.lock'))
|
||||
? 'yarn'
|
||||
: existsSync(join(dir, 'pnpm-lock.yaml')) ||
|
||||
existsSync(join(dir, 'pnpm-workspace.yaml'))
|
||||
@ -64,8 +66,8 @@ export function isVerboseE2ERun() {
|
||||
|
||||
export const e2eCwd = `${e2eRoot}/nx`;
|
||||
|
||||
export function getSelectedPackageManager(): 'npm' | 'yarn' | 'pnpm' {
|
||||
return (process.env.SELECTED_PM as 'npm' | 'yarn' | 'pnpm') || 'npm';
|
||||
export function getSelectedPackageManager(): 'npm' | 'yarn' | 'pnpm' | 'bun' {
|
||||
return (process.env.SELECTED_PM as 'npm' | 'yarn' | 'pnpm' | 'bun') || 'npm';
|
||||
}
|
||||
|
||||
export function getNpmMajorVersion(): string | undefined {
|
||||
@ -108,6 +110,7 @@ export const packageManagerLockFile = {
|
||||
npm: 'package-lock.json',
|
||||
yarn: 'yarn.lock',
|
||||
pnpm: 'pnpm-lock.yaml',
|
||||
bun: 'bun.lockb',
|
||||
};
|
||||
|
||||
export function ensureCypressInstallation() {
|
||||
|
||||
@ -374,7 +374,7 @@ describe('create-nx-workspace', () => {
|
||||
});
|
||||
|
||||
describe('Use detected package manager', () => {
|
||||
function setupProject(envPm: 'npm' | 'yarn' | 'pnpm') {
|
||||
function setupProject(envPm: 'npm' | 'yarn' | 'pnpm' | 'bun') {
|
||||
process.env.SELECTED_PM = envPm;
|
||||
runCreateWorkspace(uniq('pm'), {
|
||||
preset: 'apps',
|
||||
@ -389,7 +389,8 @@ describe('create-nx-workspace', () => {
|
||||
checkFilesExist(packageManagerLockFile['npm']);
|
||||
checkFilesDoNotExist(
|
||||
packageManagerLockFile['yarn'],
|
||||
packageManagerLockFile['pnpm']
|
||||
packageManagerLockFile['pnpm'],
|
||||
packageManagerLockFile['bun']
|
||||
);
|
||||
process.env.SELECTED_PM = packageManager;
|
||||
}, 90000);
|
||||
@ -401,7 +402,21 @@ describe('create-nx-workspace', () => {
|
||||
checkFilesExist(packageManagerLockFile['pnpm']);
|
||||
checkFilesDoNotExist(
|
||||
packageManagerLockFile['yarn'],
|
||||
packageManagerLockFile['npm']
|
||||
packageManagerLockFile['npm'],
|
||||
packageManagerLockFile['bun']
|
||||
);
|
||||
process.env.SELECTED_PM = packageManager;
|
||||
}, 90000);
|
||||
}
|
||||
|
||||
if (packageManager === 'bun') {
|
||||
it('should use bun when invoked with bunx', () => {
|
||||
setupProject('bun');
|
||||
checkFilesExist(packageManagerLockFile['bun']);
|
||||
checkFilesDoNotExist(
|
||||
packageManagerLockFile['yarn'],
|
||||
packageManagerLockFile['npm'],
|
||||
packageManagerLockFile['pnpm']
|
||||
);
|
||||
process.env.SELECTED_PM = packageManager;
|
||||
}, 90000);
|
||||
@ -414,7 +429,8 @@ describe('create-nx-workspace', () => {
|
||||
checkFilesExist(packageManagerLockFile['yarn']);
|
||||
checkFilesDoNotExist(
|
||||
packageManagerLockFile['pnpm'],
|
||||
packageManagerLockFile['npm']
|
||||
packageManagerLockFile['npm'],
|
||||
packageManagerLockFile['bun']
|
||||
);
|
||||
process.env.SELECTED_PM = packageManager;
|
||||
}, 90000);
|
||||
|
||||
@ -110,6 +110,7 @@ export async function determinePackageManager(
|
||||
{ name: 'npm', message: 'NPM' },
|
||||
{ name: 'yarn', message: 'Yarn' },
|
||||
{ name: 'pnpm', message: 'PNPM' },
|
||||
{ name: 'bun', message: 'Bun' },
|
||||
],
|
||||
},
|
||||
])
|
||||
|
||||
@ -119,6 +119,11 @@ export async function recordStat(opts: {
|
||||
|
||||
function shouldRecordStats(): boolean {
|
||||
const pmc = getPackageManagerCommand();
|
||||
if (!pmc.getRegistryUrl) {
|
||||
// Fallback on true as Package management doesn't support reading config for registry.
|
||||
// currently Bun doesn't support fetching config settings https://github.com/oven-sh/bun/issues/7140
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
const stdout = execSync(pmc.getRegistryUrl, { encoding: 'utf-8' });
|
||||
const url = new URL(stdout.trim());
|
||||
|
||||
@ -7,12 +7,14 @@ import { join } from 'path';
|
||||
* we duplicate the helper functions from @nx/workspace in this file.
|
||||
*/
|
||||
|
||||
export const packageManagerList = ['pnpm', 'yarn', 'npm'] as const;
|
||||
export const packageManagerList = ['pnpm', 'yarn', 'npm', 'bun'] as const;
|
||||
|
||||
export type PackageManager = typeof packageManagerList[number];
|
||||
|
||||
export function detectPackageManager(dir: string = ''): PackageManager {
|
||||
return existsSync(join(dir, 'yarn.lock'))
|
||||
return existsSync(join(dir, 'bun.lockb'))
|
||||
? 'bun'
|
||||
: existsSync(join(dir, 'yarn.lock'))
|
||||
? 'yarn'
|
||||
: existsSync(join(dir, 'pnpm-lock.yaml'))
|
||||
? 'pnpm'
|
||||
@ -38,7 +40,8 @@ export function getPackageManagerCommand(
|
||||
exec: string;
|
||||
preInstall?: string;
|
||||
globalAdd: string;
|
||||
getRegistryUrl: string;
|
||||
// Make this required once bun adds programatically support for reading config https://github.com/oven-sh/bun/issues/7140
|
||||
getRegistryUrl?: string;
|
||||
} {
|
||||
const pmVersion = getPackageManagerVersion(packageManager);
|
||||
const [pmMajor, pmMinor] = pmVersion.split('.');
|
||||
@ -79,6 +82,13 @@ export function getPackageManagerCommand(
|
||||
globalAdd: 'npm i -g',
|
||||
getRegistryUrl: 'npm config get registry',
|
||||
};
|
||||
case 'bun':
|
||||
// bun doesn't current support programatically reading config https://github.com/oven-sh/bun/issues/7140
|
||||
return {
|
||||
install: 'bun install --silent --ignore-scripts',
|
||||
exec: 'bunx',
|
||||
globalAdd: 'bun install -g',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -14,6 +14,7 @@ export function createApplicationFiles(host: Tree, options: NormalizedSchema) {
|
||||
npm: 'package-lock.json',
|
||||
yarn: 'yarn.lock',
|
||||
pnpm: 'pnpm-lock.yaml',
|
||||
bun: 'bun.lockb',
|
||||
};
|
||||
const packageManager = detectPackageManager(host.root);
|
||||
const packageLockFile = packageManagerLockFile[packageManager];
|
||||
|
||||
@ -19,6 +19,7 @@ export default function update(tree: Tree) {
|
||||
npm: 'package-lock.json',
|
||||
yarn: 'yarn.lock',
|
||||
pnpm: 'pnpm-lock.yaml',
|
||||
bun: 'bun.lockb',
|
||||
};
|
||||
|
||||
for (const [name, config] of projects.entries()) {
|
||||
|
||||
@ -366,7 +366,7 @@
|
||||
"packageManager": {
|
||||
"type": "string",
|
||||
"description": "The default package manager to use.",
|
||||
"enum": ["yarn", "pnpm", "npm"]
|
||||
"enum": ["yarn", "pnpm", "npm", "bun"]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -243,6 +243,7 @@ function moveFilesToTempWorkspace(options: NormalizedOptions) {
|
||||
options.packageManager === 'yarn' ? 'yarn.lock' : null,
|
||||
options.packageManager === 'pnpm' ? 'pnpm-lock.yaml' : null,
|
||||
options.packageManager === 'npm' ? 'package-lock.json' : null,
|
||||
options.packageManager === 'bun' ? 'bun.lockb' : null,
|
||||
];
|
||||
|
||||
const optionalCraFiles = ['README.md'];
|
||||
|
||||
@ -24,6 +24,7 @@ import { hashArray } from '../../hasher/file-hasher';
|
||||
import { detectPackageManager } from '../../utils/package-manager';
|
||||
import { workspaceRoot } from '../../utils/workspace-root';
|
||||
import { nxVersion } from '../../utils/versions';
|
||||
import { execSync } from 'child_process';
|
||||
|
||||
export const name = 'nx/js/dependencies-and-lockfile';
|
||||
|
||||
@ -51,7 +52,10 @@ export const createNodes: CreateNodes = [
|
||||
}
|
||||
|
||||
const lockFilePath = join(workspaceRoot, lockFile);
|
||||
const lockFileContents = readFileSync(lockFilePath).toString();
|
||||
const lockFileContents =
|
||||
packageManager !== 'bun'
|
||||
? readFileSync(lockFilePath).toString()
|
||||
: execSync(`bun ${lockFilePath}`).toString();
|
||||
const lockFileHash = getLockFileHash(lockFileContents);
|
||||
|
||||
if (!lockFileNeedsReprocessing(lockFileHash)) {
|
||||
@ -91,7 +95,10 @@ export const createDependencies: CreateDependencies = (
|
||||
parsedLockFile.externalNodes
|
||||
) {
|
||||
const lockFilePath = join(workspaceRoot, getLockFileName(packageManager));
|
||||
const lockFileContents = readFileSync(lockFilePath).toString();
|
||||
const lockFileContents =
|
||||
packageManager !== 'bun'
|
||||
? readFileSync(lockFilePath).toString()
|
||||
: execSync(`bun ${lockFilePath}`).toString();
|
||||
const lockFileHash = getLockFileHash(lockFileContents);
|
||||
|
||||
if (!lockFileNeedsReprocessing(lockFileHash)) {
|
||||
|
||||
@ -45,11 +45,18 @@ import {
|
||||
const YARN_LOCK_FILE = 'yarn.lock';
|
||||
const NPM_LOCK_FILE = 'package-lock.json';
|
||||
const PNPM_LOCK_FILE = 'pnpm-lock.yaml';
|
||||
export const LOCKFILES = [YARN_LOCK_FILE, NPM_LOCK_FILE, PNPM_LOCK_FILE];
|
||||
const BUN_LOCK_FILE = 'bun.lockb';
|
||||
export const LOCKFILES = [
|
||||
YARN_LOCK_FILE,
|
||||
NPM_LOCK_FILE,
|
||||
PNPM_LOCK_FILE,
|
||||
BUN_LOCK_FILE,
|
||||
];
|
||||
|
||||
const YARN_LOCK_PATH = join(workspaceRoot, YARN_LOCK_FILE);
|
||||
const NPM_LOCK_PATH = join(workspaceRoot, NPM_LOCK_FILE);
|
||||
const PNPM_LOCK_PATH = join(workspaceRoot, PNPM_LOCK_FILE);
|
||||
const BUN_LOCK_PATH = join(workspaceRoot, BUN_LOCK_FILE);
|
||||
|
||||
/**
|
||||
* Parses lock file and maps dependencies and metadata to {@link LockFileGraph}
|
||||
@ -73,6 +80,11 @@ export function getLockFileNodes(
|
||||
if (packageManager === 'npm') {
|
||||
return getNpmLockfileNodes(contents, lockFileHash);
|
||||
}
|
||||
if (packageManager === 'bun') {
|
||||
// bun uses yarn v1 for the file format
|
||||
const packageJson = readJsonFile('package.json');
|
||||
return getYarnLockfileNodes(contents, lockFileHash, packageJson);
|
||||
}
|
||||
} catch (e) {
|
||||
if (!isPostInstallProcess()) {
|
||||
output.error({
|
||||
@ -104,6 +116,10 @@ export function getLockFileDependencies(
|
||||
if (packageManager === 'npm') {
|
||||
return getNpmLockfileDependencies(contents, lockFileHash, context);
|
||||
}
|
||||
if (packageManager === 'bun') {
|
||||
// bun uses yarn v1 for the file format
|
||||
return getYarnLockfileDependencies(contents, lockFileHash, context);
|
||||
}
|
||||
} catch (e) {
|
||||
if (!isPostInstallProcess()) {
|
||||
output.error({
|
||||
@ -126,6 +142,9 @@ export function lockFileExists(packageManager: PackageManager): boolean {
|
||||
if (packageManager === 'npm') {
|
||||
return existsSync(NPM_LOCK_PATH);
|
||||
}
|
||||
if (packageManager === 'bun') {
|
||||
return existsSync(BUN_LOCK_PATH);
|
||||
}
|
||||
throw new Error(
|
||||
`Unknown package manager ${packageManager} or lock file missing`
|
||||
);
|
||||
@ -146,6 +165,9 @@ export function getLockFileName(packageManager: PackageManager): string {
|
||||
if (packageManager === 'npm') {
|
||||
return NPM_LOCK_FILE;
|
||||
}
|
||||
if (packageManager === 'bun') {
|
||||
return BUN_LOCK_FILE;
|
||||
}
|
||||
throw new Error(`Unknown package manager: ${packageManager}`);
|
||||
}
|
||||
|
||||
@ -159,6 +181,9 @@ function getLockFilePath(packageManager: PackageManager): string {
|
||||
if (packageManager === 'npm') {
|
||||
return NPM_LOCK_PATH;
|
||||
}
|
||||
if (packageManager === 'bun') {
|
||||
return BUN_LOCK_PATH;
|
||||
}
|
||||
throw new Error(`Unknown package manager: ${packageManager}`);
|
||||
}
|
||||
|
||||
@ -191,6 +216,12 @@ export function createLockFile(
|
||||
const prunedGraph = pruneProjectGraph(graph, packageJson);
|
||||
return stringifyNpmLockfile(prunedGraph, content, normalizedPackageJson);
|
||||
}
|
||||
if (packageManager === 'bun') {
|
||||
output.log({
|
||||
title:
|
||||
"Unable to create bun lock files. Run bun install it's just as quick",
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
if (!isPostInstallProcess()) {
|
||||
const additionalInfo = [
|
||||
|
||||
@ -101,6 +101,11 @@ export async function recordStat(opts: {
|
||||
|
||||
function shouldRecordStats(): boolean {
|
||||
const pmc = getPackageManagerCommand();
|
||||
if (!pmc.getRegistryUrl) {
|
||||
// Fallback on true as Package management doesn't support reading config for registry.
|
||||
// currently Bun doesn't support fetching config settings https://github.com/oven-sh/bun/issues/7140
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
const stdout = execSync(pmc.getRegistryUrl, { encoding: 'utf-8' });
|
||||
const url = new URL(stdout.trim());
|
||||
|
||||
@ -10,6 +10,9 @@ import {
|
||||
|
||||
describe('package-manager', () => {
|
||||
describe('detectPackageManager', () => {
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
it('should detect package manager in nxJson', () => {
|
||||
jest.spyOn(configModule, 'readNxJson').mockReturnValueOnce({
|
||||
cli: {
|
||||
@ -30,13 +33,15 @@ describe('package-manager', () => {
|
||||
return false;
|
||||
case 'package-lock.json':
|
||||
return false;
|
||||
case 'bun.lockb':
|
||||
return false;
|
||||
default:
|
||||
return jest.requireActual('fs').existsSync(p);
|
||||
}
|
||||
});
|
||||
const packageManager = detectPackageManager();
|
||||
expect(packageManager).toEqual('yarn');
|
||||
expect(fs.existsSync).toHaveBeenNthCalledWith(1, 'yarn.lock');
|
||||
expect(fs.existsSync).toHaveBeenNthCalledWith(2, 'yarn.lock');
|
||||
});
|
||||
|
||||
it('should detect pnpm package manager from pnpm-lock.yaml', () => {
|
||||
@ -49,6 +54,8 @@ describe('package-manager', () => {
|
||||
return true;
|
||||
case 'package-lock.json':
|
||||
return false;
|
||||
case 'bun.lockb':
|
||||
return false;
|
||||
default:
|
||||
return jest.requireActual('fs').existsSync(p);
|
||||
}
|
||||
@ -58,6 +65,27 @@ describe('package-manager', () => {
|
||||
expect(fs.existsSync).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
|
||||
it('should detect bun package manager from bun.lockb', () => {
|
||||
jest.spyOn(configModule, 'readNxJson').mockReturnValueOnce({});
|
||||
jest.spyOn(fs, 'existsSync').mockImplementation((p) => {
|
||||
switch (p) {
|
||||
case 'yarn.lock':
|
||||
return false;
|
||||
case 'pnpm-lock.yaml':
|
||||
return false;
|
||||
case 'package-lock.json':
|
||||
return false;
|
||||
case 'bun.lockb':
|
||||
return true;
|
||||
default:
|
||||
return jest.requireActual('fs').existsSync(p);
|
||||
}
|
||||
});
|
||||
const packageManager = detectPackageManager();
|
||||
expect(packageManager).toEqual('bun');
|
||||
expect(fs.existsSync).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should use npm package manager as default', () => {
|
||||
jest.spyOn(configModule, 'readNxJson').mockReturnValueOnce({});
|
||||
jest.spyOn(fs, 'existsSync').mockImplementation((p) => {
|
||||
@ -68,13 +96,15 @@ describe('package-manager', () => {
|
||||
return false;
|
||||
case 'package-lock.json':
|
||||
return false;
|
||||
case 'bun.lockb':
|
||||
return false;
|
||||
default:
|
||||
return jest.requireActual('fs').existsSync(p);
|
||||
}
|
||||
});
|
||||
const packageManager = detectPackageManager();
|
||||
expect(packageManager).toEqual('npm');
|
||||
expect(fs.existsSync).toHaveBeenCalledTimes(5);
|
||||
expect(fs.existsSync).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@ import { workspaceRoot } from './workspace-root';
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
|
||||
export type PackageManager = 'yarn' | 'pnpm' | 'npm';
|
||||
export type PackageManager = 'yarn' | 'pnpm' | 'npm' | 'bun';
|
||||
|
||||
export interface PackageManagerCommands {
|
||||
preInstall?: string;
|
||||
@ -27,7 +27,8 @@ export interface PackageManagerCommands {
|
||||
dlx: string;
|
||||
list: string;
|
||||
run: (script: string, args?: string) => string;
|
||||
getRegistryUrl: string;
|
||||
// Make this required once bun adds programatically support for reading config https://github.com/oven-sh/bun/issues/7140
|
||||
getRegistryUrl?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -37,7 +38,9 @@ export function detectPackageManager(dir: string = ''): PackageManager {
|
||||
const nxJson = readNxJson();
|
||||
return (
|
||||
nxJson.cli?.packageManager ??
|
||||
(existsSync(join(dir, 'yarn.lock'))
|
||||
(existsSync(join(dir, 'bun.lockb'))
|
||||
? 'bun'
|
||||
: existsSync(join(dir, 'yarn.lock'))
|
||||
? 'yarn'
|
||||
: existsSync(join(dir, 'pnpm-lock.yaml'))
|
||||
? 'pnpm'
|
||||
@ -154,6 +157,21 @@ export function getPackageManagerCommand(
|
||||
getRegistryUrl: 'npm config get registry',
|
||||
};
|
||||
},
|
||||
bun: () => {
|
||||
// bun doesn't current support programatically reading config https://github.com/oven-sh/bun/issues/7140
|
||||
return {
|
||||
install: 'bun install',
|
||||
ciInstall: 'bun install --no-cache',
|
||||
updateLockFile: 'bun install --frozen-lockfile',
|
||||
add: 'bun install',
|
||||
addDev: 'bun install -D',
|
||||
rm: 'bun rm',
|
||||
exec: 'bun',
|
||||
dlx: 'bunx',
|
||||
run: (script: string, args: string) => `bun run ${script} -- ${args}`,
|
||||
list: 'bun pm ls',
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
return commands[packageManager]();
|
||||
@ -242,7 +260,12 @@ export function copyPackageManagerConfigurationFiles(
|
||||
root: string,
|
||||
destination: string
|
||||
) {
|
||||
for (const packageManagerConfigFile of ['.npmrc', '.yarnrc', '.yarnrc.yml']) {
|
||||
for (const packageManagerConfigFile of [
|
||||
'.npmrc',
|
||||
'.yarnrc',
|
||||
'.yarnrc.yml',
|
||||
'bunfig.toml',
|
||||
]) {
|
||||
// f is an absolute path, including the {workspaceRoot}.
|
||||
const f = findFileInPackageJsonDirectory(packageManagerConfigFile, root);
|
||||
if (f) {
|
||||
@ -267,6 +290,10 @@ export function copyPackageManagerConfigurationFiles(
|
||||
writeFileSync(destinationPath, updated);
|
||||
break;
|
||||
}
|
||||
case 'bunfig.toml': {
|
||||
copyFileSync(f, destinationPath);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -365,12 +392,16 @@ export async function packageRegistryView(
|
||||
args: string
|
||||
): Promise<string> {
|
||||
let pm = detectPackageManager();
|
||||
if (pm === 'yarn') {
|
||||
if (pm === 'yarn' || pm === 'bun') {
|
||||
/**
|
||||
* yarn has `yarn info` but it behaves differently than (p)npm,
|
||||
* which makes it's usage unreliable
|
||||
*
|
||||
* @see https://github.com/nrwl/nx/pull/9667#discussion_r842553994
|
||||
*
|
||||
* Bun has a pm ls function but it only relates to its lockfile
|
||||
* and acts differently from all other package managers
|
||||
* from Jarred: "it probably would be bun pm view <package-name>"
|
||||
*/
|
||||
pm = 'npm';
|
||||
}
|
||||
@ -385,13 +416,15 @@ export async function packageRegistryPack(
|
||||
version: string
|
||||
): Promise<{ tarballPath: string }> {
|
||||
let pm = detectPackageManager();
|
||||
if (pm === 'yarn') {
|
||||
if (pm === 'yarn' || pm === 'bun') {
|
||||
/**
|
||||
* `(p)npm pack` will download a tarball of the specified version,
|
||||
* whereas `yarn` pack creates a tarball of the active workspace, so it
|
||||
* does not work for getting the content of a library.
|
||||
*
|
||||
* @see https://github.com/nrwl/nx/pull/9667#discussion_r842553994
|
||||
*
|
||||
* bun doesn't currently support pack
|
||||
*/
|
||||
pm = 'npm';
|
||||
}
|
||||
|
||||
@ -166,6 +166,7 @@ jobs:
|
||||
with:
|
||||
node-version: 20
|
||||
cache: 'npm'
|
||||
|
||||
- run: npm ci
|
||||
- uses: nrwl/nx-set-shas@v4
|
||||
|
||||
@ -206,6 +207,7 @@ jobs:
|
||||
with:
|
||||
node-version: 20
|
||||
cache: 'npm'
|
||||
|
||||
- run: npm ci
|
||||
- uses: nrwl/nx-set-shas@v4
|
||||
|
||||
@ -216,6 +218,254 @@ jobs:
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`CI Workflow generator with bun should generate azure CI config 1`] = `
|
||||
"name: CI
|
||||
|
||||
trigger:
|
||||
- main
|
||||
pr:
|
||||
- main
|
||||
|
||||
variables:
|
||||
CI: 'true'
|
||||
\${{ if eq(variables['Build.Reason'], 'PullRequest') }}:
|
||||
NX_BRANCH: $(System.PullRequest.PullRequestNumber)
|
||||
TARGET_BRANCH: $[replace(variables['System.PullRequest.TargetBranch'],'refs/heads/','origin/')]
|
||||
BASE_SHA: $(git merge-base $(TARGET_BRANCH) HEAD)
|
||||
\${{ if ne(variables['Build.Reason'], 'PullRequest') }}:
|
||||
NX_BRANCH: $(Build.SourceBranchName)
|
||||
BASE_SHA: $(git rev-parse HEAD~1)
|
||||
HEAD_SHA: $(git rev-parse HEAD)
|
||||
|
||||
jobs:
|
||||
- job: main
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
steps:
|
||||
- checkout: self
|
||||
fetchDepth: 0
|
||||
# Set Azure Devops CLI default settings
|
||||
- bash: az devops configure --defaults organization=$(System.TeamFoundationCollectionUri) project=$(System.TeamProject)
|
||||
displayName: 'Set default Azure DevOps organization and project'
|
||||
# Get last successfull commit from Azure Devops CLI
|
||||
- bash: |
|
||||
LAST_SHA=$(az pipelines build list --branch $(Build.SourceBranchName) --definition-ids $(System.DefinitionId) --result succeeded --top 1 --query "[0].triggerInfo.\\"ci.sourceSha\\"")
|
||||
if [ -z "$LAST_SHA" ]
|
||||
then
|
||||
echo "Last successful commit not found. Using fallback 'HEAD~1': $BASE_SHA"
|
||||
else
|
||||
echo "Last successful commit SHA: $LAST_SHA"
|
||||
echo "##vso[task.setvariable variable=BASE_SHA]$LAST_SHA"
|
||||
fi
|
||||
displayName: 'Get last successful commit SHA'
|
||||
condition: ne(variables['Build.Reason'], 'PullRequest')
|
||||
env:
|
||||
AZURE_DEVOPS_EXT_PAT: $(System.AccessToken)
|
||||
|
||||
- script: npm install --prefix=$HOME/.local -g Bun
|
||||
displayName: Install Bun
|
||||
|
||||
# Connect your workspace on nx.app and uncomment this to enable task distribution.
|
||||
# The "--stop-agents-after" is optional, but allows idle agents to shut down once the "build" targets have been requested
|
||||
# - script: bunx nx-cloud start-ci-run --distribute-on="5 linux-medium-js" --stop-agents-after="build"
|
||||
|
||||
- script: bun install --no-cache
|
||||
- script: git branch --track main origin/main
|
||||
condition: eq(variables['Build.Reason'], 'PullRequest')
|
||||
|
||||
# Prepend any command with "nx-cloud record --" to record its logs to Nx Cloud
|
||||
# - script: bun nx-cloud record -- echo Hello World
|
||||
- script: bun nx affected --base=$(BASE_SHA) --head=$(HEAD_SHA) lint test build
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`CI Workflow generator with bun should generate bitbucket pipelines config 1`] = `
|
||||
"image: node:20
|
||||
|
||||
clone:
|
||||
depth: full
|
||||
|
||||
pipelines:
|
||||
pull-requests:
|
||||
'**':
|
||||
- step:
|
||||
name: 'Build and test affected apps on Pull Requests'
|
||||
script:
|
||||
- export NX_BRANCH=$BITBUCKET_PR_ID
|
||||
|
||||
- npm install --prefix=$HOME/.local -g bun
|
||||
|
||||
# Connect your workspace on nx.app and uncomment this to enable task distribution.
|
||||
# The "--stop-agents-after" is optional, but allows idle agents to shut down once the "build" targets have been requested
|
||||
# - bunx nx-cloud start-ci-run --distribute-on="5 linux-medium-js" --stop-agents-after="build"
|
||||
|
||||
- bun install --no-cache
|
||||
|
||||
- bun nx-cloud record -- nx format:check
|
||||
- bun nx affected --base=origin/main -t lint test build
|
||||
|
||||
branches:
|
||||
main:
|
||||
- step:
|
||||
name: 'Build and test affected apps on "main" branch changes'
|
||||
script:
|
||||
- export NX_BRANCH=$BITBUCKET_BRANCH
|
||||
# Connect your workspace on nx.app and uncomment this to enable task distribution.
|
||||
# The "--stop-agents-after" is optional, but allows idle agents to shut down once the "build" targets have been requested
|
||||
# - bunx nx-cloud start-ci-run --distribute-on="5 linux-medium-js" --stop-agents-after="build"
|
||||
|
||||
- npm install --prefix=$HOME/.local -g bun
|
||||
|
||||
- bun install --no-cache
|
||||
|
||||
# Prepend any command with "nx-cloud record --" to record its logs to Nx Cloud
|
||||
# - bun nx-cloud record -- echo Hello World
|
||||
- bun nx affected -t lint test build --base=HEAD~1
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`CI Workflow generator with bun should generate circleci CI config 1`] = `
|
||||
"version: 2.1
|
||||
|
||||
orbs:
|
||||
nx: nrwl/nx@1.6.2
|
||||
|
||||
jobs:
|
||||
main:
|
||||
docker:
|
||||
- image: cimg/node:lts-browsers
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
- run:
|
||||
name: Install Bun
|
||||
command: npm install --prefix=$HOME/.local -g bun
|
||||
|
||||
# Connect your workspace on nx.app and uncomment this to enable task distribution.
|
||||
# The "--stop-agents-after" is optional, but allows idle agents to shut down once the "build" targets have been requested
|
||||
# - run: bunx nx-cloud start-ci-run --distribute-on="5 linux-medium-js" --stop-agents-after="build"
|
||||
|
||||
- run: bun install --no-cache
|
||||
- nx/set-shas:
|
||||
main-branch-name: 'main'
|
||||
|
||||
# Prepend any command with "nx-cloud record --" to record its logs to Nx Cloud
|
||||
# - run: bun nx-cloud record -- echo Hello World
|
||||
- run: bun nx affected --base=$NX_BASE --head=$NX_HEAD -t lint test build
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
|
||||
ci:
|
||||
jobs:
|
||||
- main
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`CI Workflow generator with bun should generate github CI config 1`] = `
|
||||
"name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: oven-sh/setup-bun@v1
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
# Connect your workspace on nx.app and uncomment this to enable task distribution.
|
||||
# The "--stop-agents-after" is optional, but allows idle agents to shut down once the "build" targets have been requested
|
||||
# - run: bunx nx-cloud start-ci-run --distribute-on="5 linux-medium-js" --stop-agents-after="build"
|
||||
|
||||
- run: bun install --no-cache
|
||||
- uses: nrwl/nx-set-shas@v4
|
||||
|
||||
# Prepend any command with "nx-cloud record --" to record its logs to Nx Cloud
|
||||
# - run: bun nx-cloud record -- echo Hello World
|
||||
- run: bun nx affected -t lint test build
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`CI Workflow generator with bun should generate github CI config with custom name 1`] = `
|
||||
"name: My custom-workflow
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: oven-sh/setup-bun@v1
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
# Connect your workspace on nx.app and uncomment this to enable task distribution.
|
||||
# The "--stop-agents-after" is optional, but allows idle agents to shut down once the "build" targets have been requested
|
||||
# - run: bunx nx-cloud start-ci-run --distribute-on="5 linux-medium-js" --stop-agents-after="build"
|
||||
|
||||
- run: bun install --no-cache
|
||||
- uses: nrwl/nx-set-shas@v4
|
||||
|
||||
# Prepend any command with "nx-cloud record --" to record its logs to Nx Cloud
|
||||
# - run: bun nx-cloud record -- echo Hello World
|
||||
- run: bun nx affected -t lint test build
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`CI Workflow generator with bun should generate gitlab config 1`] = `
|
||||
"image: node:20
|
||||
variables:
|
||||
CI: 'true'
|
||||
|
||||
# Main job
|
||||
CI:
|
||||
interruptible: true
|
||||
only:
|
||||
- main
|
||||
- merge_requests
|
||||
script:
|
||||
- npm install --prefix=$HOME/.local -g bun
|
||||
|
||||
# Connect your workspace on nx.app and uncomment this to enable task distribution.
|
||||
# The "--stop-agents-after" is optional, but allows idle agents to shut down once the "build" targets have been requested
|
||||
# - bunx nx-cloud start-ci-run --distribute-on="5 linux-medium-js" --stop-agents-after="build"
|
||||
|
||||
- bun install --no-cache
|
||||
- NX_HEAD=$CI_COMMIT_SHA
|
||||
- NX_BASE=\${CI_MERGE_REQUEST_DIFF_BASE_SHA:-$CI_COMMIT_BEFORE_SHA}
|
||||
|
||||
# Prepend any command with "nx-cloud record --" to record its logs to Nx Cloud
|
||||
# - bun nx-cloud record -- echo Hello World
|
||||
- bun nx affected --base=$NX_BASE --head=$NX_HEAD -t lint test build
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`CI Workflow generator with npm should generate azure CI config 1`] = `
|
||||
"name: CI
|
||||
|
||||
@ -379,6 +629,7 @@ jobs:
|
||||
with:
|
||||
node-version: 20
|
||||
cache: 'npm'
|
||||
|
||||
- run: npm ci
|
||||
- uses: nrwl/nx-set-shas@v4
|
||||
|
||||
@ -418,6 +669,7 @@ jobs:
|
||||
with:
|
||||
node-version: 20
|
||||
cache: 'npm'
|
||||
|
||||
- run: npm ci
|
||||
- uses: nrwl/nx-set-shas@v4
|
||||
|
||||
@ -631,6 +883,7 @@ jobs:
|
||||
with:
|
||||
node-version: 20
|
||||
cache: 'pnpm'
|
||||
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- uses: nrwl/nx-set-shas@v4
|
||||
|
||||
@ -674,6 +927,7 @@ jobs:
|
||||
with:
|
||||
node-version: 20
|
||||
cache: 'pnpm'
|
||||
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- uses: nrwl/nx-set-shas@v4
|
||||
|
||||
@ -874,6 +1128,7 @@ jobs:
|
||||
with:
|
||||
node-version: 20
|
||||
cache: 'yarn'
|
||||
|
||||
- run: yarn install --frozen-lockfile
|
||||
- uses: nrwl/nx-set-shas@v4
|
||||
|
||||
@ -913,6 +1168,7 @@ jobs:
|
||||
with:
|
||||
node-version: 20
|
||||
cache: 'yarn'
|
||||
|
||||
- run: yarn install --frozen-lockfile
|
||||
- uses: nrwl/nx-set-shas@v4
|
||||
|
||||
|
||||
@ -21,7 +21,9 @@ jest.mock('fs', () => {
|
||||
return {
|
||||
...jest.requireActual<any>('fs'),
|
||||
existsSync: (p) =>
|
||||
p.endsWith('yarn.lock') || p.endsWith('pnpm-lock.yaml')
|
||||
p.endsWith('yarn.lock') ||
|
||||
p.endsWith('pnpm-lock.yaml') ||
|
||||
p.endsWith('bun.lockb')
|
||||
? memFs.existsSync(p)
|
||||
: actualFs.existsSync(p),
|
||||
};
|
||||
@ -38,11 +40,13 @@ describe('CI Workflow generator', () => {
|
||||
vol.reset();
|
||||
});
|
||||
|
||||
['npm', 'yarn', 'pnpm'].forEach((packageManager: PackageManager) => {
|
||||
['npm', 'yarn', 'pnpm', 'bun'].forEach((packageManager: PackageManager) => {
|
||||
describe(`with ${packageManager}`, () => {
|
||||
beforeEach(() => {
|
||||
let fileSys;
|
||||
if (packageManager === 'yarn') {
|
||||
if (packageManager === 'bun') {
|
||||
fileSys = { 'bun.lockb': '' };
|
||||
} else if (packageManager === 'yarn') {
|
||||
fileSys = { 'yarn.lock': '' };
|
||||
} else if (packageManager === 'pnpm') {
|
||||
fileSys = { 'pnpm-lock.yaml': '' };
|
||||
|
||||
@ -45,6 +45,11 @@ jobs:
|
||||
- script: npm install --prefix=$HOME/.local -g pnpm@8
|
||||
displayName: Install PNPM
|
||||
|
||||
<% } %>
|
||||
<% if(packageManager == 'bun'){ %>
|
||||
- script: npm install --prefix=$HOME/.local -g Bun
|
||||
displayName: Install Bun
|
||||
|
||||
<% } %>
|
||||
# Connect your workspace on <%= nxCloudHost %> and uncomment this to enable task distribution.
|
||||
# The "--stop-agents-after" is optional, but allows idle agents to shut down once the "<% if(hasE2E){ %>e2e-ci<% } else { %>build<% } %>" targets have been requested
|
||||
|
||||
@ -14,6 +14,10 @@ pipelines:
|
||||
<% if(packageManager == 'pnpm'){ %>
|
||||
- npm install --prefix=$HOME/.local -g pnpm@8
|
||||
|
||||
<% } %>
|
||||
<% if(packageManager == 'bun'){ %>
|
||||
- npm install --prefix=$HOME/.local -g bun
|
||||
|
||||
<% } %>
|
||||
# Connect your workspace on <%= nxCloudHost %> and uncomment this to enable task distribution.
|
||||
# The "--stop-agents-after" is optional, but allows idle agents to shut down once the "<% if(hasE2E){ %>e2e-ci<% } else { %>build<% } %>" targets have been requested
|
||||
@ -38,6 +42,9 @@ pipelines:
|
||||
<% if(packageManager == 'pnpm'){ %>
|
||||
- npm install --prefix=$HOME/.local -g pnpm@8
|
||||
<% } %>
|
||||
<% if(packageManager == 'bun'){ %>
|
||||
- npm install --prefix=$HOME/.local -g bun
|
||||
<% } %>
|
||||
- <%= packageManagerInstall %>
|
||||
|
||||
# Prepend any command with "nx-cloud record --" to record its logs to Nx Cloud
|
||||
|
||||
@ -14,6 +14,12 @@ jobs:
|
||||
name: Install PNPM
|
||||
command: npm install --prefix=$HOME/.local -g pnpm@8
|
||||
<% } %>
|
||||
<% if(packageManager == 'bun'){ %>
|
||||
- run:
|
||||
name: Install Bun
|
||||
command: npm install --prefix=$HOME/.local -g bun
|
||||
<% } %>
|
||||
|
||||
|
||||
# Connect your workspace on <%= nxCloudHost %> and uncomment this to enable task distribution.
|
||||
# The "--stop-agents-after" is optional, but allows idle agents to shut down once the "<% if(hasE2E){ %>e2e-ci<% } else { %>build<% } %>" targets have been requested
|
||||
|
||||
@ -22,16 +22,23 @@ jobs:
|
||||
with:
|
||||
version: 8
|
||||
<% } %>
|
||||
<% if(packageManager == 'bun'){ %>
|
||||
- uses: oven-sh/setup-bun@v1
|
||||
with:
|
||||
bun-version: latest
|
||||
<% } %>
|
||||
|
||||
# Connect your workspace on <%= nxCloudHost %> and uncomment this to enable task distribution.
|
||||
# The "--stop-agents-after" is optional, but allows idle agents to shut down once the "<% if(hasE2E){ %>e2e-ci<% } else { %>build<% } %>" targets have been requested
|
||||
# - run: <%= packageManagerPreInstallPrefix %> nx-cloud start-ci-run --distribute-on="5 linux-medium-js" --stop-agents-after="<% if(hasE2E){ %>e2e-ci<% } else { %>build<% } %>"
|
||||
|
||||
<% if(packageManager != 'bun'){ %>
|
||||
# Cache node_modules
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20
|
||||
cache: '<%= packageManager %>'
|
||||
<% } %>
|
||||
- run: <%= packageManagerInstall %>
|
||||
- uses: nrwl/nx-set-shas@v4
|
||||
|
||||
|
||||
@ -12,6 +12,9 @@ variables:
|
||||
<% if(packageManager == 'pnpm'){ %>
|
||||
- npm install --prefix=$HOME/.local -g pnpm@8
|
||||
<% } %>
|
||||
<% if(packageManager == 'bun'){ %>
|
||||
- npm install --prefix=$HOME/.local -g bun
|
||||
<% } %>
|
||||
# Connect your workspace on <%= nxCloudHost %> and uncomment this to enable task distribution.
|
||||
# The "--stop-agents-after" is optional, but allows idle agents to shut down once the "<% if(hasE2E){ %>e2e-ci<% } else { %>build<% } %>" targets have been requested
|
||||
# - <%= packageManagerPreInstallPrefix %> nx-cloud start-ci-run --distribute-on="5 linux-medium-js" --stop-agents-after="<% if(hasE2E){ %>e2e-ci<% } else { %>build<% } %>"
|
||||
|
||||
@ -56,7 +56,7 @@
|
||||
"packageManager": {
|
||||
"description": "The package manager used to install dependencies.",
|
||||
"type": "string",
|
||||
"enum": ["npm", "yarn", "pnpm"]
|
||||
"enum": ["npm", "yarn", "pnpm", "bun"]
|
||||
},
|
||||
"framework": {
|
||||
"description": "The framework which the application is using",
|
||||
|
||||
@ -62,7 +62,7 @@
|
||||
"packageManager": {
|
||||
"description": "The package manager used to install dependencies.",
|
||||
"type": "string",
|
||||
"enum": ["npm", "yarn", "pnpm"]
|
||||
"enum": ["npm", "yarn", "pnpm", "bun"]
|
||||
},
|
||||
"framework": {
|
||||
"description": "The framework which the application is using",
|
||||
|
||||
@ -7,6 +7,11 @@ function checkLockFiles() {
|
||||
'Invalid occurence of "package-lock.json" file. Please remove it and use only "pnpm-lock.yaml"'
|
||||
);
|
||||
}
|
||||
if (fs.existsSync('bun.lockb')) {
|
||||
errors.push(
|
||||
'Invalid occurence of "bun.lockb" file. Please remove it and use only "pnpm-lock.yaml"'
|
||||
);
|
||||
}
|
||||
if (fs.existsSync('yarn.lock')) {
|
||||
errors.push(
|
||||
'Invalid occurence of "yarn.lock" file. Please remove it and use only "pnpm-lock.yaml"'
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user