Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/lockfile-explorer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Here's how to invoke the **Rush Lockfile Explorer** tool:
```bash
# Install the NPM package globally.
#
# (You could substitute "pnpm" or "yarn" instead of "npm" here. To avoid confusing
# (You could substitute "bun" or "pnpm" or "yarn" instead of "npm" here. To avoid confusing
# duplicate installs, always use the same tool for global installations!)
npm install -g @rushstack/lockfile-explorer

Expand Down
2 changes: 1 addition & 1 deletion apps/rush/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

- **A single NPM install:** In one step, Rush installs all the dependencies for all your projects into a common folder. This is not just a "package.json" file at the root of your repo (which might set you up to accidentally `require()` a sibling's dependencies). Instead, Rush uses symlinks to reconstruct an accurate "node_modules" folder for each project, without any of the limitations or glitches that seem to plague other approaches.

⏵ **This algorithm supports the [PNPM, NPM, and Yarn](https://rushjs.io/pages/maintainer/package_managers/) package managers.**
⏵ **This algorithm supports the [Bun, PNPM, NPM, and Yarn](https://rushjs.io/pages/maintainer/package_managers/) package managers.**

- **Automatic local linking:** Inside a Rush repo, all your projects are automatically symlinked to each other. When you make a change, you can see the downstream effects without publishing anything, and without any `npm link` headaches. If you don't want certain projects to get linked, that's supported, too.

Expand Down
Empty file modified apps/rush/bin/rush-pnpm
100644 → 100755
Empty file.
2 changes: 1 addition & 1 deletion apps/rush/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@microsoft/rush",
"version": "5.106.0",
"version": "5.106.0-bun",
"description": "A professional solution for consolidating all your JavaScript projects in one Git repo",
"keywords": [
"install",
Expand Down
975 changes: 490 additions & 485 deletions build-tests/install-test-workspace/workspace/common/pnpm-lock.yaml

Large diffs are not rendered by default.

17 changes: 16 additions & 1 deletion common/reviews/api/rush-lib.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,13 @@ export enum BumpType {
'prerelease' = 1
}

// @public
export class BunOptionsConfiguration extends PackageManagerOptionsConfigurationBase {
// @internal
constructor(json: _IBunOptionsJson);
readonly useWorkspaces: boolean;
}

// @public
export class ChangeManager {
static createEmptyChangeFiles(rushConfiguration: RushConfiguration, projectName: string, emailAddress: string): string | undefined;
Expand Down Expand Up @@ -310,6 +317,11 @@ export interface _IBuiltInPluginConfiguration extends _IRushPluginConfigurationB
pluginPackageFolder: string;
}

// @internal
export interface _IBunOptionsJson extends IPackageManagerOptionsJsonBase {
useWorkspaces?: boolean;
}

// @beta (undocumented)
export interface ICloudBuildCacheProvider {
// (undocumented)
Expand Down Expand Up @@ -934,7 +946,7 @@ export abstract class PackageManager {
}

// @public
export type PackageManagerName = 'pnpm' | 'npm' | 'yarn';
export type PackageManagerName = 'pnpm' | 'npm' | 'yarn' | 'bun';

// @public
export abstract class PackageManagerOptionsConfigurationBase implements IPackageManagerOptionsJsonBase {
Expand Down Expand Up @@ -1035,6 +1047,8 @@ export class Rush {
export class RushConfiguration {
readonly allowMostlyStandardPackageNames: boolean;
readonly approvedPackagesPolicy: ApprovedPackagesPolicy;
readonly bunCacheFolder: string;
readonly bunOptions: BunOptionsConfiguration;
readonly changesFolder: string;
// @deprecated
get committedShrinkwrapFilename(): string;
Expand Down Expand Up @@ -1179,6 +1193,7 @@ export class RushConstants {
static readonly buildCacheVersion: number;
static readonly buildCommandName: string;
static readonly bulkCommandKind: 'bulk';
static readonly bunShrinkwrapFilename: string;
static readonly bypassPolicyFlagLongName: '--bypass-policy';
static readonly changeFilesFolderName: string;
static readonly cobuildFilename: string;
Expand Down
1 change: 1 addition & 0 deletions libraries/rush-lib/assets/rush-init/[dot]gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pnpm-lock.yaml merge=text
shrinkwrap.yaml merge=binary
npm-shrinkwrap.json merge=binary
yarn.lock merge=binary
*.lockb merge=binary diff=lockb

# Rush's JSON config files use JavaScript-style code comments. The rule below prevents pedantic
# syntax highlighters such as GitHub's from highlighting these comments as errors. Your text editor
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[install]
# set default registry as a string
registry = "https://registry.npmjs.org"
3 changes: 2 additions & 1 deletion libraries/rush-lib/assets/rush-init/rush.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@
* Rush installs its own local copy of the package manager to ensure that your build process
* is fully isolated from whatever tools are present in the local environment.
*
* Specify one of: "pnpmVersion", "npmVersion", or "yarnVersion". See the Rush documentation
* Specify one of: "bunVersion", "pnpmVersion", "npmVersion", or "yarnVersion". See the Rush documentation
* for details about these alternatives.
*/
"pnpmVersion": "7.33.5",

/*[LINE "HYPOTHETICAL"]*/ "npmVersion": "6.14.15",
/*[LINE "HYPOTHETICAL"]*/ "yarnVersion": "1.9.4",
/*[LINE "HYPOTHETICAL"]*/ "bunVersion": "1.9.4",

/**
* Older releases of the Node.js engine may be missing features required by your system.
Expand Down
29 changes: 28 additions & 1 deletion libraries/rush-lib/src/api/RushConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { PackageManagerName, PackageManager } from './packageManager/PackageMana
import { NpmPackageManager } from './packageManager/NpmPackageManager';
import { YarnPackageManager } from './packageManager/YarnPackageManager';
import { PnpmPackageManager } from './packageManager/PnpmPackageManager';
import { BunPackageManager } from './packageManager/BunPackageManager';
import { ExperimentsConfiguration } from './ExperimentsConfiguration';
import { PackageNameParsers } from './PackageNameParsers';
import { RepoStateFile } from '../logic/RepoStateFile';
Expand All @@ -37,6 +38,7 @@ import { RushPluginsConfiguration } from './RushPluginsConfiguration';
import { IPnpmOptionsJson, PnpmOptionsConfiguration } from '../logic/pnpm/PnpmOptionsConfiguration';
import { INpmOptionsJson, NpmOptionsConfiguration } from '../logic/npm/NpmOptionsConfiguration';
import { IYarnOptionsJson, YarnOptionsConfiguration } from '../logic/yarn/YarnOptionsConfiguration';
import { IBunOptionsJson, BunOptionsConfiguration } from '../logic/bun/BunOptionsConfiguration';
import schemaJson from '../schemas/rush.schema.json';

import type * as DependencyAnalyzerModuleType from '../logic/DependencyAnalyzer';
Expand Down Expand Up @@ -157,6 +159,7 @@ export interface IRushConfigurationJson {
npmVersion?: string;
pnpmVersion?: string;
yarnVersion?: string;
bunVersion?: string;
rushVersion: string;
repository?: IRushRepositoryJson;
nodeSupportedVersionRange?: string;
Expand All @@ -175,6 +178,7 @@ export interface IRushConfigurationJson {
npmOptions?: INpmOptionsJson;
pnpmOptions?: IPnpmOptionsJson;
yarnOptions?: IYarnOptionsJson;
bunOptions?: IBunOptionsJson;
ensureConsistentVersions?: boolean;
variants?: IRushVariantOptionsJson[];
}
Expand Down Expand Up @@ -320,6 +324,13 @@ export class RushConfiguration {
*/
public readonly yarnCacheFolder: string;

/**
* The local folder that will store the Bun package cache.
*
* Example: `C:\MyRepo\common\temp\bun-cache`
*/
public readonly bunCacheFolder: string;

/**
* The filename (without any path) of the shrinkwrap file that is used by the package manager.
* @remarks
Expand Down Expand Up @@ -509,11 +520,17 @@ export class RushConfiguration {
*/
public readonly yarnOptions: YarnOptionsConfiguration;

/**
* {@inheritDoc YarnOptionsConfiguration}
*/
public readonly bunOptions: BunOptionsConfiguration;

/**
* The configuration options used by the current package manager.
* @remarks
* For package manager specific variants, reference {@link RushConfiguration.npmOptions | npmOptions},
* {@link RushConfiguration.pnpmOptions | pnpmOptions}, or {@link RushConfiguration.yarnOptions | yarnOptions}.
* {@link RushConfiguration.pnpmOptions | pnpmOptions}, or {@link RushConfiguration.yarnOptions | yarnOptions}
* or {@link RushConfiguration.bunOptions | bunOptions}.
*/
public readonly packageManagerOptions!: PackageManagerOptionsConfigurationBase;

Expand Down Expand Up @@ -612,6 +629,7 @@ export class RushConfiguration {
this.npmCacheFolder = path.resolve(path.join(this.commonTempFolder, 'npm-cache'));
this.npmTmpFolder = path.resolve(path.join(this.commonTempFolder, 'npm-tmp'));
this.yarnCacheFolder = path.resolve(path.join(this.commonTempFolder, 'yarn-cache'));
this.bunCacheFolder = path.resolve(path.join(this.commonTempFolder, 'bun-cache'));

this.changesFolder = path.join(this.commonFolder, RushConstants.changeFilesFolderName);

Expand All @@ -635,6 +653,7 @@ export class RushConfiguration {

this.npmOptions = new NpmOptionsConfiguration(rushConfigurationJson.npmOptions || {});
this.yarnOptions = new YarnOptionsConfiguration(rushConfigurationJson.yarnOptions || {});
this.bunOptions = new BunOptionsConfiguration(rushConfigurationJson.bunOptions || {});
try {
this.pnpmOptions = PnpmOptionsConfiguration.loadFromJsonFileOrThrow(
`${this.commonRushConfigFolder}/${RushConstants.pnpmConfigFilename}`,
Expand Down Expand Up @@ -675,6 +694,11 @@ export class RushConfiguration {
this.packageManagerOptions = this.yarnOptions;
packageManagerFields.push('yarnVersion');
}
if (rushConfigurationJson.bunVersion) {
this.packageManager = 'bun';
this.packageManagerOptions = this.bunOptions;
packageManagerFields.push('bunVersion');
}

if (packageManagerFields.length === 0) {
throw new Error(
Expand All @@ -695,6 +719,9 @@ export class RushConfiguration {
} else if (this.packageManager === 'pnpm') {
this.packageManagerToolVersion = rushConfigurationJson.pnpmVersion!;
this.packageManagerWrapper = new PnpmPackageManager(this.packageManagerToolVersion);
} else if (this.packageManager === 'bun') {
this.packageManagerToolVersion = rushConfigurationJson.bunVersion!;
this.packageManagerWrapper = new BunPackageManager(this.packageManagerToolVersion);
} else {
this.packageManagerToolVersion = rushConfigurationJson.yarnVersion!;
this.packageManagerWrapper = new YarnPackageManager(this.packageManagerToolVersion);
Expand Down
15 changes: 15 additions & 0 deletions libraries/rush-lib/src/api/packageManager/BunPackageManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.

import { RushConstants } from '../../logic/RushConstants';
import { PackageManager } from './PackageManager';

/**
* Support for interacting with the Bun package manager.
*/
export class BunPackageManager extends PackageManager {
/** @internal */
public constructor(version: string) {
super(version, 'bun', RushConstants.bunShrinkwrapFilename);
}
}
4 changes: 2 additions & 2 deletions libraries/rush-lib/src/api/packageManager/PackageManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
* This represents the available Package Manager tools as a string
* @public
*/
export type PackageManagerName = 'pnpm' | 'npm' | 'yarn';
export type PackageManagerName = 'pnpm' | 'npm' | 'yarn' | 'bun';

/**
* An abstraction for controlling the supported package managers: PNPM, NPM, and Yarn.
* An abstraction for controlling the supported package managers: PNPM, NPM, Bun, and Yarn.
* @public
*/
export abstract class PackageManager {
Expand Down
4 changes: 4 additions & 0 deletions libraries/rush-lib/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ export {
IYarnOptionsJson as _IYarnOptionsJson,
YarnOptionsConfiguration
} from './logic/yarn/YarnOptionsConfiguration';
export {
IBunOptionsJson as _IBunOptionsJson,
BunOptionsConfiguration
} from './logic/bun/BunOptionsConfiguration';
export {
IPnpmOptionsJson as _IPnpmOptionsJson,
PnpmStoreLocation,
Expand Down
4 changes: 4 additions & 0 deletions libraries/rush-lib/src/logic/InstallManagerFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ export class InstallManagerFactory {
return new WorkspaceInstallManager(rushConfiguration, rushGlobalFolder, purgeManager, options);
}

if (rushConfiguration.packageManager === 'bun' && rushConfiguration.bunOptions?.useWorkspaces) {
return new WorkspaceInstallManager(rushConfiguration, rushGlobalFolder, purgeManager, options);
}

const rushInstallManagerModule: typeof import('./installManager/RushInstallManager') = await import(
/* webpackChunkName: 'RushInstallManager' */
'./installManager/RushInstallManager'
Expand Down
3 changes: 3 additions & 0 deletions libraries/rush-lib/src/logic/LinkManagerFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ export class LinkManagerFactory {
case 'yarn':
// Yarn uses the same node_modules structure as NPM
return new NpmLinkManager(rushConfiguration);
case 'bun':
// Bun uses the same node_modules structure as NPM
return new NpmLinkManager(rushConfiguration);
default:
throw new Error(`Unsupported package manager: ${rushConfiguration.packageManager}`);
}
Expand Down
4 changes: 4 additions & 0 deletions libraries/rush-lib/src/logic/PackageJsonUpdater.ts
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,10 @@ export class PackageJsonUpdater {
let commandArgs: string[];
if (this._rushConfiguration.packageManager === 'yarn') {
commandArgs = ['info', packageName, 'dist-tags.latest', '--silent'];
}
if (this._rushConfiguration.packageManager === 'bun') {
// npm needs to be installed
commandArgs = ['run', 'npm', 'view', `${packageName}@latest`, 'version'];
} else {
commandArgs = ['view', `${packageName}@latest`, 'version'];
}
Expand Down
5 changes: 5 additions & 0 deletions libraries/rush-lib/src/logic/RushConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ export class RushConstants {
*/
public static readonly npmShrinkwrapFilename: string = 'npm-shrinkwrap.json';

/**
* The filename ("bun.lockb") used to store an installation plan for the NPM package manger.
*/
public static readonly bunShrinkwrapFilename: string = 'bun.lockb';

/**
* Number of installation attempts
*/
Expand Down
7 changes: 5 additions & 2 deletions libraries/rush-lib/src/logic/ShrinkwrapFileFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { BaseShrinkwrapFile } from './base/BaseShrinkwrapFile';
import { NpmShrinkwrapFile } from './npm/NpmShrinkwrapFile';
import { PnpmShrinkwrapFile } from './pnpm/PnpmShrinkwrapFile';
import { YarnShrinkwrapFile } from './yarn/YarnShrinkwrapFile';
import { BunShrinkwrapFile } from './bun/BunShrinkwrapFile';

export class ShrinkwrapFileFactory {
public static getShrinkwrapFile(
Expand All @@ -21,6 +22,8 @@ export class ShrinkwrapFileFactory {
return PnpmShrinkwrapFile.loadFromFile(shrinkwrapFilename);
case 'yarn':
return YarnShrinkwrapFile.loadFromFile(shrinkwrapFilename);
case 'bun':
return BunShrinkwrapFile.loadFromFile(shrinkwrapFilename);
default:
throw new Error(`Invalid package manager: ${packageManager}`);
}
Expand All @@ -36,8 +39,8 @@ export class ShrinkwrapFileFactory {
return NpmShrinkwrapFile.loadFromString(shrinkwrapContent);
case 'pnpm':
return PnpmShrinkwrapFile.loadFromString(shrinkwrapContent);
case 'yarn':
return YarnShrinkwrapFile.loadFromString(shrinkwrapContent);
case 'bun':
return BunShrinkwrapFile.loadFromString(shrinkwrapContent);
default:
throw new Error(`Invalid package manager: ${packageManager}`);
}
Expand Down
4 changes: 3 additions & 1 deletion libraries/rush-lib/src/logic/base/BaseInstallManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,9 @@ ${gitLfsHookHandling}
* to the command-line.
*/
protected pushConfigurationArgs(args: string[], options: IInstallManagerOptions): void {
if (this.rushConfiguration.packageManager === 'npm') {
if (this.rushConfiguration.packageManager === 'bun') {
args.push('--cache-dir', this.rushConfiguration.bunCacheFolder);
} else if (this.rushConfiguration.packageManager === 'npm') {
if (semver.lt(this.rushConfiguration.packageManagerToolVersion, '5.0.0')) {
// NOTE:
//
Expand Down
2 changes: 2 additions & 0 deletions libraries/rush-lib/src/logic/base/BasePackage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ export interface IRushTempPackageJson extends IPackageJson {
* references to locally built projects.
*/
rushDependencies?: { [key: string]: string };

workspaces?: string[];
}

/**
Expand Down
43 changes: 43 additions & 0 deletions libraries/rush-lib/src/logic/bun/BunOptionsConfiguration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.

import {
IPackageManagerOptionsJsonBase,
PackageManagerOptionsConfigurationBase
} from '../base/BasePackageManagerOptionsConfiguration';

/**
* Part of IRushConfigurationJson.
* @internal
*/
export interface IBunOptionsJson extends IPackageManagerOptionsJsonBase {
/**
* {@inheritDoc BunOptionsConfiguration.useWorkspaces}
*/
useWorkspaces?: boolean;
}

/**
* Options that are only used when the bun package manager is selected.
*
* @remarks
* It is valid to define these options in rush.json even if the bun package manager
* is not being used.
*
* @public
*/
export class BunOptionsConfiguration extends PackageManagerOptionsConfigurationBase {
/**
* If true, then Rush will use the workspaces feature to install and link packages when invoking PNPM.
*
* @remarks
* The default value is true. (For now.)
*/
public readonly useWorkspaces: boolean;

/** @internal */
public constructor(json: IBunOptionsJson) {
super(json);
this.useWorkspaces = !!json.useWorkspaces;
}
}
Loading