diff --git a/apps/rush/CHANGELOG.json b/apps/rush/CHANGELOG.json index ec4af1c2ffe..1870a671886 100644 --- a/apps/rush/CHANGELOG.json +++ b/apps/rush/CHANGELOG.json @@ -1,6 +1,30 @@ { "name": "@microsoft/rush", "entries": [ + { + "version": "5.93.1", + "tag": "@microsoft/rush_v5.93.1", + "date": "Fri, 17 Feb 2023 14:46:59 GMT", + "comments": { + "none": [ + { + "comment": "Fix a regression where \"rush-sdk\" failed to load older versions of \"rush-lib\" (GitHub #3979)" + } + ] + } + }, + { + "version": "5.93.0", + "tag": "@microsoft/rush_v5.93.0", + "date": "Fri, 17 Feb 2023 02:14:43 GMT", + "comments": { + "none": [ + { + "comment": "Add code path to @rushstack/rush-sdk for inheriting @microsoft/rush-lib location from a parent process via the RUSH_LIB_PATH environment variable." + } + ] + } + }, { "version": "5.92.0", "tag": "@microsoft/rush_v5.92.0", diff --git a/apps/rush/CHANGELOG.md b/apps/rush/CHANGELOG.md index 49c3a5b9179..39ea008752a 100644 --- a/apps/rush/CHANGELOG.md +++ b/apps/rush/CHANGELOG.md @@ -1,6 +1,20 @@ # Change Log - @microsoft/rush -This log was last generated on Sun, 12 Feb 2023 02:50:42 GMT and should not be manually modified. +This log was last generated on Fri, 17 Feb 2023 14:46:59 GMT and should not be manually modified. + +## 5.93.1 +Fri, 17 Feb 2023 14:46:59 GMT + +### Updates + +- Fix a regression where "rush-sdk" failed to load older versions of "rush-lib" (GitHub #3979) + +## 5.93.0 +Fri, 17 Feb 2023 02:14:43 GMT + +### Updates + +- Add code path to @rushstack/rush-sdk for inheriting @microsoft/rush-lib location from a parent process via the RUSH_LIB_PATH environment variable. ## 5.92.0 Sun, 12 Feb 2023 02:50:42 GMT diff --git a/apps/rush/package.json b/apps/rush/package.json index 51d9bae0c82..0a155075a3f 100644 --- a/apps/rush/package.json +++ b/apps/rush/package.json @@ -1,6 +1,6 @@ { "name": "@microsoft/rush", - "version": "5.92.0", + "version": "5.93.1", "description": "A professional solution for consolidating all your JavaScript projects in one Git repo", "keywords": [ "install", diff --git a/build-tests/install-test-workspace/workspace/common/pnpm-lock.yaml b/build-tests/install-test-workspace/workspace/common/pnpm-lock.yaml index 3e43f0ef299..848844916e9 100644 --- a/build-tests/install-test-workspace/workspace/common/pnpm-lock.yaml +++ b/build-tests/install-test-workspace/workspace/common/pnpm-lock.yaml @@ -4,13 +4,13 @@ importers: rush-lib-test: specifiers: - '@microsoft/rush-lib': file:microsoft-rush-lib-5.92.0.tgz + '@microsoft/rush-lib': file:microsoft-rush-lib-5.93.1.tgz '@types/node': 14.18.36 colors: ^1.4.0 rimraf: ^4.1.2 typescript: ~4.8.4 dependencies: - '@microsoft/rush-lib': file:../temp/tarballs/microsoft-rush-lib-5.92.0.tgz_@types+node@14.18.36 + '@microsoft/rush-lib': file:../temp/tarballs/microsoft-rush-lib-5.93.1.tgz_@types+node@14.18.36 colors: 1.4.0 devDependencies: '@types/node': 14.18.36 @@ -19,17 +19,17 @@ importers: rush-sdk-test: specifiers: - '@microsoft/rush-lib': file:microsoft-rush-lib-5.92.0.tgz - '@rushstack/rush-sdk': file:rushstack-rush-sdk-5.92.0.tgz + '@microsoft/rush-lib': file:microsoft-rush-lib-5.93.1.tgz + '@rushstack/rush-sdk': file:rushstack-rush-sdk-5.93.1.tgz '@types/node': 14.18.36 colors: ^1.4.0 rimraf: ^4.1.2 typescript: ~4.8.4 dependencies: - '@rushstack/rush-sdk': file:../temp/tarballs/rushstack-rush-sdk-5.92.0.tgz_@types+node@14.18.36 + '@rushstack/rush-sdk': file:../temp/tarballs/rushstack-rush-sdk-5.93.1.tgz_@types+node@14.18.36 colors: 1.4.0 devDependencies: - '@microsoft/rush-lib': file:../temp/tarballs/microsoft-rush-lib-5.92.0.tgz_@types+node@14.18.36 + '@microsoft/rush-lib': file:../temp/tarballs/microsoft-rush-lib-5.93.1.tgz_@types+node@14.18.36 '@types/node': 14.18.36 rimraf: 4.1.2 typescript: 4.8.4 @@ -395,12 +395,9 @@ packages: /@types/node-fetch/2.6.2: resolution: {integrity: sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==} dependencies: - '@types/node': 12.20.24 + '@types/node': 14.18.36 form-data: 3.0.1 - /@types/node/12.20.24: - resolution: {integrity: sha512-yxDeaQIAJlMav7fH5AQqPH1u8YIuhYJXYBzxaQ4PifsU0GDO38MSdmEDeRlIxrKbC6NbEaaEHDanWb+y30U8SQ==} - /@types/node/14.18.36: resolution: {integrity: sha512-FXKWbsJ6a1hIrRxv+FoukuHnGTgEzKYGi7kilfMae96AL9UNkPFNWJEEYWzdRI9ooIkbr4AKldyuSTLql06vLQ==} @@ -3656,11 +3653,11 @@ packages: optionalDependencies: commander: 2.20.3 - file:../temp/tarballs/microsoft-rush-lib-5.92.0.tgz_@types+node@14.18.36: - resolution: {tarball: file:../temp/tarballs/microsoft-rush-lib-5.92.0.tgz} - id: file:../temp/tarballs/microsoft-rush-lib-5.92.0.tgz + file:../temp/tarballs/microsoft-rush-lib-5.93.1.tgz_@types+node@14.18.36: + resolution: {tarball: file:../temp/tarballs/microsoft-rush-lib-5.93.1.tgz} + id: file:../temp/tarballs/microsoft-rush-lib-5.93.1.tgz name: '@microsoft/rush-lib' - version: 5.92.0 + version: 5.93.1 engines: {node: '>=5.6.0'} dependencies: '@pnpm/link-bins': 5.3.25 @@ -3893,11 +3890,11 @@ packages: resolve: 1.22.1 strip-json-comments: 3.1.1 - file:../temp/tarballs/rushstack-rush-sdk-5.92.0.tgz_@types+node@14.18.36: - resolution: {tarball: file:../temp/tarballs/rushstack-rush-sdk-5.92.0.tgz} - id: file:../temp/tarballs/rushstack-rush-sdk-5.92.0.tgz + file:../temp/tarballs/rushstack-rush-sdk-5.93.1.tgz_@types+node@14.18.36: + resolution: {tarball: file:../temp/tarballs/rushstack-rush-sdk-5.93.1.tgz} + id: file:../temp/tarballs/rushstack-rush-sdk-5.93.1.tgz name: '@rushstack/rush-sdk' - version: 5.92.0 + version: 5.93.1 dependencies: '@rushstack/node-core-library': file:../temp/tarballs/rushstack-node-core-library-3.55.2.tgz_@types+node@14.18.36 '@types/node-fetch': 2.6.2 diff --git a/common/config/rush/version-policies.json b/common/config/rush/version-policies.json index a3eb10e8e5d..2aecd6e6077 100644 --- a/common/config/rush/version-policies.json +++ b/common/config/rush/version-policies.json @@ -102,8 +102,8 @@ { "policyName": "rush", "definitionName": "lockStepVersion", - "version": "5.92.0", - "nextBump": "minor", + "version": "5.93.1", + "nextBump": "patch", "mainProject": "@microsoft/rush" } ] diff --git a/common/reviews/api/rush-lib.api.md b/common/reviews/api/rush-lib.api.md index 9aa7b02ce99..206bc26cc51 100644 --- a/common/reviews/api/rush-lib.api.md +++ b/common/reviews/api/rush-lib.api.md @@ -177,6 +177,7 @@ export enum EnvironmentVariableNames { RUSH_GIT_BINARY_PATH = "RUSH_GIT_BINARY_PATH", RUSH_GLOBAL_FOLDER = "RUSH_GLOBAL_FOLDER", RUSH_INVOKED_FOLDER = "RUSH_INVOKED_FOLDER", + RUSH_LIB_PATH = "_RUSH_LIB_PATH", RUSH_PARALLELISM = "RUSH_PARALLELISM", RUSH_PNPM_STORE_PATH = "RUSH_PNPM_STORE_PATH", RUSH_PNPM_VERIFY_STORE_INTEGRITY = "RUSH_PNPM_VERIFY_STORE_INTEGRITY", diff --git a/heft-plugins/heft-storybook-plugin/CHANGELOG.json b/heft-plugins/heft-storybook-plugin/CHANGELOG.json index 147d3994f70..3490b1c3445 100644 --- a/heft-plugins/heft-storybook-plugin/CHANGELOG.json +++ b/heft-plugins/heft-storybook-plugin/CHANGELOG.json @@ -1,6 +1,18 @@ { "name": "@rushstack/heft-storybook-plugin", "entries": [ + { + "version": "0.2.3", + "tag": "@rushstack/heft-storybook-plugin_v0.2.3", + "date": "Wed, 22 Feb 2023 16:26:55 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where static build output ends up in the wrong folder." + } + ] + } + }, { "version": "0.2.2", "tag": "@rushstack/heft-storybook-plugin_v0.2.2", diff --git a/heft-plugins/heft-storybook-plugin/CHANGELOG.md b/heft-plugins/heft-storybook-plugin/CHANGELOG.md index bdd2e5f88e7..71d0a1b06a3 100644 --- a/heft-plugins/heft-storybook-plugin/CHANGELOG.md +++ b/heft-plugins/heft-storybook-plugin/CHANGELOG.md @@ -1,6 +1,13 @@ # Change Log - @rushstack/heft-storybook-plugin -This log was last generated on Fri, 10 Feb 2023 01:18:51 GMT and should not be manually modified. +This log was last generated on Wed, 22 Feb 2023 16:26:55 GMT and should not be manually modified. + +## 0.2.3 +Wed, 22 Feb 2023 16:26:55 GMT + +### Patches + +- Fix an issue where static build output ends up in the wrong folder. ## 0.2.2 Fri, 10 Feb 2023 01:18:51 GMT diff --git a/heft-plugins/heft-storybook-plugin/package.json b/heft-plugins/heft-storybook-plugin/package.json index 4b4eb9b7348..efe111ecfa4 100644 --- a/heft-plugins/heft-storybook-plugin/package.json +++ b/heft-plugins/heft-storybook-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@rushstack/heft-storybook-plugin", - "version": "0.2.2", + "version": "0.2.3", "description": "Heft plugin for supporting UI development using Storybook", "repository": { "type": "git", diff --git a/heft-plugins/heft-storybook-plugin/src/StorybookPlugin.ts b/heft-plugins/heft-storybook-plugin/src/StorybookPlugin.ts index ca9d2151be4..4c30a167c6e 100644 --- a/heft-plugins/heft-storybook-plugin/src/StorybookPlugin.ts +++ b/heft-plugins/heft-storybook-plugin/src/StorybookPlugin.ts @@ -150,7 +150,9 @@ export class StorybookPlugin implements IHeftPlugin { return; } - this._staticBuildOutputFolder = build.properties.serveMode ? undefined : options.staticBuildModulePath; + this._staticBuildOutputFolder = build.properties.serveMode + ? undefined + : options.staticBuildOutputFolder; const modulePath: string | undefined = build.properties.serveMode ? options.startupModulePath : options.staticBuildModulePath; diff --git a/libraries/package-deps-hash/CHANGELOG.json b/libraries/package-deps-hash/CHANGELOG.json index 6fd10839b49..3570e3c1f96 100644 --- a/libraries/package-deps-hash/CHANGELOG.json +++ b/libraries/package-deps-hash/CHANGELOG.json @@ -1,6 +1,18 @@ { "name": "@rushstack/package-deps-hash", "entries": [ + { + "version": "4.0.9", + "tag": "@rushstack/package-deps-hash_v4.0.9", + "date": "Fri, 24 Feb 2023 01:24:17 GMT", + "comments": { + "patch": [ + { + "comment": "Prevent network calls or maintenance tasks during local Git operations." + } + ] + } + }, { "version": "4.0.8", "tag": "@rushstack/package-deps-hash_v4.0.8", diff --git a/libraries/package-deps-hash/CHANGELOG.md b/libraries/package-deps-hash/CHANGELOG.md index aa6e66ce31c..dbae2d23b99 100644 --- a/libraries/package-deps-hash/CHANGELOG.md +++ b/libraries/package-deps-hash/CHANGELOG.md @@ -1,6 +1,13 @@ # Change Log - @rushstack/package-deps-hash -This log was last generated on Fri, 10 Feb 2023 01:18:51 GMT and should not be manually modified. +This log was last generated on Fri, 24 Feb 2023 01:24:17 GMT and should not be manually modified. + +## 4.0.9 +Fri, 24 Feb 2023 01:24:17 GMT + +### Patches + +- Prevent network calls or maintenance tasks during local Git operations. ## 4.0.8 Fri, 10 Feb 2023 01:18:51 GMT diff --git a/libraries/package-deps-hash/package.json b/libraries/package-deps-hash/package.json index 093402d7ba9..39fe69194b8 100644 --- a/libraries/package-deps-hash/package.json +++ b/libraries/package-deps-hash/package.json @@ -1,6 +1,6 @@ { "name": "@rushstack/package-deps-hash", - "version": "4.0.8", + "version": "4.0.9", "description": "", "main": "lib/index.js", "typings": "dist/package-deps-hash.d.ts", diff --git a/libraries/package-deps-hash/src/getRepoState.ts b/libraries/package-deps-hash/src/getRepoState.ts index ed3a156957f..6016a4b1dde 100644 --- a/libraries/package-deps-hash/src/getRepoState.ts +++ b/libraries/package-deps-hash/src/getRepoState.ts @@ -19,6 +19,14 @@ const MINIMUM_GIT_VERSION: IGitVersion = { patch: 0 }; +const STANDARD_GIT_OPTIONS: readonly string[] = [ + // Don't request any optional file locks + '--no-optional-locks', + // Ensure that commands don't run automatic maintenance, since performance of the command itself is paramount + '-c', + 'maintenance.auto=false' +]; + interface IGitTreeState { files: Map; // type "blob" submodules: Map; // type "commit" @@ -300,12 +308,36 @@ export async function getRepoStateAsync( ): Promise> { const statePromise: Promise = spawnGitAsync( gitPath, - ['--no-optional-locks', 'ls-tree', '-r', '-z', '--full-name', 'HEAD', '--'], + STANDARD_GIT_OPTIONS.concat([ + 'ls-tree', + // Recursively expand trees + '-r', + // Use NUL as the separator + '-z', + // Specify the full path to files relative to the root + '--full-name', + // As of last commit + 'HEAD', + '--' + ]), rootDirectory ).then(parseGitLsTree); const locallyModifiedPromise: Promise> = spawnGitAsync( gitPath, - ['--no-optional-locks', 'status', '-z', '-u', '--no-renames', '--ignore-submodules', '--'], + STANDARD_GIT_OPTIONS.concat([ + 'status', + // Use NUL as the separator + '-z', + // Include untracked files + '-u', + // Disable rename detection so that renames show up as add + delete + '--no-renames', + // Don't process submodules with this command; they'll be handled individually + '--ignore-submodules', + // Don't compare against the remote + '--no-ahead-behind', + '--' + ]), rootDirectory ).then(parseGitStatus); @@ -332,7 +364,7 @@ export async function getRepoStateAsync( const hashObjectPromise: Promise = spawnGitAsync( gitPath, - ['--no-optional-locks', 'hash-object', '--stdin-paths'], + STANDARD_GIT_OPTIONS.concat(['hash-object', '--stdin-paths']), rootDirectory, Readable.from(getFilesToHash(), { encoding: 'utf-8', @@ -391,8 +423,7 @@ export function getRepoChanges( const result: child_process.SpawnSyncReturns = Executable.spawnSync( gitPath || 'git', - [ - '--no-optional-locks', + STANDARD_GIT_OPTIONS.concat([ 'diff-index', '--color=never', '--no-renames', @@ -401,7 +432,7 @@ export function getRepoChanges( '-z', revision, '--' - ], + ]), { currentWorkingDirectory: rootDirectory } @@ -441,7 +472,10 @@ export function ensureGitMinimumVersion(gitPath?: string): void { } function getGitVersion(gitPath?: string): IGitVersion { - const result: child_process.SpawnSyncReturns = Executable.spawnSync(gitPath || 'git', ['version']); + const result: child_process.SpawnSyncReturns = Executable.spawnSync( + gitPath || 'git', + STANDARD_GIT_OPTIONS.concat(['version']) + ); if (result.status !== 0) { throw new Error( diff --git a/libraries/rush-lib/package.json b/libraries/rush-lib/package.json index db57be7ae11..9448989d1eb 100644 --- a/libraries/rush-lib/package.json +++ b/libraries/rush-lib/package.json @@ -1,6 +1,6 @@ { "name": "@microsoft/rush-lib", - "version": "5.92.0", + "version": "5.93.1", "description": "A library for writing scripts that interact with the Rush tool", "repository": { "type": "git", @@ -90,5 +90,11 @@ "@rushstack/rush-amazon-s3-build-cache-plugin": "workspace:*", "@rushstack/rush-azure-storage-build-cache-plugin": "workspace:*", "@rushstack/rush-http-build-cache-plugin": "workspace:*" - } + }, + "sideEffects": [ + "lib-esnext/start-pnpm.js", + "lib-esnext/start.js", + "lib-esnext/startx.js", + "lib-esnext/utilities/SetRushLibPath.js" + ] } diff --git a/libraries/rush-lib/src/api/EnvironmentConfiguration.ts b/libraries/rush-lib/src/api/EnvironmentConfiguration.ts index 3bd511504b7..99b34ff369b 100644 --- a/libraries/rush-lib/src/api/EnvironmentConfiguration.ts +++ b/libraries/rush-lib/src/api/EnvironmentConfiguration.ts @@ -153,6 +153,12 @@ export enum EnvironmentVariableNames { */ RUSH_TAR_BINARY_PATH = 'RUSH_TAR_BINARY_PATH', + /** + * Internal variable that explicitly specifies the path for the version of `@microsoft/rush-lib` being executed. + * Will be set upon loading Rush. + */ + RUSH_LIB_PATH = '_RUSH_LIB_PATH', + /** * When Rush executes shell scripts, it sometimes changes the working directory to be a project folder or * the repository root folder. The original working directory (where the Rush command was invoked) is assigned @@ -441,6 +447,7 @@ export class EnvironmentConfiguration { break; case EnvironmentVariableNames.RUSH_INVOKED_FOLDER: + case EnvironmentVariableNames.RUSH_LIB_PATH: // Assigned by Rush itself break; diff --git a/libraries/rush-lib/src/api/Rush.ts b/libraries/rush-lib/src/api/Rush.ts index 5afe16a4738..3fcdc1cd221 100644 --- a/libraries/rush-lib/src/api/Rush.ts +++ b/libraries/rush-lib/src/api/Rush.ts @@ -10,6 +10,8 @@ import { PackageJsonLookup } from '@rushstack/node-core-library'; +import '../utilities/SetRushLibPath'; + import { RushCommandLineParser } from '../cli/RushCommandLineParser'; import { RushStartupBanner } from '../cli/RushStartupBanner'; import { RushXCommandLine } from '../cli/RushXCommandLine'; diff --git a/libraries/rush-lib/src/cli/actions/test/removeRepo/common/temp/rush#90625.lock b/libraries/rush-lib/src/cli/actions/test/removeRepo/common/temp/rush#90625.lock deleted file mode 100644 index b2b0d4002b8..00000000000 --- a/libraries/rush-lib/src/cli/actions/test/removeRepo/common/temp/rush#90625.lock +++ /dev/null @@ -1 +0,0 @@ -Fri Jan 27 01:50:33 2023 \ No newline at end of file diff --git a/libraries/rush-lib/src/utilities/SetRushLibPath.ts b/libraries/rush-lib/src/utilities/SetRushLibPath.ts new file mode 100644 index 00000000000..ec18843e67b --- /dev/null +++ b/libraries/rush-lib/src/utilities/SetRushLibPath.ts @@ -0,0 +1,12 @@ +import { PackageJsonLookup } from '@rushstack/node-core-library'; + +import { EnvironmentVariableNames } from '../api/EnvironmentConfiguration'; + +if (!process.env[EnvironmentVariableNames.RUSH_LIB_PATH]) { + const rootDir: string | undefined = PackageJsonLookup.instance.tryGetPackageFolderFor(__dirname); + if (rootDir) { + // Route to the 'main' field of package.json + const rushLibIndex: string = require.resolve(rootDir, { paths: [] }); + process.env[EnvironmentVariableNames.RUSH_LIB_PATH] = rushLibIndex; + } +} diff --git a/libraries/rush-sdk/README.md b/libraries/rush-sdk/README.md index 6f1cc9bfdc1..73ec410e3c7 100644 --- a/libraries/rush-sdk/README.md +++ b/libraries/rush-sdk/README.md @@ -10,7 +10,9 @@ The **@rushstack/rush-sdk** package acts as a lightweight proxy for accessing th 2. When authoring unit tests for a Rush plugin, developers should add **@microsoft/rush-lib** to their **package.json** `devDependencies`. In this context, **@rushstack/rush-sdk** will resolve to that instance for testing purposes. -3. For scripts and tools that are designed to be used in a Rush monorepo, in the future **@rushstack/rush-sdk** will automatically invoke **install-run-rush.js** and load the local installation. This ensures that tools load a compatible version of the Rush engine for the given branch. Once this is implemented, **@rushstack/rush-sdk** can replace **@microsoft/rush-lib** entirely as the official API interface, with the latter serving as the underlying implementation. +3. For projects within a monorepo that use **@rushstack/rush-sdk** during their build process, child processes will inherit the installation of Rush that invoked them. This is communicated using the `_RUSH_LIB_PATH` environment variable. + +4. For scripts and tools that are designed to be used in a Rush monorepo, in the future **@rushstack/rush-sdk** will automatically invoke **install-run-rush.js** and load the local installation. This ensures that tools load a compatible version of the Rush engine for the given branch. Once this is implemented, **@rushstack/rush-sdk** can replace **@microsoft/rush-lib** entirely as the official API interface, with the latter serving as the underlying implementation. The **@rushstack/rush-sdk** API declarations are identical to the corresponding version of **@microsoft/rush-lib**. @@ -42,8 +44,8 @@ Example 2: How to import an internal API: // WARNING: INTERNAL APIS MAY CHANGE AT ANY TIME -- USE THIS AT YOUR OWN RISK: // Important: Since we're calling an internal API, we need to use the unbundled .d.ts files -// instead of the normal .d.ts rollup -import { RushConfiguration } from '@rushstack/rush-sdk/lib/'; +// instead of the normal .d.ts rollup, otherwise TypeScript will complain about a type mismatch. +import { RushConfiguration } from '@rushstack/rush-sdk/lib/index'; const config = RushConfiguration.loadFromDefaultLocation(); console.log(config.commonFolder); diff --git a/libraries/rush-sdk/package.json b/libraries/rush-sdk/package.json index bb4ad81bbf0..a0cc5ae8868 100644 --- a/libraries/rush-sdk/package.json +++ b/libraries/rush-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@rushstack/rush-sdk", - "version": "5.92.0", + "version": "5.93.1", "description": "An API for interacting with the Rush engine", "repository": { "type": "git", diff --git a/libraries/rush-sdk/src/index.ts b/libraries/rush-sdk/src/index.ts index 3a05b4f1102..2677e9bef8d 100644 --- a/libraries/rush-sdk/src/index.ts +++ b/libraries/rush-sdk/src/index.ts @@ -15,7 +15,7 @@ import { } from '@rushstack/node-core-library'; import type { SpawnSyncReturns } from 'child_process'; -const RUSH_LIB_NAME: string = '@microsoft/rush-lib'; +const RUSH_LIB_NAME: '@microsoft/rush-lib' = '@microsoft/rush-lib'; const verboseEnabled: boolean = typeof process !== 'undefined' && process.env.RUSH_SDK_DEBUG === '1'; const terminal: Terminal = new Terminal( @@ -28,6 +28,7 @@ type RushLibModuleType = Record; declare const global: NodeJS.Global & typeof globalThis & { ___rush___rushLibModule?: RushLibModuleType; + ___rush___rushLibModuleFromEnvironment?: RushLibModuleType; ___rush___rushLibModuleFromInstallAndRunRush?: RushLibModuleType; }; @@ -46,7 +47,9 @@ function _require(moduleName: string): TResult { // SCENARIO 1: Rush's PluginManager has initialized "rush-sdk" with Rush's own instance of rush-lib. // The Rush host process will assign "global.___rush___rushLibModule" before loading the plugin. let rushLibModule: RushLibModuleType | undefined = - global.___rush___rushLibModule || global.___rush___rushLibModuleFromInstallAndRunRush; + global.___rush___rushLibModule || + global.___rush___rushLibModuleFromEnvironment || + global.___rush___rushLibModuleFromInstallAndRunRush; let errorMessage: string = ''; // SCENARIO 2: The project importing "rush-sdk" has installed its own instance of "rush-lib" @@ -89,7 +92,31 @@ if (rushLibModule === undefined) { } } -// SCENARIO 3: A tool or script depends on "rush-sdk", and is meant to be used inside a monorepo folder. +// SCENARIO 3: A tool or script has been invoked as a child process by an instance of "rush-lib" and can use the +// version that invoked it. In this case, use process.env._RUSH_LIB_PATH to find "rush-lib". +if (rushLibModule === undefined) { + const rushLibVariable: '_RUSH_LIB_PATH' = '_RUSH_LIB_PATH'; + const rushLibPath: string | undefined = process.env[rushLibVariable]; + if (rushLibPath) { + terminal.writeVerboseLine( + `Try to load ${RUSH_LIB_NAME} from process.env.${rushLibVariable} from caller package` + ); + try { + rushLibModule = _require(rushLibPath); + } catch (error) { + // Log this as a warning, since it is unexpected to define an incorrect value of the variable. + terminal.writeWarningLine(`Failed to load ${RUSH_LIB_NAME} via process.env.${rushLibVariable}`); + } + + if (rushLibModule !== undefined) { + // to track which scenario is active and how it got initialized. + global.___rush___rushLibModuleFromEnvironment = rushLibModule; + terminal.writeVerboseLine(`Loaded ${RUSH_LIB_NAME} from process.env.${rushLibVariable}`); + } + } +} + +// SCENARIO 4: A standalone tool or script depends on "rush-sdk", and is meant to be used inside a monorepo folder. // In this case, we can use install-run-rush.js to obtain the appropriate rush-lib version for the monorepo. if (rushLibModule === undefined) { try { diff --git a/libraries/rush-sdk/src/test/__snapshots__/script.test.ts.snap b/libraries/rush-sdk/src/test/__snapshots__/script.test.ts.snap new file mode 100644 index 00000000000..36bce37042e --- /dev/null +++ b/libraries/rush-sdk/src/test/__snapshots__/script.test.ts.snap @@ -0,0 +1,76 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`@rushstack/rush-sdk Should load via env when Rush has loaded (for child processes): stderr 1`] = `""`; + +exports[`@rushstack/rush-sdk Should load via env when Rush has loaded (for child processes): stdout 1`] = ` +"Try to load @microsoft/rush-lib from process.env._RUSH_LIB_PATH from caller package +Loaded @microsoft/rush-lib from process.env._RUSH_LIB_PATH +[ + '_rushSdk_loadInternalModule', + 'ApprovedPackagesConfiguration', + 'ApprovedPackagesItem', + 'ApprovedPackagesPolicy', + 'BuildCacheConfiguration', + 'BumpType', + 'ChangeManager', + 'CommonVersionsConfiguration', + 'CredentialCache', + 'DependencyType', + 'EnvironmentConfiguration', + 'EnvironmentVariableNames', + 'Event', + 'EventHooks', + 'ExperimentsConfiguration', + 'FileSystemBuildCacheProvider', + 'IndividualVersionPolicy', + 'LockStepVersionPolicy', + 'LookupByPath', + 'NpmOptionsConfiguration', + 'Operation', + 'OperationStatus', + 'PackageJsonDependency', + 'PackageJsonEditor', + 'PackageManager', + 'PackageManagerOptionsConfigurationBase', + 'PhasedCommandHooks', + 'PnpmOptionsConfiguration', + 'ProjectChangeAnalyzer', + 'RepoStateFile', + 'Rush', + 'RushConfiguration', + 'RushConfigurationProject', + 'RushConstants', + 'RushLifecycleHooks', + 'RushSession', + 'RushUserConfiguration', + 'VersionPolicy', + 'VersionPolicyConfiguration', + 'VersionPolicyDefinitionName', + 'YarnOptionsConfiguration', + '_LastInstallFlag', + '_OperationMetadataManager', + '_OperationStateFile', + '_RushGlobalFolder', + '_RushInternals' +]" +`; + +exports[`@rushstack/rush-sdk Should load via global (for plugins): stderr 1`] = `""`; + +exports[`@rushstack/rush-sdk Should load via global (for plugins): stdout 1`] = `"[ '_rushSdk_loadInternalModule', 'foo' ]"`; + +exports[`@rushstack/rush-sdk Should load via install-run (for standalone tools): stderr 1`] = `""`; + +exports[`@rushstack/rush-sdk Should load via install-run (for standalone tools): stdout 1`] = ` +"Trying to load @microsoft/rush-lib installed by install-run-rush +Loaded @microsoft/rush-lib installed by install-run-rush +[ '_rushSdk_loadInternalModule', 'foo' ]" +`; + +exports[`@rushstack/rush-sdk Should load via process.env._RUSH_LIB_PATH (for child processes): stderr 1`] = `""`; + +exports[`@rushstack/rush-sdk Should load via process.env._RUSH_LIB_PATH (for child processes): stdout 1`] = ` +"Try to load @microsoft/rush-lib from process.env._RUSH_LIB_PATH from caller package +Loaded @microsoft/rush-lib from process.env._RUSH_LIB_PATH +[ '_rushSdk_loadInternalModule', 'foo' ]" +`; diff --git a/libraries/rush-sdk/src/test/script.test.ts b/libraries/rush-sdk/src/test/script.test.ts index 78de0ca3843..e1919b55694 100644 --- a/libraries/rush-sdk/src/test/script.test.ts +++ b/libraries/rush-sdk/src/test/script.test.ts @@ -8,8 +8,72 @@ const mockRushLibPath: string = `${__dirname}/fixture/mock-rush-lib.js`; const coreLibPath: string = require.resolve('@rushstack/node-core-library'); -describe('used in script', () => { - it('should work when used in script', () => { +describe('@rushstack/rush-sdk', () => { + it('Should load via global (for plugins)', () => { + const result = Executable.spawnSync( + 'node', + [ + '-e', + ` +global.___rush___rushLibModule = { foo: 1 }; +console.log(Object.keys(require(${JSON.stringify(rushSdkPath)})));` + ], + { + currentWorkingDirectory: mockPackageFolder, + environment: { + ...process.env, + RUSH_SDK_DEBUG: '1', + _RUSH_LIB_PATH: '' // Need to clear if invoked via Rush + } + } + ); + expect(result.stderr.trim()).toMatchSnapshot('stderr'); + expect(result.stdout.trim()).toMatchSnapshot('stdout'); + expect(result.status).toBe(0); + }); + + it('Should load via env when Rush has loaded (for child processes)', () => { + const result = Executable.spawnSync( + 'node', + [ + '-e', + ` +require('@microsoft/rush-lib'); +console.log(Object.keys(require(${JSON.stringify(rushSdkPath)})));` + ], + { + currentWorkingDirectory: mockPackageFolder, + environment: { + ...process.env, + RUSH_SDK_DEBUG: '1', + _RUSH_LIB_PATH: '' // Need to clear if invoked via Rush + } + } + ); + expect(result.stderr.trim()).toMatchSnapshot('stderr'); + expect(result.stdout.trim()).toMatchSnapshot('stdout'); + expect(result.status).toBe(0); + }); + + it('Should load via process.env._RUSH_LIB_PATH (for child processes)', () => { + const result = Executable.spawnSync( + 'node', + ['-e', `console.log(Object.keys(require(${JSON.stringify(rushSdkPath)})));`], + { + currentWorkingDirectory: mockPackageFolder, + environment: { + ...process.env, + RUSH_SDK_DEBUG: '1', + _RUSH_LIB_PATH: mockRushLibPath + } + } + ); + expect(result.stderr.trim()).toMatchSnapshot('stderr'); + expect(result.stdout.trim()).toMatchSnapshot('stdout'); + expect(result.status).toBe(0); + }); + + it('Should load via install-run (for standalone tools)', () => { const result = Executable.spawnSync( 'node', [ @@ -24,20 +88,20 @@ const mockResolveModule = (options) => { return originalResolveModule(options); } Import.resolveModule = mockResolveModule; -console.log(require(${JSON.stringify(rushSdkPath)})); +console.log(Object.keys(require(${JSON.stringify(rushSdkPath)}))); ` ], { - currentWorkingDirectory: mockPackageFolder + currentWorkingDirectory: mockPackageFolder, + environment: { + ...process.env, + RUSH_SDK_DEBUG: '1', + _RUSH_LIB_PATH: '' // Need to clear if invoked via Rush + } } ); - expect(result.stderr.trim()).toMatchInlineSnapshot(`""`); - expect(result.stdout.trim()).toMatchInlineSnapshot(` -"{ - _rushSdk_loadInternalModule: [Function: _rushSdk_loadInternalModule], - foo: [Getter] -}" -`); + expect(result.stderr.trim()).toMatchSnapshot('stderr'); + expect(result.stdout.trim()).toMatchSnapshot('stdout'); expect(result.status).toBe(0); }); }); diff --git a/rush-plugins/rush-amazon-s3-build-cache-plugin/package.json b/rush-plugins/rush-amazon-s3-build-cache-plugin/package.json index 555e920ad82..f6f1d939f3c 100644 --- a/rush-plugins/rush-amazon-s3-build-cache-plugin/package.json +++ b/rush-plugins/rush-amazon-s3-build-cache-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@rushstack/rush-amazon-s3-build-cache-plugin", - "version": "5.92.0", + "version": "5.93.1", "description": "Rush plugin for Amazon S3 cloud build cache", "repository": { "type": "git", diff --git a/rush-plugins/rush-azure-storage-build-cache-plugin/package.json b/rush-plugins/rush-azure-storage-build-cache-plugin/package.json index 0dff50f9cad..17f538dabfb 100644 --- a/rush-plugins/rush-azure-storage-build-cache-plugin/package.json +++ b/rush-plugins/rush-azure-storage-build-cache-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@rushstack/rush-azure-storage-build-cache-plugin", - "version": "5.92.0", + "version": "5.93.1", "description": "Rush plugin for Azure storage cloud build cache", "repository": { "type": "git",