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] Support PNPM workspaces #1938

Merged
merged 39 commits into from
Jul 3, 2020
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
d44931f
Move to installManager
D4N14L Jun 15, 2020
65c1c44
Add initial implementation of workspaces
D4N14L Jun 17, 2020
824c01d
Merge branch 'master' of https://github.com/D4N14L/web-build-tools in…
D4N14L Jun 17, 2020
e6d78e7
Rush update
D4N14L Jun 17, 2020
cadb3f6
Rush change
D4N14L Jun 17, 2020
7acf1ed
Lint
D4N14L Jun 17, 2020
f35d08b
Add new test files
D4N14L Jun 19, 2020
5b49dd8
Add 'rush add' support for workspace projects
D4N14L Jun 19, 2020
078d7b0
Add workspaces versioning support and tests
D4N14L Jun 19, 2020
f73c79d
Make pnpmfile shim workspace-only
D4N14L Jun 24, 2020
85885a7
Allow exact ranges to be used for workspace range conversion
D4N14L Jun 24, 2020
debf80f
Add repo-state.json to be used by workspaces to validate common versions
D4N14L Jun 24, 2020
2301d3b
Merge branch 'master' of https://github.com/D4N14L/web-build-tools in…
D4N14L Jun 24, 2020
9b738c8
Rush update
D4N14L Jun 24, 2020
e841136
Small modification to avoid work when using DeployManager
D4N14L Jun 24, 2020
48bcca5
Fix changes when workspace dependencies should be tracked
D4N14L Jun 25, 2020
b0984b7
Merge branch 'master' of https://github.com/microsoft/rushstack into …
D4N14L Jun 27, 2020
6ce1e86
Rush update
D4N14L Jun 27, 2020
d8a7b2c
PR feedback
D4N14L Jun 27, 2020
f7f7605
Updated snapshot
D4N14L Jun 29, 2020
8b43f8e
Fix local project references for RushInstallManager
D4N14L Jun 29, 2020
495699a
Add support for reverting workspace notation when going back to legac…
D4N14L Jun 29, 2020
3ea3fbd
Fix per-project shrinkwrap when encountering duplicate dev dependencies
D4N14L Jun 29, 2020
3fad71e
Use repo-state.json for shrinkwrap hash validation
D4N14L Jun 30, 2020
a886fb1
PR feedback
D4N14L Jun 30, 2020
e94bfa1
Fix RepoStateFile serialization error
D4N14L Jun 30, 2020
c83abf7
Add "workspaces" property to the last-install.flag file
D4N14L Jul 1, 2020
5e92471
Merge branch 'master' of https://github.com/microsoft/rushstack into …
D4N14L Jul 1, 2020
952b0bc
Add SpecifierType enum
D4N14L Jul 3, 2020
46a7d3d
PR feedback
D4N14L Jul 3, 2020
58eb273
Remove 'generated' comment from checked in file
D4N14L Jul 3, 2020
cb7aad3
Merge branch 'master' of https://github.com/microsoft/rushstack into …
D4N14L Jul 3, 2020
c225f18
Bump semver
D4N14L Jul 3, 2020
e6da401
rush change
D4N14L Jul 3, 2020
3d9ec44
Merge branch 'master' of https://github.com/microsoft/rushstack into …
D4N14L Jul 3, 2020
2aaf287
PR feedback
D4N14L Jul 3, 2020
5e3c3ea
Move dynamic data to pnpmfileSettings.json
D4N14L Jul 3, 2020
1771839
Upgrade semver types to match package version.
iclanton Jul 3, 2020
0e8d05a
Improve typesafety in PnpmfileShim.
iclanton Jul 3, 2020
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
4 changes: 2 additions & 2 deletions apps/api-extractor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"colors": "~1.2.1",
"lodash": "~4.17.15",
"resolve": "~1.17.0",
"semver": "~5.3.0",
"semver": "~7.3.0",
"source-map": "~0.6.1",
"typescript": "~3.9.5"
},
Expand All @@ -49,7 +49,7 @@
"@rushstack/eslint-config": "1.0.2",
"@types/jest": "25.2.1",
"@types/lodash": "4.14.116",
"@types/semver": "5.3.33",
"@types/semver": "~7.2.0",
"@types/node": "10.17.13",
"@types/resolve": "1.17.1",
"gulp": "~4.0.2"
Expand Down
20 changes: 18 additions & 2 deletions apps/rush-lib/assets/rush-init/rush.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
* Specify one of: "pnpmVersion", "npmVersion", or "yarnVersion". See the Rush documentation
* for details about these alternatives.
*/
"pnpmVersion": "4.12.5",
"pnpmVersion": "4.14.4",

/*[LINE "HYPOTHETICAL"]*/ "npmVersion": "4.5.0",
/*[LINE "HYPOTHETICAL"]*/ "yarnVersion": "1.9.4",
Expand Down Expand Up @@ -94,7 +94,23 @@
*
* The default value is false.
*/
/*[LINE "HYPOTHETICAL"]*/ "preventManualShrinkwrapChanges": true
/*[LINE "HYPOTHETICAL"]*/ "preventManualShrinkwrapChanges": true,

/**
* If true, then `rush install` will use the PNPM workspaces feature to perform the
* install.
*
* This feature uses PNPM to peform the entire monorepo install. When using workspaces, Rush will
* generate a "pnpm-workspace.yaml" file referencing all local projects to install. Rush will
* also generate a "pnpmfile.js" which is used to provide preferred versions support. When install
* is run, this pnpmfile will be used to replace dependency version ranges with a smaller subset
* of the original range. If the preferred version is not fully a subset of the original version
* range, it will be left as-is. After this, the pnpmfile.js provided in the repository (if one
* exists) will be called to further modify package dependencies.
*
* The default value is false.
*/
/*[LINE "HYPOTHETICAL"]*/ "useWorkspaces": true
},

/**
Expand Down
4 changes: 2 additions & 2 deletions apps/rush-lib/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
"npm-packlist": "~2.1.2",
"read-package-tree": "~5.1.5",
"resolve": "~1.17.0",
"semver": "~5.3.0",
"semver": "~7.3.0",
"strict-uri-encode": "~2.0.0",
"tar": "~5.0.5",
"true-case-path": "~2.2.1",
Expand All @@ -64,7 +64,7 @@
"@types/npm-packlist": "~1.1.1",
"@types/read-package-tree": "5.1.0",
"@types/resolve": "1.17.1",
"@types/semver": "5.3.33",
"@types/semver": "~7.2.0",
"@types/strict-uri-encode": "2.0.0",
"@types/tar": "4.0.3",
"@types/wordwrap": "1.0.0",
Expand Down
21 changes: 20 additions & 1 deletion apps/rush-lib/src/api/CommonVersionsConfiguration.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.

import * as crypto from 'crypto';
import * as path from 'path';
import {
JsonFile,
JsonSchema,
MapExtensions,
ProtectableMap,
FileSystem
FileSystem,
Sort
} from '@rushstack/node-core-library';
import { PackageNameParsers } from './PackageNameParsers';
import { JsonSchemaUrls } from '../logic/JsonSchemaUrls';
Expand Down Expand Up @@ -148,6 +150,23 @@ export class CommonVersionsConfiguration {
return this._filePath;
}

/**
* Get a sha1 hash of the preferred versions.
*/
public getPreferredVersionsHash(): string {
// Sort so that the hash is stable
const orderedPreferredVersions: Map<string, string> = new Map<string, string>(
this._preferredVersions.protectedView
);
Sort.sortMapKeys(orderedPreferredVersions);

// JSON.stringify does not support maps, so we need to convert to an object first
const preferredVersionsObj: { [dependency: string]: string } = MapExtensions.toObject(
orderedPreferredVersions
);
return crypto.createHash('sha1').update(JSON.stringify(preferredVersionsObj)).digest('hex');
}

/**
* Writes the "common-versions.json" file to disk, using the filename that was passed to loadFromFile().
*/
Expand Down
8 changes: 7 additions & 1 deletion apps/rush-lib/src/api/PackageJsonEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,13 @@ export class PackageJsonEditor {
this._onChange.bind(this)
);

if (dependencyType === DependencyType.Regular || dependencyType === DependencyType.Optional) {
// Rush collapses everything that isn't a devDependency into the dependencies
// field, so we need to set the value dependening on dependency type
if (
dependencyType === DependencyType.Regular ||
dependencyType === DependencyType.Optional ||
dependencyType === DependencyType.Peer
) {
this._dependencies.set(packageName, dependency);
D4N14L marked this conversation as resolved.
Show resolved Hide resolved
} else {
this._devDependencies.set(packageName, dependency);
Expand Down
39 changes: 38 additions & 1 deletion apps/rush-lib/src/api/RushConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { YarnPackageManager } from './packageManager/YarnPackageManager';
import { PnpmPackageManager } from './packageManager/PnpmPackageManager';
import { ExperimentsConfiguration } from './ExperimentsConfiguration';
import { PackageNameParsers } from './PackageNameParsers';
import { RepoStateFile } from '../logic/RepoStateFile';

const MINIMUM_SUPPORTED_RUSH_JSON_VERSION: string = '0.0.0';
const DEFAULT_BRANCH: string = 'master';
Expand All @@ -38,6 +39,7 @@ const knownRushConfigFilenames: string[] = [
'.npmrc-publish',
RushConstants.pinnedVersionsFilename,
RushConstants.commonVersionsFilename,
RushConstants.repoStateFilename,
RushConstants.browserApprovedPackagesFilename,
RushConstants.nonbrowserApprovedPackagesFilename,
RushConstants.versionPoliciesFilename,
Expand Down Expand Up @@ -168,6 +170,10 @@ export interface IPnpmOptionsJson extends IPackageManagerOptionsJsonBase {
* {@inheritDoc PnpmOptionsConfiguration.preventManualShrinkwrapChanges}
*/
preventManualShrinkwrapChanges?: boolean;
/**
* {@inheritDoc PnpmOptionsConfiguration.useWorkspaces}
*/
useWorkspaces?: boolean;
D4N14L marked this conversation as resolved.
Show resolved Hide resolved
}

/**
Expand Down Expand Up @@ -334,7 +340,7 @@ export class PnpmOptionsConfiguration extends PackageManagerOptionsConfiguration
* @remarks
* This feature protects against accidental inconsistencies that may be introduced
* if the PNPM shrinkwrap file (`pnpm-lock.yaml`) is manually edited. When this
* feature is enabled, `rush update` will append a hash to the file as a YAML comment,
* feature is enabled, `rush update` will write a hash of the shrinkwrap contents to repo-state.json,
* and then `rush update` and `rush install` will validate the hash. Note that this does not prohibit
* manual modifications, but merely requires `rush update` be run
* afterwards, ensuring that PNPM can report or repair any potential inconsistencies.
Expand All @@ -346,6 +352,14 @@ export class PnpmOptionsConfiguration extends PackageManagerOptionsConfiguration
*/
public readonly preventManualShrinkwrapChanges: boolean;

/**
* If true, then Rush will use the workspaces feature to install and link packages when invoking PNPM.
D4N14L marked this conversation as resolved.
Show resolved Hide resolved
*
* @remarks
* The default value is false. (For now.)
*/
public readonly useWorkspaces: boolean;

/** @internal */
public constructor(json: IPnpmOptionsJson, commonTempFolder: string) {
super(json);
Expand All @@ -360,6 +374,7 @@ export class PnpmOptionsConfiguration extends PackageManagerOptionsConfiguration
this.strictPeerDependencies = !!json.strictPeerDependencies;
this.resolutionStrategy = json.resolutionStrategy || 'fewer-dependencies';
this.preventManualShrinkwrapChanges = !!json.preventManualShrinkwrapChanges;
this.useWorkspaces = !!json.useWorkspaces;
}
}

Expand Down Expand Up @@ -1425,6 +1440,28 @@ export class RushConfiguration {
return CommonVersionsConfiguration.loadFromFile(commonVersionsFilename);
}

/**
* Gets the path to the repo-state.json file for a specific variant.
* @param variant - The name of the current variant in use by the active command.
*/
public getRepoStateFilePath(variant?: string | undefined): string {
const repoStateFilename: string = path.join(
this.commonRushConfigFolder,
...(variant ? [RushConstants.rushVariantsFolderName, variant] : []),
RushConstants.repoStateFilename
);
return repoStateFilename;
}

/**
* Gets the contents from the repo-state.json file for a specific variant.
* @param variant - The name of the current variant in use by the active command.
*/
public getRepoState(variant?: string | undefined): RepoStateFile {
const repoStateFilename: string = this.getRepoStateFilePath(variant);
return RepoStateFile.loadFromFile(repoStateFilename, variant);
}

/**
* Gets the committed shrinkwrap file name for a specific variant.
* @param variant - The name of the current variant in use by the active command.
Expand Down
14 changes: 9 additions & 5 deletions apps/rush-lib/src/cli/actions/AddAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { RushConfigurationProject } from '../../api/RushConfigurationProject';
import { BaseRushAction } from './BaseRushAction';
import { RushCommandLineParser } from '../RushCommandLineParser';
import { PackageJsonUpdater, SemVerStyle } from '../../logic/PackageJsonUpdater';
import { DependencySpecifier } from '../../logic/DependencySpecifier';

export class AddAction extends BaseRushAction {
private _allFlag: CommandLineFlagParameter;
Expand All @@ -25,9 +26,9 @@ export class AddAction extends BaseRushAction {
'Adds a specified package as a dependency of the current project (as determined by the current working directory)' +
' and then runs "rush update". If no version is specified, a version will be automatically detected (typically' +
' either the latest version or a version that won\'t break the "ensureConsistentVersions" policy). If a version' +
' range is specified, the latest version in the range will be used. The version will be automatically prepended' +
' with a tilde, unless the "--exact" or "--caret" flags are used. The "--make-consistent" flag can be used to' +
' update all packages with the dependency.'
' range (or a workspace range) is specified, the latest version in the range will be used. The version will be' +
' automatically prepended with a tilde, unless the "--exact" or "--caret" flags are used. The "--make-consistent"' +
' flag can be used to update all packages with the dependency.'
];
super({
actionName: 'add',
Expand Down Expand Up @@ -128,8 +129,11 @@ export class AddAction extends BaseRushAction {
throw new Error(`The package name "${packageName}" is not valid.`);
}

if (version && version !== 'latest' && !semver.validRange(version) && !semver.valid(version)) {
throw new Error(`The SemVer specifier "${version}" is not valid.`);
if (version && version !== 'latest') {
const specifier: DependencySpecifier = new DependencySpecifier(packageName, version);
D4N14L marked this conversation as resolved.
Show resolved Hide resolved
if (!semver.validRange(specifier.versionSpecifier) && !semver.valid(specifier.versionSpecifier)) {
throw new Error(`The SemVer specifier "${version}" is not valid.`);
}
}

const updater: PackageJsonUpdater = new PackageJsonUpdater(this.rushConfiguration, this.rushGlobalFolder);
Expand Down
5 changes: 3 additions & 2 deletions apps/rush-lib/src/cli/actions/BaseInstallAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import {

import { BaseRushAction } from './BaseRushAction';
import { Event } from '../../api/EventHooks';
import { InstallManager, IInstallManagerOptions } from '../../logic/InstallManager';
import { BaseInstallManager, IInstallManagerOptions } from '../../logic/base/BaseInstallManager';
import { InstallManagerFactory } from '../../logic/InstallManagerFactory';
import { PurgeManager } from '../../logic/PurgeManager';
import { SetupChecks } from '../../logic/SetupChecks';
import { StandardScriptUpdater } from '../../logic/StandardScriptUpdater';
Expand Down Expand Up @@ -117,7 +118,7 @@ export abstract class BaseInstallAction extends BaseRushAction {

const installManagerOptions: IInstallManagerOptions = this.buildInstallOptions();

const installManager: InstallManager = new InstallManager(
const installManager: BaseInstallManager = InstallManagerFactory.getInstallManager(
this.rushConfiguration,
this.rushGlobalFolder,
purgeManager,
Expand Down
2 changes: 1 addition & 1 deletion apps/rush-lib/src/cli/actions/InstallAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// See LICENSE in the project root for license information.

import { BaseInstallAction } from './BaseInstallAction';
import { IInstallManagerOptions } from '../../logic/InstallManager';
import { IInstallManagerOptions } from '../../logic/base/BaseInstallManager';
import { RushCommandLineParser } from '../RushCommandLineParser';

export class InstallAction extends BaseInstallAction {
Expand Down
2 changes: 1 addition & 1 deletion apps/rush-lib/src/cli/actions/UpdateAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { CommandLineFlagParameter } from '@rushstack/ts-command-line';

import { BaseInstallAction } from './BaseInstallAction';
import { IInstallManagerOptions } from '../../logic/InstallManager';
import { IInstallManagerOptions } from '../../logic/base/BaseInstallManager';
import { RushCommandLineParser } from '../RushCommandLineParser';

export class UpdateAction extends BaseInstallAction {
Expand Down
10 changes: 8 additions & 2 deletions apps/rush-lib/src/cli/actions/VersionAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,16 @@ export class VersionAction extends BaseRushAction {
const newPolicyVersion: semver.SemVer = new semver.SemVer(policy.version);
if (newPolicyVersion.prerelease.length) {
// Update 1.5.0-alpha.10 to 1.5.0-beta.10
newPolicyVersion.prerelease[0] = this._prereleaseIdentifier.value;
// For example, if we are parsing "1.5.0-alpha.10" then the newPolicyVersion.prerelease array
// would contain [ "alpha", 10 ], so we would replace "alpha" with "beta"
newPolicyVersion.prerelease = [
this._prereleaseIdentifier.value,
...newPolicyVersion.prerelease.slice(1)
];
} else {
// Update 1.5.0 to 1.5.0-beta
newPolicyVersion.prerelease.push(this._prereleaseIdentifier.value);
// Since there is no length, we can just set to a new array
newPolicyVersion.prerelease = [this._prereleaseIdentifier.value];
}
newVersion = newPolicyVersion.format();
}
Expand Down
16 changes: 7 additions & 9 deletions apps/rush-lib/src/cli/scriptActions/GlobalScriptAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { BaseScriptAction, IBaseScriptActionOptions } from './BaseScriptAction';
import { Utilities } from '../../utilities/Utilities';
import { AlreadyReportedError } from '../../utilities/AlreadyReportedError';
import { FileSystem, LockFile, IPackageJson, JsonFile, PackageName } from '@rushstack/node-core-library';
import { InstallHelpers } from '../../logic/InstallHelpers';
import { InstallHelpers } from '../../logic/installManager/InstallHelpers';
import { RushConstants } from '../../logic/RushConstants';
import { LastInstallFlag } from '../../api/LastInstallFlag';

Expand Down Expand Up @@ -138,14 +138,12 @@ export class GlobalScriptAction extends BaseScriptAction {

console.log(`Installing dependencies under ${this._autoinstallerNameFullPath}...\n`);

Utilities.executeCommand(
this.rushConfiguration.packageManagerToolFilename,
['install', '--frozen-lockfile'],
this._autoinstallerNameFullPath,
undefined,
/* suppressOutput */ false,
/* keepEnvironment */ true
);
Utilities.executeCommand({
command: this.rushConfiguration.packageManagerToolFilename,
args: ['install', '--frozen-lockfile'],
workingDirectory: this._autoinstallerNameFullPath,
keepEnvironment: true
});

// Create file: ../common/autoinstallers/my-task/.rush/temp/last-install.flag
lastInstallFlag.create();
Expand Down
7 changes: 6 additions & 1 deletion apps/rush-lib/src/cli/test/Cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@ describe('CLI', () => {
const startPath: string = path.resolve(path.join(__dirname, '../../start.js'));

expect(() => {
Utilities.executeCommand('node', [startPath], workingDir, undefined, true);
Utilities.executeCommand({
command: 'node',
args: [startPath],
workingDirectory: workingDir,
suppressOutput: true
});
}).not.toThrow();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,11 @@ Adds a specified package as a dependency of the current project (as
determined by the current working directory) and then runs \\"rush update\\". If
no version is specified, a version will be automatically detected (typically
either the latest version or a version that won't break the
\\"ensureConsistentVersions\\" policy). If a version range is specified, the
latest version in the range will be used. The version will be automatically
prepended with a tilde, unless the \\"--exact\\" or \\"--caret\\" flags are used. The
\\"--make-consistent\\" flag can be used to update all packages with the
dependency.
\\"ensureConsistentVersions\\" policy). If a version range (or a workspace range)
is specified, the latest version in the range will be used. The version will
be automatically prepended with a tilde, unless the \\"--exact\\" or \\"--caret\\"
flags are used. The \\"--make-consistent\\" flag can be used to update all
packages with the dependency.

Optional arguments:
-h, --help Show this help message and exit.
Expand Down
2 changes: 2 additions & 0 deletions apps/rush-lib/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ export { CommonVersionsConfiguration } from './api/CommonVersionsConfiguration';

export { PackageJsonEditor, PackageJsonDependency, DependencyType } from './api/PackageJsonEditor';

export { RepoStateFile } from './logic/RepoStateFile';

export { EventHooks, Event } from './api/EventHooks';

export { ChangeManager } from './api/ChangeManager';
Expand Down
Loading