Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[rush] Add support for PNPM version 3.x #1210

Merged
merged 17 commits into from
Apr 23, 2019
Merged
Show file tree
Hide file tree
Changes from 4 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/rush-lib/assets/rush-init/[dot]gitattributes
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Don't allow people to merge changes to these generated files, because the result
# may be invalid. You need to run "rush update" again.
shrinkwrap.yaml merge=binary
pnpm-lock.yaml merge=binary
npm-shrinkwrap.json merge=binary
yarn.lock merge=binary

Expand Down
103 changes: 59 additions & 44 deletions apps/rush-lib/src/api/RushConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export interface IRushRepositoryJson {
*/
export interface IPnpmOptionsJson {
strictPeerDependencies?: boolean;
resolutionStrategy?: ResolutionStrategy;
}

/**
Expand Down Expand Up @@ -161,9 +162,18 @@ export class PnpmOptionsConfiguration {
*/
public readonly strictPeerDependencies: boolean;

/**
* The resolution strategy that will be used by PNPM.
*
* The default value is "fewer-dependencies" i.e. PNPM will prefer package versions
* that have already been resolved previously.
*/
public readonly resolutionStrategy: ResolutionStrategy;

/** @internal */
public constructor(json: IPnpmOptionsJson) {
this.strictPeerDependencies = !!json.strictPeerDependencies;
this.resolutionStrategy = json.resolutionStrategy || 'fewer-dependencies';
}
}

Expand Down Expand Up @@ -214,6 +224,12 @@ export interface ITryFindRushJsonLocationOptions {
*/
export type PackageManager = 'pnpm' | 'npm' | 'yarn';

/**
* This represents the available PNPM resolution strategies as a string
* @public
*/
export type ResolutionStrategy = 'fewer-dependencies' | 'fast';

/**
* This represents the Rush configuration for a repository, based on the "rush.json"
* configuration file.
Expand All @@ -234,6 +250,7 @@ export class RushConfiguration {
private _npmTmpFolder: string;
private _pnpmStoreFolder: string;
private _yarnCacheFolder: string;
private _shrinkwrapFilename: string;
private _tempShrinkwrapFilename: string;
private _tempShrinkwrapPreinstallFilename: string;
private _rushLinkJsonFilename: string;
Expand Down Expand Up @@ -405,7 +422,11 @@ export class RushConfiguration {
* _validateCommonRushConfigFolder() function makes sure that this folder only contains
* recognized config files.
*/
private static _validateCommonRushConfigFolder(commonRushConfigFolder: string, packageManager: PackageManager): void {
private static _validateCommonRushConfigFolder(
commonRushConfigFolder: string,
packageManager: PackageManager,
shrinkwrapFilename: string
): void {
if (!FileSystem.exists(commonRushConfigFolder)) {
console.log(`Creating folder: ${commonRushConfigFolder}`);
FileSystem.ensureFolder(commonRushConfigFolder);
Expand All @@ -427,17 +448,13 @@ export class RushConfiguration {
}

const knownSet: Set<string> = new Set<string>(knownRushConfigFilenames.map(x => x.toUpperCase()));
switch (packageManager) {
case 'npm':
knownSet.add(RushConstants.npmShrinkwrapFilename.toUpperCase());
break;
case 'pnpm':
knownSet.add(RushConstants.pnpmShrinkwrapFilename.toUpperCase());
knownSet.add(RushConstants.pnpmfileFilename.toUpperCase());
break;
case 'yarn':
knownSet.add(RushConstants.yarnShrinkwrapFilename.toUpperCase());
break;

// Add the shrinkwrap filename for the package manager to the known set.
knownSet.add(shrinkwrapFilename.toUpperCase());

// If the package manager is pnpm, then also add the pnpm file to the known set.
if (packageManager === 'pnpm') {
knownSet.add(RushConstants.pnpmfileFilename.toUpperCase());
octogonz marked this conversation as resolved.
Show resolved Hide resolved
}

// Is the filename something we know? If not, report an error.
Expand Down Expand Up @@ -569,7 +586,7 @@ export class RushConfiguration {
* command uses a temporary copy, whose path is tempShrinkwrapFilename.)
* @remarks
* This property merely reports the filename; the file itself may not actually exist.
* Example: `C:\MyRepo\common\npm-shrinkwrap.json` or `C:\MyRepo\common\shrinkwrap.yaml`
* Example: `C:\MyRepo\common\npm-shrinkwrap.json` or `C:\MyRepo\common\pnpm-lock.yaml`
*
* @deprecated Use `getCommittedShrinkwrapFilename` instead, which gets the correct common
* shrinkwrap file name for a given active variant.
Expand All @@ -578,12 +595,22 @@ export class RushConfiguration {
return this.getCommittedShrinkwrapFilename();
}

/**
* The filename of the shrinkwrap file that is used by the package manager.
* @remarks
* This property merely reports the filename; the file itself may not actually exist.
* Example: `npm-shrinkwrap.json` or `pnpm-lock.yaml`
*/
public get shrinkwrapFilename(): string {
return this._shrinkwrapFilename;
}

/**
* The full path of the temporary shrinkwrap file that is used during "rush install".
* This file may get rewritten by the package manager during installation.
* @remarks
* This property merely reports the filename; the file itself may not actually exist.
* Example: `C:\MyRepo\common\temp\npm-shrinkwrap.json` or `C:\MyRepo\common\temp\shrinkwrap.yaml`
* Example: `C:\MyRepo\common\temp\npm-shrinkwrap.json` or `C:\MyRepo\common\temp\pnpm-lock.yaml`
*/
public get tempShrinkwrapFilename(): string {
return this._tempShrinkwrapFilename;
Expand All @@ -596,7 +623,7 @@ export class RushConfiguration {
* @remarks
* This property merely reports the filename; the file itself may not actually exist.
* Example: `C:\MyRepo\common\temp\npm-shrinkwrap-preinstall.json`
* or `C:\MyRepo\common\temp\shrinkwrap-preinstall.yaml`
* or `C:\MyRepo\common\temp\pnpm-lock-preinstall.yaml`
*/
public get tempShrinkwrapPreinstallFilename(): string {
return this._tempShrinkwrapPreinstallFilename;
Expand Down Expand Up @@ -831,21 +858,7 @@ export class RushConfiguration {

const variantConfigFolderPath: string = this._getVariantConfigFolderPath(variant);

if (this.packageManager === 'pnpm') {
return path.join(
variantConfigFolderPath,
RushConstants.pnpmShrinkwrapFilename);
} else if (this.packageManager === 'npm') {
return path.join(
variantConfigFolderPath,
RushConstants.npmShrinkwrapFilename);
} else if (this.packageManager === 'yarn') {
return path.join(
variantConfigFolderPath,
RushConstants.yarnShrinkwrapFilename);
} else {
throw new Error('Invalid package manager.');
}
return path.join(variantConfigFolderPath, this._shrinkwrapFilename);
}

/**
Expand Down Expand Up @@ -1003,31 +1016,33 @@ export class RushConfiguration {
}

if (this._packageManager === 'npm') {
this._tempShrinkwrapFilename = path.join(this._commonTempFolder, RushConstants.npmShrinkwrapFilename);

this._packageManagerToolVersion = rushConfigurationJson.npmVersion!;
this._packageManagerToolFilename = path.resolve(path.join(this._commonTempFolder,
'npm-local', 'node_modules', '.bin', 'npm'));
this._shrinkwrapFilename = RushConstants.npmShrinkwrapFilename;
} else if (this._packageManager === 'pnpm') {
this._tempShrinkwrapFilename = path.join(this._commonTempFolder, RushConstants.pnpmShrinkwrapFilename);

this._packageManagerToolVersion = rushConfigurationJson.pnpmVersion!;
this._packageManagerToolFilename = path.resolve(path.join(this._commonTempFolder,
'pnpm-local', 'node_modules', '.bin', 'pnpm'));
this._shrinkwrapFilename = RushConstants.pnpmShrinkwrapFilename(this._packageManagerToolVersion);
} else {
this._tempShrinkwrapFilename = path.join(this._commonTempFolder, RushConstants.yarnShrinkwrapFilename);

this._packageManagerToolVersion = rushConfigurationJson.yarnVersion!;
this._packageManagerToolFilename = path.resolve(path.join(this._commonTempFolder,
'yarn-local', 'node_modules', '.bin', 'yarn'));
this._shrinkwrapFilename = RushConstants.yarnShrinkwrapFilename;
}

/// From "C:\repo\common\temp\shrinkwrap.yaml" --> "C:\repo\common\temp\shrinkwrap-preinstall.yaml"
this._tempShrinkwrapFilename = path.join(
this._commonTempFolder, this._shrinkwrapFilename
);
this._packageManagerToolFilename = path.resolve(path.join(
this._commonTempFolder, `${this.packageManager}-local`, 'node_modules', '.bin', `${this.packageManager}`
));

/// From "C:\repo\common\temp\pnpm-lock.yaml" --> "C:\repo\common\temp\pnpm-lock-preinstall.yaml"
const parsedPath: path.ParsedPath = path.parse(this._tempShrinkwrapFilename);
this._tempShrinkwrapPreinstallFilename = path.join(parsedPath.dir,
parsedPath.name + '-preinstall' + parsedPath.ext);

RushConfiguration._validateCommonRushConfigFolder(this._commonRushConfigFolder, this.packageManager);
RushConfiguration._validateCommonRushConfigFolder(
this._commonRushConfigFolder,
this.packageManager,
this._shrinkwrapFilename
);

this._projectFolderMinDepth = rushConfigurationJson.projectFolderMinDepth !== undefined
? rushConfigurationJson.projectFolderMinDepth : 1;
Expand Down
24 changes: 23 additions & 1 deletion apps/rush-lib/src/api/test/RushConfiguration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ describe('RushConfiguration', () => {

expect(rushConfiguration.packageManager).toEqual('pnpm');
assertPathProperty('committedShrinkwrapFilename',
rushConfiguration.committedShrinkwrapFilename, './repo/common/config/rush/shrinkwrap.yaml');
rushConfiguration.committedShrinkwrapFilename, './repo/common/config/rush/pnpm-lock.yaml');
assertPathProperty('commonFolder',
rushConfiguration.commonFolder, './repo/common');
assertPathProperty('commonRushConfigFolder',
Expand Down Expand Up @@ -168,6 +168,28 @@ describe('RushConfiguration', () => {
done();
});

it('can load repo/rush-pnpm-2.json', (done: jest.DoneCallback) => {
const rushFilename: string = path.resolve(__dirname, 'repo', 'rush-pnpm-2.json');
const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(rushFilename);

expect(rushConfiguration.packageManager).toEqual('pnpm');
expect(rushConfiguration.packageManagerToolVersion).toEqual('2.0.0');
expect(rushConfiguration.shrinkwrapFilename).toEqual('shrinkwrap.yaml');

done();
});

it('can load repo/rush-pnpm-3.json', (done: jest.DoneCallback) => {
const rushFilename: string = path.resolve(__dirname, 'repo', 'rush-pnpm-3.json');
const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(rushFilename);

expect(rushConfiguration.packageManager).toEqual('pnpm');
expect(rushConfiguration.packageManagerToolVersion).toEqual('3.0.0');
expect(rushConfiguration.shrinkwrapFilename).toEqual('pnpm-lock.yaml');

done();
});

it('allows the temp directory to be set via environment variable', () => {
const expectedValue: string = path.resolve('/var/temp');
process.env['RUSH_TEMP_FOLDER'] = expectedValue; // tslint:disable-line:no-string-literal
Expand Down
49 changes: 49 additions & 0 deletions apps/rush-lib/src/api/test/repo/rush-pnpm-2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"pnpmVersion": "2.0.0",
"rushVersion": "2.5.0",
"projectFolderMinDepth": 1,
"projectFolderMaxDepth": 99,

"approvedPackagesPolicy": {
"reviewCategories": [ "first-party", "third-party", "prototype" ],
"ignoredNpmScopes": [ "@types", "@internal" ]
},

"repository": {
"url": "someFakeUrl"
},

"gitPolicy": {
"allowedEmailRegExps": [
"[^@]+@contoso\\.com"
],
"sampleEmail": "[email protected]"
},

"eventHooks": {
"postRushBuild": [
"do something"
]
},

"projects": [

{
"packageName": "project1",
"projectFolder": "project1",
"reviewCategory": "third-party"
},

{
"packageName": "project2",
"projectFolder": "project2",
"reviewCategory": "third-party"
},

{
"packageName": "project3",
"projectFolder": "project3",
"reviewCategory": "prototype"
}
]
}
49 changes: 49 additions & 0 deletions apps/rush-lib/src/api/test/repo/rush-pnpm-3.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"pnpmVersion": "3.0.0",
"rushVersion": "2.5.0",
"projectFolderMinDepth": 1,
"projectFolderMaxDepth": 99,

"approvedPackagesPolicy": {
"reviewCategories": [ "first-party", "third-party", "prototype" ],
"ignoredNpmScopes": [ "@types", "@internal" ]
},

"repository": {
"url": "someFakeUrl"
},

"gitPolicy": {
"allowedEmailRegExps": [
"[^@]+@contoso\\.com"
],
"sampleEmail": "[email protected]"
},

"eventHooks": {
"postRushBuild": [
"do something"
]
},

"projects": [

{
"packageName": "project1",
"projectFolder": "project1",
"reviewCategory": "third-party"
},

{
"packageName": "project2",
"projectFolder": "project2",
"reviewCategory": "third-party"
},

{
"packageName": "project3",
"projectFolder": "project3",
"reviewCategory": "prototype"
}
]
}
1 change: 1 addition & 0 deletions apps/rush-lib/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export {
RushConfiguration,
ITryFindRushJsonLocationOptions,
PackageManager,
ResolutionStrategy,
PnpmOptionsConfiguration,
YarnOptionsConfiguration
} from './api/RushConfiguration';
Expand Down
6 changes: 4 additions & 2 deletions apps/rush-lib/src/logic/InstallManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -949,7 +949,7 @@ export class InstallManager {
}

if (options.allowShrinkwrapUpdates && !shrinkwrapIsUpToDate) {
// Copy (or delete) common\temp\shrinkwrap.yaml --> common\config\rush\shrinkwrap.yaml
// Copy (or delete) common\temp\pnpm-lock.yaml --> common\config\rush\pnpm-lock.yaml
this._syncFile(this._rushConfiguration.tempShrinkwrapFilename,
this._rushConfiguration.getCommittedShrinkwrapFilename(options.variant));
} else {
Expand Down Expand Up @@ -1119,7 +1119,7 @@ export class InstallManager {
// last install flag, which encapsulates the entire installation
args.push('--no-lock');

// Ensure that Rush's tarball dependencies get synchronized properly with the shrinkwrap.yaml file.
// Ensure that Rush's tarball dependencies get synchronized properly with the pnpm-lock.yaml file.
// See this GitHub issue: https://github.com/pnpm/pnpm/issues/1342
args.push('--no-prefer-frozen-shrinkwrap');

Expand All @@ -1134,6 +1134,8 @@ export class InstallManager {
if (this._rushConfiguration.pnpmOptions.strictPeerDependencies) {
args.push('--strict-peer-dependencies');
}

args.push('--resolution-strategy', this._rushConfiguration.pnpmOptions.resolutionStrategy);
} else if (this._rushConfiguration.packageManager === 'yarn') {
args.push('--link-folder', 'yarn-link');
args.push('--cache-folder', this._rushConfiguration.yarnCacheFolder);
Expand Down
Loading