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`
|
Type: `string`
|
||||||
|
|
||||||
Choices: [npm, pnpm, yarn]
|
Choices: [bun, npm, pnpm, yarn]
|
||||||
|
|
||||||
Default: `npm`
|
Default: `npm`
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
# Type alias: PackageManager
|
# 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`
|
Type: `string`
|
||||||
|
|
||||||
Choices: [npm, pnpm, yarn]
|
Choices: [bun, npm, pnpm, yarn]
|
||||||
|
|
||||||
Default: `npm`
|
Default: `npm`
|
||||||
|
|
||||||
|
|||||||
@ -53,7 +53,7 @@
|
|||||||
"packageManager": {
|
"packageManager": {
|
||||||
"description": "The package manager used to install dependencies.",
|
"description": "The package manager used to install dependencies.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["npm", "yarn", "pnpm"]
|
"enum": ["npm", "yarn", "pnpm", "bun"]
|
||||||
},
|
},
|
||||||
"framework": {
|
"framework": {
|
||||||
"description": "The framework which the application is using",
|
"description": "The framework which the application is using",
|
||||||
|
|||||||
@ -59,7 +59,7 @@
|
|||||||
"packageManager": {
|
"packageManager": {
|
||||||
"description": "The package manager used to install dependencies.",
|
"description": "The package manager used to install dependencies.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["npm", "yarn", "pnpm"]
|
"enum": ["npm", "yarn", "pnpm", "bun"]
|
||||||
},
|
},
|
||||||
"framework": {
|
"framework": {
|
||||||
"description": "The framework which the application is using",
|
"description": "The framework which the application is using",
|
||||||
|
|||||||
@ -171,6 +171,19 @@ export function getPackageManagerCommand({
|
|||||||
list: 'pnpm ls --depth 10',
|
list: 'pnpm ls --depth 10',
|
||||||
runLerna: `pnpm exec lerna`,
|
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];
|
}[packageManager.trim() as PackageManager];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -78,7 +78,7 @@ export function newProject({
|
|||||||
packages,
|
packages,
|
||||||
}: {
|
}: {
|
||||||
name?: string;
|
name?: string;
|
||||||
packageManager?: 'npm' | 'yarn' | 'pnpm';
|
packageManager?: 'npm' | 'yarn' | 'pnpm' | 'bun';
|
||||||
unsetProjectNameAndRootFormat?: boolean;
|
unsetProjectNameAndRootFormat?: boolean;
|
||||||
readonly packages?: Array<NxPackage>;
|
readonly packages?: Array<NxPackage>;
|
||||||
} = {}): string {
|
} = {}): string {
|
||||||
@ -240,7 +240,7 @@ export function runCreateWorkspace(
|
|||||||
appName?: string;
|
appName?: string;
|
||||||
style?: string;
|
style?: string;
|
||||||
base?: string;
|
base?: string;
|
||||||
packageManager?: 'npm' | 'yarn' | 'pnpm';
|
packageManager?: 'npm' | 'yarn' | 'pnpm' | 'bun';
|
||||||
extraArgs?: string;
|
extraArgs?: string;
|
||||||
useDetectedPm?: boolean;
|
useDetectedPm?: boolean;
|
||||||
cwd?: string;
|
cwd?: string;
|
||||||
@ -358,7 +358,7 @@ export function runCreatePlugin(
|
|||||||
extraArgs,
|
extraArgs,
|
||||||
useDetectedPm = false,
|
useDetectedPm = false,
|
||||||
}: {
|
}: {
|
||||||
packageManager?: 'npm' | 'yarn' | 'pnpm';
|
packageManager?: 'npm' | 'yarn' | 'pnpm' | 'bun';
|
||||||
extraArgs?: string;
|
extraArgs?: string;
|
||||||
useDetectedPm?: boolean;
|
useDetectedPm?: boolean;
|
||||||
}
|
}
|
||||||
@ -543,6 +543,11 @@ export function newLernaWorkspace({
|
|||||||
...json.resolutions,
|
...json.resolutions,
|
||||||
...overrides,
|
...overrides,
|
||||||
};
|
};
|
||||||
|
} else if (packageManager === 'bun') {
|
||||||
|
json.overrides = {
|
||||||
|
...json.resolutions,
|
||||||
|
...overrides,
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
json.overrides = overrides;
|
json.overrides = overrides;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,7 +23,9 @@ export function getPublishedVersion(): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function detectPackageManager(dir: string = ''): PackageManager {
|
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'
|
? 'yarn'
|
||||||
: existsSync(join(dir, 'pnpm-lock.yaml')) ||
|
: existsSync(join(dir, 'pnpm-lock.yaml')) ||
|
||||||
existsSync(join(dir, 'pnpm-workspace.yaml'))
|
existsSync(join(dir, 'pnpm-workspace.yaml'))
|
||||||
@ -64,8 +66,8 @@ export function isVerboseE2ERun() {
|
|||||||
|
|
||||||
export const e2eCwd = `${e2eRoot}/nx`;
|
export const e2eCwd = `${e2eRoot}/nx`;
|
||||||
|
|
||||||
export function getSelectedPackageManager(): 'npm' | 'yarn' | 'pnpm' {
|
export function getSelectedPackageManager(): 'npm' | 'yarn' | 'pnpm' | 'bun' {
|
||||||
return (process.env.SELECTED_PM as 'npm' | 'yarn' | 'pnpm') || 'npm';
|
return (process.env.SELECTED_PM as 'npm' | 'yarn' | 'pnpm' | 'bun') || 'npm';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getNpmMajorVersion(): string | undefined {
|
export function getNpmMajorVersion(): string | undefined {
|
||||||
@ -108,6 +110,7 @@ export const packageManagerLockFile = {
|
|||||||
npm: 'package-lock.json',
|
npm: 'package-lock.json',
|
||||||
yarn: 'yarn.lock',
|
yarn: 'yarn.lock',
|
||||||
pnpm: 'pnpm-lock.yaml',
|
pnpm: 'pnpm-lock.yaml',
|
||||||
|
bun: 'bun.lockb',
|
||||||
};
|
};
|
||||||
|
|
||||||
export function ensureCypressInstallation() {
|
export function ensureCypressInstallation() {
|
||||||
|
|||||||
@ -374,7 +374,7 @@ describe('create-nx-workspace', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('Use detected package manager', () => {
|
describe('Use detected package manager', () => {
|
||||||
function setupProject(envPm: 'npm' | 'yarn' | 'pnpm') {
|
function setupProject(envPm: 'npm' | 'yarn' | 'pnpm' | 'bun') {
|
||||||
process.env.SELECTED_PM = envPm;
|
process.env.SELECTED_PM = envPm;
|
||||||
runCreateWorkspace(uniq('pm'), {
|
runCreateWorkspace(uniq('pm'), {
|
||||||
preset: 'apps',
|
preset: 'apps',
|
||||||
@ -389,7 +389,8 @@ describe('create-nx-workspace', () => {
|
|||||||
checkFilesExist(packageManagerLockFile['npm']);
|
checkFilesExist(packageManagerLockFile['npm']);
|
||||||
checkFilesDoNotExist(
|
checkFilesDoNotExist(
|
||||||
packageManagerLockFile['yarn'],
|
packageManagerLockFile['yarn'],
|
||||||
packageManagerLockFile['pnpm']
|
packageManagerLockFile['pnpm'],
|
||||||
|
packageManagerLockFile['bun']
|
||||||
);
|
);
|
||||||
process.env.SELECTED_PM = packageManager;
|
process.env.SELECTED_PM = packageManager;
|
||||||
}, 90000);
|
}, 90000);
|
||||||
@ -401,7 +402,21 @@ describe('create-nx-workspace', () => {
|
|||||||
checkFilesExist(packageManagerLockFile['pnpm']);
|
checkFilesExist(packageManagerLockFile['pnpm']);
|
||||||
checkFilesDoNotExist(
|
checkFilesDoNotExist(
|
||||||
packageManagerLockFile['yarn'],
|
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;
|
process.env.SELECTED_PM = packageManager;
|
||||||
}, 90000);
|
}, 90000);
|
||||||
@ -414,7 +429,8 @@ describe('create-nx-workspace', () => {
|
|||||||
checkFilesExist(packageManagerLockFile['yarn']);
|
checkFilesExist(packageManagerLockFile['yarn']);
|
||||||
checkFilesDoNotExist(
|
checkFilesDoNotExist(
|
||||||
packageManagerLockFile['pnpm'],
|
packageManagerLockFile['pnpm'],
|
||||||
packageManagerLockFile['npm']
|
packageManagerLockFile['npm'],
|
||||||
|
packageManagerLockFile['bun']
|
||||||
);
|
);
|
||||||
process.env.SELECTED_PM = packageManager;
|
process.env.SELECTED_PM = packageManager;
|
||||||
}, 90000);
|
}, 90000);
|
||||||
|
|||||||
@ -110,6 +110,7 @@ export async function determinePackageManager(
|
|||||||
{ name: 'npm', message: 'NPM' },
|
{ name: 'npm', message: 'NPM' },
|
||||||
{ name: 'yarn', message: 'Yarn' },
|
{ name: 'yarn', message: 'Yarn' },
|
||||||
{ name: 'pnpm', message: 'PNPM' },
|
{ name: 'pnpm', message: 'PNPM' },
|
||||||
|
{ name: 'bun', message: 'Bun' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
|||||||
@ -119,6 +119,11 @@ export async function recordStat(opts: {
|
|||||||
|
|
||||||
function shouldRecordStats(): boolean {
|
function shouldRecordStats(): boolean {
|
||||||
const pmc = getPackageManagerCommand();
|
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 {
|
try {
|
||||||
const stdout = execSync(pmc.getRegistryUrl, { encoding: 'utf-8' });
|
const stdout = execSync(pmc.getRegistryUrl, { encoding: 'utf-8' });
|
||||||
const url = new URL(stdout.trim());
|
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.
|
* 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 type PackageManager = typeof packageManagerList[number];
|
||||||
|
|
||||||
export function detectPackageManager(dir: string = ''): PackageManager {
|
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'
|
? 'yarn'
|
||||||
: existsSync(join(dir, 'pnpm-lock.yaml'))
|
: existsSync(join(dir, 'pnpm-lock.yaml'))
|
||||||
? 'pnpm'
|
? 'pnpm'
|
||||||
@ -38,7 +40,8 @@ export function getPackageManagerCommand(
|
|||||||
exec: string;
|
exec: string;
|
||||||
preInstall?: string;
|
preInstall?: string;
|
||||||
globalAdd: 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 pmVersion = getPackageManagerVersion(packageManager);
|
||||||
const [pmMajor, pmMinor] = pmVersion.split('.');
|
const [pmMajor, pmMinor] = pmVersion.split('.');
|
||||||
@ -79,6 +82,13 @@ export function getPackageManagerCommand(
|
|||||||
globalAdd: 'npm i -g',
|
globalAdd: 'npm i -g',
|
||||||
getRegistryUrl: 'npm config get registry',
|
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',
|
npm: 'package-lock.json',
|
||||||
yarn: 'yarn.lock',
|
yarn: 'yarn.lock',
|
||||||
pnpm: 'pnpm-lock.yaml',
|
pnpm: 'pnpm-lock.yaml',
|
||||||
|
bun: 'bun.lockb',
|
||||||
};
|
};
|
||||||
const packageManager = detectPackageManager(host.root);
|
const packageManager = detectPackageManager(host.root);
|
||||||
const packageLockFile = packageManagerLockFile[packageManager];
|
const packageLockFile = packageManagerLockFile[packageManager];
|
||||||
|
|||||||
@ -19,6 +19,7 @@ export default function update(tree: Tree) {
|
|||||||
npm: 'package-lock.json',
|
npm: 'package-lock.json',
|
||||||
yarn: 'yarn.lock',
|
yarn: 'yarn.lock',
|
||||||
pnpm: 'pnpm-lock.yaml',
|
pnpm: 'pnpm-lock.yaml',
|
||||||
|
bun: 'bun.lockb',
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const [name, config] of projects.entries()) {
|
for (const [name, config] of projects.entries()) {
|
||||||
|
|||||||
@ -366,7 +366,7 @@
|
|||||||
"packageManager": {
|
"packageManager": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The default package manager to use.",
|
"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 === 'yarn' ? 'yarn.lock' : null,
|
||||||
options.packageManager === 'pnpm' ? 'pnpm-lock.yaml' : null,
|
options.packageManager === 'pnpm' ? 'pnpm-lock.yaml' : null,
|
||||||
options.packageManager === 'npm' ? 'package-lock.json' : null,
|
options.packageManager === 'npm' ? 'package-lock.json' : null,
|
||||||
|
options.packageManager === 'bun' ? 'bun.lockb' : null,
|
||||||
];
|
];
|
||||||
|
|
||||||
const optionalCraFiles = ['README.md'];
|
const optionalCraFiles = ['README.md'];
|
||||||
|
|||||||
@ -24,6 +24,7 @@ import { hashArray } from '../../hasher/file-hasher';
|
|||||||
import { detectPackageManager } from '../../utils/package-manager';
|
import { detectPackageManager } from '../../utils/package-manager';
|
||||||
import { workspaceRoot } from '../../utils/workspace-root';
|
import { workspaceRoot } from '../../utils/workspace-root';
|
||||||
import { nxVersion } from '../../utils/versions';
|
import { nxVersion } from '../../utils/versions';
|
||||||
|
import { execSync } from 'child_process';
|
||||||
|
|
||||||
export const name = 'nx/js/dependencies-and-lockfile';
|
export const name = 'nx/js/dependencies-and-lockfile';
|
||||||
|
|
||||||
@ -51,7 +52,10 @@ export const createNodes: CreateNodes = [
|
|||||||
}
|
}
|
||||||
|
|
||||||
const lockFilePath = join(workspaceRoot, lockFile);
|
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);
|
const lockFileHash = getLockFileHash(lockFileContents);
|
||||||
|
|
||||||
if (!lockFileNeedsReprocessing(lockFileHash)) {
|
if (!lockFileNeedsReprocessing(lockFileHash)) {
|
||||||
@ -91,7 +95,10 @@ export const createDependencies: CreateDependencies = (
|
|||||||
parsedLockFile.externalNodes
|
parsedLockFile.externalNodes
|
||||||
) {
|
) {
|
||||||
const lockFilePath = join(workspaceRoot, getLockFileName(packageManager));
|
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);
|
const lockFileHash = getLockFileHash(lockFileContents);
|
||||||
|
|
||||||
if (!lockFileNeedsReprocessing(lockFileHash)) {
|
if (!lockFileNeedsReprocessing(lockFileHash)) {
|
||||||
|
|||||||
@ -45,11 +45,18 @@ import {
|
|||||||
const YARN_LOCK_FILE = 'yarn.lock';
|
const YARN_LOCK_FILE = 'yarn.lock';
|
||||||
const NPM_LOCK_FILE = 'package-lock.json';
|
const NPM_LOCK_FILE = 'package-lock.json';
|
||||||
const PNPM_LOCK_FILE = 'pnpm-lock.yaml';
|
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 YARN_LOCK_PATH = join(workspaceRoot, YARN_LOCK_FILE);
|
||||||
const NPM_LOCK_PATH = join(workspaceRoot, NPM_LOCK_FILE);
|
const NPM_LOCK_PATH = join(workspaceRoot, NPM_LOCK_FILE);
|
||||||
const PNPM_LOCK_PATH = join(workspaceRoot, PNPM_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}
|
* Parses lock file and maps dependencies and metadata to {@link LockFileGraph}
|
||||||
@ -73,6 +80,11 @@ export function getLockFileNodes(
|
|||||||
if (packageManager === 'npm') {
|
if (packageManager === 'npm') {
|
||||||
return getNpmLockfileNodes(contents, lockFileHash);
|
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) {
|
} catch (e) {
|
||||||
if (!isPostInstallProcess()) {
|
if (!isPostInstallProcess()) {
|
||||||
output.error({
|
output.error({
|
||||||
@ -104,6 +116,10 @@ export function getLockFileDependencies(
|
|||||||
if (packageManager === 'npm') {
|
if (packageManager === 'npm') {
|
||||||
return getNpmLockfileDependencies(contents, lockFileHash, context);
|
return getNpmLockfileDependencies(contents, lockFileHash, context);
|
||||||
}
|
}
|
||||||
|
if (packageManager === 'bun') {
|
||||||
|
// bun uses yarn v1 for the file format
|
||||||
|
return getYarnLockfileDependencies(contents, lockFileHash, context);
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (!isPostInstallProcess()) {
|
if (!isPostInstallProcess()) {
|
||||||
output.error({
|
output.error({
|
||||||
@ -126,6 +142,9 @@ export function lockFileExists(packageManager: PackageManager): boolean {
|
|||||||
if (packageManager === 'npm') {
|
if (packageManager === 'npm') {
|
||||||
return existsSync(NPM_LOCK_PATH);
|
return existsSync(NPM_LOCK_PATH);
|
||||||
}
|
}
|
||||||
|
if (packageManager === 'bun') {
|
||||||
|
return existsSync(BUN_LOCK_PATH);
|
||||||
|
}
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unknown package manager ${packageManager} or lock file missing`
|
`Unknown package manager ${packageManager} or lock file missing`
|
||||||
);
|
);
|
||||||
@ -146,6 +165,9 @@ export function getLockFileName(packageManager: PackageManager): string {
|
|||||||
if (packageManager === 'npm') {
|
if (packageManager === 'npm') {
|
||||||
return NPM_LOCK_FILE;
|
return NPM_LOCK_FILE;
|
||||||
}
|
}
|
||||||
|
if (packageManager === 'bun') {
|
||||||
|
return BUN_LOCK_FILE;
|
||||||
|
}
|
||||||
throw new Error(`Unknown package manager: ${packageManager}`);
|
throw new Error(`Unknown package manager: ${packageManager}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,6 +181,9 @@ function getLockFilePath(packageManager: PackageManager): string {
|
|||||||
if (packageManager === 'npm') {
|
if (packageManager === 'npm') {
|
||||||
return NPM_LOCK_PATH;
|
return NPM_LOCK_PATH;
|
||||||
}
|
}
|
||||||
|
if (packageManager === 'bun') {
|
||||||
|
return BUN_LOCK_PATH;
|
||||||
|
}
|
||||||
throw new Error(`Unknown package manager: ${packageManager}`);
|
throw new Error(`Unknown package manager: ${packageManager}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,6 +216,12 @@ export function createLockFile(
|
|||||||
const prunedGraph = pruneProjectGraph(graph, packageJson);
|
const prunedGraph = pruneProjectGraph(graph, packageJson);
|
||||||
return stringifyNpmLockfile(prunedGraph, content, normalizedPackageJson);
|
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) {
|
} catch (e) {
|
||||||
if (!isPostInstallProcess()) {
|
if (!isPostInstallProcess()) {
|
||||||
const additionalInfo = [
|
const additionalInfo = [
|
||||||
|
|||||||
@ -101,6 +101,11 @@ export async function recordStat(opts: {
|
|||||||
|
|
||||||
function shouldRecordStats(): boolean {
|
function shouldRecordStats(): boolean {
|
||||||
const pmc = getPackageManagerCommand();
|
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 {
|
try {
|
||||||
const stdout = execSync(pmc.getRegistryUrl, { encoding: 'utf-8' });
|
const stdout = execSync(pmc.getRegistryUrl, { encoding: 'utf-8' });
|
||||||
const url = new URL(stdout.trim());
|
const url = new URL(stdout.trim());
|
||||||
|
|||||||
@ -10,6 +10,9 @@ import {
|
|||||||
|
|
||||||
describe('package-manager', () => {
|
describe('package-manager', () => {
|
||||||
describe('detectPackageManager', () => {
|
describe('detectPackageManager', () => {
|
||||||
|
afterEach(() => {
|
||||||
|
jest.restoreAllMocks();
|
||||||
|
});
|
||||||
it('should detect package manager in nxJson', () => {
|
it('should detect package manager in nxJson', () => {
|
||||||
jest.spyOn(configModule, 'readNxJson').mockReturnValueOnce({
|
jest.spyOn(configModule, 'readNxJson').mockReturnValueOnce({
|
||||||
cli: {
|
cli: {
|
||||||
@ -30,13 +33,15 @@ describe('package-manager', () => {
|
|||||||
return false;
|
return false;
|
||||||
case 'package-lock.json':
|
case 'package-lock.json':
|
||||||
return false;
|
return false;
|
||||||
|
case 'bun.lockb':
|
||||||
|
return false;
|
||||||
default:
|
default:
|
||||||
return jest.requireActual('fs').existsSync(p);
|
return jest.requireActual('fs').existsSync(p);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const packageManager = detectPackageManager();
|
const packageManager = detectPackageManager();
|
||||||
expect(packageManager).toEqual('yarn');
|
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', () => {
|
it('should detect pnpm package manager from pnpm-lock.yaml', () => {
|
||||||
@ -49,6 +54,8 @@ describe('package-manager', () => {
|
|||||||
return true;
|
return true;
|
||||||
case 'package-lock.json':
|
case 'package-lock.json':
|
||||||
return false;
|
return false;
|
||||||
|
case 'bun.lockb':
|
||||||
|
return false;
|
||||||
default:
|
default:
|
||||||
return jest.requireActual('fs').existsSync(p);
|
return jest.requireActual('fs').existsSync(p);
|
||||||
}
|
}
|
||||||
@ -58,6 +65,27 @@ describe('package-manager', () => {
|
|||||||
expect(fs.existsSync).toHaveBeenCalledTimes(3);
|
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', () => {
|
it('should use npm package manager as default', () => {
|
||||||
jest.spyOn(configModule, 'readNxJson').mockReturnValueOnce({});
|
jest.spyOn(configModule, 'readNxJson').mockReturnValueOnce({});
|
||||||
jest.spyOn(fs, 'existsSync').mockImplementation((p) => {
|
jest.spyOn(fs, 'existsSync').mockImplementation((p) => {
|
||||||
@ -68,13 +96,15 @@ describe('package-manager', () => {
|
|||||||
return false;
|
return false;
|
||||||
case 'package-lock.json':
|
case 'package-lock.json':
|
||||||
return false;
|
return false;
|
||||||
|
case 'bun.lockb':
|
||||||
|
return false;
|
||||||
default:
|
default:
|
||||||
return jest.requireActual('fs').existsSync(p);
|
return jest.requireActual('fs').existsSync(p);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const packageManager = detectPackageManager();
|
const packageManager = detectPackageManager();
|
||||||
expect(packageManager).toEqual('npm');
|
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);
|
const execAsync = promisify(exec);
|
||||||
|
|
||||||
export type PackageManager = 'yarn' | 'pnpm' | 'npm';
|
export type PackageManager = 'yarn' | 'pnpm' | 'npm' | 'bun';
|
||||||
|
|
||||||
export interface PackageManagerCommands {
|
export interface PackageManagerCommands {
|
||||||
preInstall?: string;
|
preInstall?: string;
|
||||||
@ -27,7 +27,8 @@ export interface PackageManagerCommands {
|
|||||||
dlx: string;
|
dlx: string;
|
||||||
list: string;
|
list: string;
|
||||||
run: (script: string, args?: string) => 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();
|
const nxJson = readNxJson();
|
||||||
return (
|
return (
|
||||||
nxJson.cli?.packageManager ??
|
nxJson.cli?.packageManager ??
|
||||||
(existsSync(join(dir, 'yarn.lock'))
|
(existsSync(join(dir, 'bun.lockb'))
|
||||||
|
? 'bun'
|
||||||
|
: existsSync(join(dir, 'yarn.lock'))
|
||||||
? 'yarn'
|
? 'yarn'
|
||||||
: existsSync(join(dir, 'pnpm-lock.yaml'))
|
: existsSync(join(dir, 'pnpm-lock.yaml'))
|
||||||
? 'pnpm'
|
? 'pnpm'
|
||||||
@ -154,6 +157,21 @@ export function getPackageManagerCommand(
|
|||||||
getRegistryUrl: 'npm config get registry',
|
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]();
|
return commands[packageManager]();
|
||||||
@ -242,7 +260,12 @@ export function copyPackageManagerConfigurationFiles(
|
|||||||
root: string,
|
root: string,
|
||||||
destination: 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}.
|
// f is an absolute path, including the {workspaceRoot}.
|
||||||
const f = findFileInPackageJsonDirectory(packageManagerConfigFile, root);
|
const f = findFileInPackageJsonDirectory(packageManagerConfigFile, root);
|
||||||
if (f) {
|
if (f) {
|
||||||
@ -267,6 +290,10 @@ export function copyPackageManagerConfigurationFiles(
|
|||||||
writeFileSync(destinationPath, updated);
|
writeFileSync(destinationPath, updated);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'bunfig.toml': {
|
||||||
|
copyFileSync(f, destinationPath);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -365,12 +392,16 @@ export async function packageRegistryView(
|
|||||||
args: string
|
args: string
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
let pm = detectPackageManager();
|
let pm = detectPackageManager();
|
||||||
if (pm === 'yarn') {
|
if (pm === 'yarn' || pm === 'bun') {
|
||||||
/**
|
/**
|
||||||
* yarn has `yarn info` but it behaves differently than (p)npm,
|
* yarn has `yarn info` but it behaves differently than (p)npm,
|
||||||
* which makes it's usage unreliable
|
* which makes it's usage unreliable
|
||||||
*
|
*
|
||||||
* @see https://github.com/nrwl/nx/pull/9667#discussion_r842553994
|
* @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';
|
pm = 'npm';
|
||||||
}
|
}
|
||||||
@ -385,13 +416,15 @@ export async function packageRegistryPack(
|
|||||||
version: string
|
version: string
|
||||||
): Promise<{ tarballPath: string }> {
|
): Promise<{ tarballPath: string }> {
|
||||||
let pm = detectPackageManager();
|
let pm = detectPackageManager();
|
||||||
if (pm === 'yarn') {
|
if (pm === 'yarn' || pm === 'bun') {
|
||||||
/**
|
/**
|
||||||
* `(p)npm pack` will download a tarball of the specified version,
|
* `(p)npm pack` will download a tarball of the specified version,
|
||||||
* whereas `yarn` pack creates a tarball of the active workspace, so it
|
* whereas `yarn` pack creates a tarball of the active workspace, so it
|
||||||
* does not work for getting the content of a library.
|
* does not work for getting the content of a library.
|
||||||
*
|
*
|
||||||
* @see https://github.com/nrwl/nx/pull/9667#discussion_r842553994
|
* @see https://github.com/nrwl/nx/pull/9667#discussion_r842553994
|
||||||
|
*
|
||||||
|
* bun doesn't currently support pack
|
||||||
*/
|
*/
|
||||||
pm = 'npm';
|
pm = 'npm';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -166,6 +166,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
|
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
- uses: nrwl/nx-set-shas@v4
|
- uses: nrwl/nx-set-shas@v4
|
||||||
|
|
||||||
@ -206,6 +207,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
|
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
- uses: nrwl/nx-set-shas@v4
|
- 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`] = `
|
exports[`CI Workflow generator with npm should generate azure CI config 1`] = `
|
||||||
"name: CI
|
"name: CI
|
||||||
|
|
||||||
@ -379,6 +629,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
|
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
- uses: nrwl/nx-set-shas@v4
|
- uses: nrwl/nx-set-shas@v4
|
||||||
|
|
||||||
@ -418,6 +669,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
|
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
- uses: nrwl/nx-set-shas@v4
|
- uses: nrwl/nx-set-shas@v4
|
||||||
|
|
||||||
@ -631,6 +883,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|
||||||
- run: pnpm install --frozen-lockfile
|
- run: pnpm install --frozen-lockfile
|
||||||
- uses: nrwl/nx-set-shas@v4
|
- uses: nrwl/nx-set-shas@v4
|
||||||
|
|
||||||
@ -674,6 +927,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|
||||||
- run: pnpm install --frozen-lockfile
|
- run: pnpm install --frozen-lockfile
|
||||||
- uses: nrwl/nx-set-shas@v4
|
- uses: nrwl/nx-set-shas@v4
|
||||||
|
|
||||||
@ -874,6 +1128,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
|
|
||||||
- run: yarn install --frozen-lockfile
|
- run: yarn install --frozen-lockfile
|
||||||
- uses: nrwl/nx-set-shas@v4
|
- uses: nrwl/nx-set-shas@v4
|
||||||
|
|
||||||
@ -913,6 +1168,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
|
|
||||||
- run: yarn install --frozen-lockfile
|
- run: yarn install --frozen-lockfile
|
||||||
- uses: nrwl/nx-set-shas@v4
|
- uses: nrwl/nx-set-shas@v4
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,9 @@ jest.mock('fs', () => {
|
|||||||
return {
|
return {
|
||||||
...jest.requireActual<any>('fs'),
|
...jest.requireActual<any>('fs'),
|
||||||
existsSync: (p) =>
|
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)
|
? memFs.existsSync(p)
|
||||||
: actualFs.existsSync(p),
|
: actualFs.existsSync(p),
|
||||||
};
|
};
|
||||||
@ -38,11 +40,13 @@ describe('CI Workflow generator', () => {
|
|||||||
vol.reset();
|
vol.reset();
|
||||||
});
|
});
|
||||||
|
|
||||||
['npm', 'yarn', 'pnpm'].forEach((packageManager: PackageManager) => {
|
['npm', 'yarn', 'pnpm', 'bun'].forEach((packageManager: PackageManager) => {
|
||||||
describe(`with ${packageManager}`, () => {
|
describe(`with ${packageManager}`, () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
let fileSys;
|
let fileSys;
|
||||||
if (packageManager === 'yarn') {
|
if (packageManager === 'bun') {
|
||||||
|
fileSys = { 'bun.lockb': '' };
|
||||||
|
} else if (packageManager === 'yarn') {
|
||||||
fileSys = { 'yarn.lock': '' };
|
fileSys = { 'yarn.lock': '' };
|
||||||
} else if (packageManager === 'pnpm') {
|
} else if (packageManager === 'pnpm') {
|
||||||
fileSys = { 'pnpm-lock.yaml': '' };
|
fileSys = { 'pnpm-lock.yaml': '' };
|
||||||
|
|||||||
@ -45,6 +45,11 @@ jobs:
|
|||||||
- script: npm install --prefix=$HOME/.local -g pnpm@8
|
- script: npm install --prefix=$HOME/.local -g pnpm@8
|
||||||
displayName: Install PNPM
|
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.
|
# 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
|
# 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'){ %>
|
<% if(packageManager == 'pnpm'){ %>
|
||||||
- npm install --prefix=$HOME/.local -g pnpm@8
|
- 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.
|
# 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
|
# 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'){ %>
|
<% if(packageManager == 'pnpm'){ %>
|
||||||
- npm install --prefix=$HOME/.local -g pnpm@8
|
- npm install --prefix=$HOME/.local -g pnpm@8
|
||||||
<% } %>
|
<% } %>
|
||||||
|
<% if(packageManager == 'bun'){ %>
|
||||||
|
- npm install --prefix=$HOME/.local -g bun
|
||||||
|
<% } %>
|
||||||
- <%= packageManagerInstall %>
|
- <%= packageManagerInstall %>
|
||||||
|
|
||||||
# Prepend any command with "nx-cloud record --" to record its logs to Nx Cloud
|
# Prepend any command with "nx-cloud record --" to record its logs to Nx Cloud
|
||||||
|
|||||||
@ -14,6 +14,12 @@ jobs:
|
|||||||
name: Install PNPM
|
name: Install PNPM
|
||||||
command: npm install --prefix=$HOME/.local -g pnpm@8
|
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.
|
# 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
|
# 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:
|
with:
|
||||||
version: 8
|
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.
|
# 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
|
# 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<% } %>"
|
# - 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
|
# Cache node_modules
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
cache: '<%= packageManager %>'
|
cache: '<%= packageManager %>'
|
||||||
|
<% } %>
|
||||||
- run: <%= packageManagerInstall %>
|
- run: <%= packageManagerInstall %>
|
||||||
- uses: nrwl/nx-set-shas@v4
|
- uses: nrwl/nx-set-shas@v4
|
||||||
|
|
||||||
|
|||||||
@ -12,6 +12,9 @@ variables:
|
|||||||
<% if(packageManager == 'pnpm'){ %>
|
<% if(packageManager == 'pnpm'){ %>
|
||||||
- npm install --prefix=$HOME/.local -g pnpm@8
|
- 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.
|
# 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
|
# 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<% } %>"
|
# - <%= 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": {
|
"packageManager": {
|
||||||
"description": "The package manager used to install dependencies.",
|
"description": "The package manager used to install dependencies.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["npm", "yarn", "pnpm"]
|
"enum": ["npm", "yarn", "pnpm", "bun"]
|
||||||
},
|
},
|
||||||
"framework": {
|
"framework": {
|
||||||
"description": "The framework which the application is using",
|
"description": "The framework which the application is using",
|
||||||
|
|||||||
@ -62,7 +62,7 @@
|
|||||||
"packageManager": {
|
"packageManager": {
|
||||||
"description": "The package manager used to install dependencies.",
|
"description": "The package manager used to install dependencies.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["npm", "yarn", "pnpm"]
|
"enum": ["npm", "yarn", "pnpm", "bun"]
|
||||||
},
|
},
|
||||||
"framework": {
|
"framework": {
|
||||||
"description": "The framework which the application is using",
|
"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"'
|
'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')) {
|
if (fs.existsSync('yarn.lock')) {
|
||||||
errors.push(
|
errors.push(
|
||||||
'Invalid occurence of "yarn.lock" file. Please remove it and use only "pnpm-lock.yaml"'
|
'Invalid occurence of "yarn.lock" file. Please remove it and use only "pnpm-lock.yaml"'
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user