diff --git a/common/config/rush/build-cache.json b/common/config/rush/build-cache.json index 13fe1a5b2b4..59bc58ccb99 100644 --- a/common/config/rush/build-cache.json +++ b/common/config/rush/build-cache.json @@ -34,6 +34,11 @@ */ "cacheEntryNamePattern": "[projectName:normalize]-[phaseName:normalize]-[hash]", + /** + * (Optional) Salt to inject during calculation of the cache key. This can be used to invalidate the cache for all projects when the salt changes. + */ + // "cacheHashSalt": "1", + /** * Use this configuration with "cacheProvider"="azure-blob-storage" */ @@ -59,7 +64,15 @@ /** * If set to true, allow writing to the cache. Defaults to false. */ - // "isCacheWriteAllowed": true + // "isCacheWriteAllowed": true, + /** + * The Entra ID login flow to use. Defaults to 'AdoCodespacesAuth' on GitHub Codespaces, 'InteractiveBrowser' otherwise. + */ + // "loginFlow": "InteractiveBrowser", + /** + * If set to true, reading the cache requires authentication. Defaults to false. + */ + // "readRequiresAuthentication": true }, /** diff --git a/common/config/rush/experiments.json b/common/config/rush/experiments.json index 282d389ba0b..ef02a74979f 100644 --- a/common/config/rush/experiments.json +++ b/common/config/rush/experiments.json @@ -82,10 +82,30 @@ * If set to true, Rush will generate a `project-impact-graph.yaml` file in the repository root during `rush update`. */ // "generateProjectImpactGraphDuringRushUpdate": true, + /** * If true, when running in watch mode, Rush will check for phase scripts named `_phase::ipc` and run them instead * of `_phase:` if they exist. The created child process will be provided with an IPC channel and expected to persist * across invocations. */ - // "useIPCScriptsInWatchMode": true + // "useIPCScriptsInWatchMode": true, + + /** + * (UNDER DEVELOPMENT) The Rush alerts feature provides a way to send announcements to engineers + * working in the monorepo, by printing directly in the user's shell window when they invoke Rush commands. + * This ensures that important notices will be seen by anyone doing active development, since people often + * ignore normal discussion group messages or don't know to subscribe. + */ + // "rushAlerts": true, + + /** + * When using cobuilds, this experiment allows uncacheable operations to benefit from cobuild orchestration without using the build cache. + */ + // "allowCobuildWithoutCache": true, + + /** + * By default, rush perform a full scan of the entire repository. For example, Rush runs `git status` to check for local file changes. + * When this toggle is enabled, Rush will only scan specific paths, significantly speeding up Git operations. + */ + // "enableSubpathScan": true } diff --git a/common/config/rush/pnpm-config.json b/common/config/rush/pnpm-config.json index ace3d064ab1..b862ec1ff0a 100644 --- a/common/config/rush/pnpm-config.json +++ b/common/config/rush/pnpm-config.json @@ -1,6 +1,11 @@ /** * This configuration file provides settings specific to the PNPM package manager. * More documentation is available on the Rush website: https://rushjs.io + * + * Rush normally looks for this file in `common/config/rush/pnpm-config.json`. However, + * if `subspacesEnabled` is true in subspaces.json, then Rush will instead first look + * for `common/config/subspaces//pnpm-config.json`. (If the file exists in both places, + * then the file under `common/config/rush` is ignored.) */ { "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/pnpm-config.schema.json", @@ -196,6 +201,7 @@ "globalOverrides": { // "example1": "^1.0.0", // "example2": "npm:@company/example2@^1.0.0" + // TODO: Remove once https://github.com/dylang/npm-check/issues/499 // has been closed and a new version of `npm-check` is published. "package-json": "^7" @@ -422,6 +428,21 @@ // "fsevents" ], + /** + * The `globalIgnoredOptionalDependencies` setting suppresses the installation of optional NPM + * dependencies specified in the list. This is useful when certain optional dependencies are + * not needed in your environment, such as platform-specific packages or dependencies that + * fail during installation but are not critical to your project. + * These settings are copied into the `pnpm.overrides` field of the `common/temp/package.json` + * file that is generated by Rush during installation, instructing PNPM to ignore the specified + * optional dependencies. + * + * PNPM documentation: https://pnpm.io/package_json#pnpmignoredoptionaldependencies + */ + "globalIgnoredOptionalDependencies": [ + // "fsevents" + ], + /** * The `globalAllowedDeprecatedVersions` setting suppresses installation warnings for package * versions that the NPM registry reports as being deprecated. This is useful if the diff --git a/common/scripts/install-run.js b/common/scripts/install-run.js index b3e92130021..96cbd258b91 100644 --- a/common/scripts/install-run.js +++ b/common/scripts/install-run.js @@ -25,7 +25,8 @@ __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ isVariableSetInNpmrcFile: () => (/* binding */ isVariableSetInNpmrcFile), -/* harmony export */ syncNpmrc: () => (/* binding */ syncNpmrc) +/* harmony export */ syncNpmrc: () => (/* binding */ syncNpmrc), +/* harmony export */ trimNpmrcFileLines: () => (/* binding */ trimNpmrcFileLines) /* harmony export */ }); /* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! fs */ 179896); /* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_0__); @@ -46,7 +47,7 @@ __webpack_require__.r(__webpack_exports__); // create a global _combinedNpmrc for cache purpose const _combinedNpmrcMap = new Map(); function _trimNpmrcFile(options) { - const { sourceNpmrcPath, linesToPrepend, linesToAppend } = options; + const { sourceNpmrcPath, linesToPrepend, linesToAppend, supportEnvVarFallbackSyntax } = options; const combinedNpmrcFromCache = _combinedNpmrcMap.get(sourceNpmrcPath); if (combinedNpmrcFromCache !== undefined) { return combinedNpmrcFromCache; @@ -62,6 +63,21 @@ function _trimNpmrcFile(options) { npmrcFileLines.push(...linesToAppend); } npmrcFileLines = npmrcFileLines.map((line) => (line || '').trim()); + const resultLines = trimNpmrcFileLines(npmrcFileLines, process.env, supportEnvVarFallbackSyntax); + const combinedNpmrc = resultLines.join('\n'); + //save the cache + _combinedNpmrcMap.set(sourceNpmrcPath, combinedNpmrc); + return combinedNpmrc; +} +/** + * + * @param npmrcFileLines The npmrc file's lines + * @param env The environment variables object + * @param supportEnvVarFallbackSyntax Whether to support fallback values in the form of `${VAR_NAME:-fallback}` + * @returns + */ +function trimNpmrcFileLines(npmrcFileLines, env, supportEnvVarFallbackSyntax) { + var _a; const resultLines = []; // This finds environment variable tokens that look like "${VAR_NAME}" const expansionRegExp = /\$\{([^\}]+)\}/g; @@ -80,10 +96,35 @@ function _trimNpmrcFile(options) { const environmentVariables = line.match(expansionRegExp); if (environmentVariables) { for (const token of environmentVariables) { - // Remove the leading "${" and the trailing "}" from the token - const environmentVariableName = token.substring(2, token.length - 1); - // Is the environment variable defined? - if (!process.env[environmentVariableName]) { + /** + * Remove the leading "${" and the trailing "}" from the token + * + * ${nameString} -> nameString + * ${nameString-fallbackString} -> name-fallbackString + * ${nameString:-fallbackString} -> name:-fallbackString + */ + const nameWithFallback = token.substring(2, token.length - 1); + let environmentVariableName; + let fallback; + if (supportEnvVarFallbackSyntax) { + /** + * Get the environment variable name and fallback value. + * + * name fallback + * nameString -> nameString undefined + * nameString-fallbackString -> nameString fallbackString + * nameString:-fallbackString -> nameString fallbackString + */ + const matched = nameWithFallback.match(/^([^:-]+)(?:\:?-(.+))?$/); + // matched: [originStr, variableName, fallback] + environmentVariableName = (_a = matched === null || matched === void 0 ? void 0 : matched[1]) !== null && _a !== void 0 ? _a : nameWithFallback; + fallback = matched === null || matched === void 0 ? void 0 : matched[2]; + } + else { + environmentVariableName = nameWithFallback; + } + // Is the environment variable and fallback value defined. + if (!env[environmentVariableName] && !fallback) { // No, so trim this line lineShouldBeTrimmed = true; break; @@ -100,20 +141,13 @@ function _trimNpmrcFile(options) { resultLines.push(line); } } - const combinedNpmrc = resultLines.join('\n'); - //save the cache - _combinedNpmrcMap.set(sourceNpmrcPath, combinedNpmrc); - return combinedNpmrc; + return resultLines; } function _copyAndTrimNpmrcFile(options) { - const { logger, sourceNpmrcPath, targetNpmrcPath, linesToPrepend, linesToAppend } = options; + const { logger, sourceNpmrcPath, targetNpmrcPath } = options; logger.info(`Transforming ${sourceNpmrcPath}`); // Verbose logger.info(` --> "${targetNpmrcPath}"`); - const combinedNpmrc = _trimNpmrcFile({ - sourceNpmrcPath, - linesToPrepend, - linesToAppend - }); + const combinedNpmrc = _trimNpmrcFile(options); fs__WEBPACK_IMPORTED_MODULE_0__.writeFileSync(targetNpmrcPath, combinedNpmrc); return combinedNpmrc; } @@ -123,7 +157,7 @@ function syncNpmrc(options) { info: console.log, // eslint-disable-next-line no-console error: console.error - }, createIfMissing = false, linesToAppend, linesToPrepend } = options; + }, createIfMissing = false } = options; const sourceNpmrcPath = path__WEBPACK_IMPORTED_MODULE_1__.join(sourceNpmrcFolder, !useNpmrcPublish ? '.npmrc' : '.npmrc-publish'); const targetNpmrcPath = path__WEBPACK_IMPORTED_MODULE_1__.join(targetNpmrcFolder, '.npmrc'); try { @@ -132,13 +166,9 @@ function syncNpmrc(options) { if (!fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(targetNpmrcFolder)) { fs__WEBPACK_IMPORTED_MODULE_0__.mkdirSync(targetNpmrcFolder, { recursive: true }); } - return _copyAndTrimNpmrcFile({ - sourceNpmrcPath, + return _copyAndTrimNpmrcFile(Object.assign({ sourceNpmrcPath, targetNpmrcPath, - logger, - linesToAppend, - linesToPrepend - }); + logger }, options)); } else if (fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(targetNpmrcPath)) { // If the source .npmrc doesn't exist and there is one in the target, delete the one in the target @@ -150,13 +180,13 @@ function syncNpmrc(options) { throw new Error(`Error syncing .npmrc file: ${e}`); } } -function isVariableSetInNpmrcFile(sourceNpmrcFolder, variableKey) { +function isVariableSetInNpmrcFile(sourceNpmrcFolder, variableKey, supportEnvVarFallbackSyntax) { const sourceNpmrcPath = `${sourceNpmrcFolder}/.npmrc`; //if .npmrc file does not exist, return false directly if (!fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(sourceNpmrcPath)) { return false; } - const trimmedNpmrcFile = _trimNpmrcFile({ sourceNpmrcPath }); + const trimmedNpmrcFile = _trimNpmrcFile({ sourceNpmrcPath, supportEnvVarFallbackSyntax }); const variableKeyRegExp = new RegExp(`^${variableKey}=`, 'm'); return trimmedNpmrcFile.match(variableKeyRegExp) !== null; } @@ -440,7 +470,8 @@ function _resolvePackageVersion(logger, rushCommonFolder, { name, version }) { (0,_utilities_npmrcUtilities__WEBPACK_IMPORTED_MODULE_4__.syncNpmrc)({ sourceNpmrcFolder, targetNpmrcFolder: rushTempFolder, - logger + logger, + supportEnvVarFallbackSyntax: false }); const npmPath = getNpmPath(); // This returns something that looks like: @@ -656,7 +687,8 @@ function installAndRun(logger, packageName, packageVersion, packageBinName, pack (0,_utilities_npmrcUtilities__WEBPACK_IMPORTED_MODULE_4__.syncNpmrc)({ sourceNpmrcFolder, targetNpmrcFolder: packageInstallFolder, - logger + logger, + supportEnvVarFallbackSyntax: false }); _createPackageJson(packageInstallFolder, packageName, packageVersion); const command = lockFilePath ? 'ci' : 'install'; diff --git a/rush.json b/rush.json index 3c42d3cf058..690690c365f 100644 --- a/rush.json +++ b/rush.json @@ -16,7 +16,7 @@ * path segment in the "$schema" field for all your Rush config files. This will ensure * correct error-underlining and tab-completion for editors such as VS Code. */ - "rushVersion": "5.145.0-pr5009.2", + "rushVersion": "5.147.2", /** * The next field selects which package manager should be installed and determines its version. @@ -65,6 +65,13 @@ */ // "suppressNodeLtsWarning": false, + /** + * Rush normally prints a warning if it detects that the current version is not one published to the + * public npmjs.org registry. If you need to block calls to the npm registry, you can use this setting to disable + * Rush's check. + */ + // "suppressRushIsPublicVersionCheck": false, + /** * Large monorepos can become intimidating for newcomers if project folder paths don't follow * a consistent and recognizable pattern. When the system allows nested folder trees, @@ -183,7 +190,7 @@ // "changeLogUpdateCommitMessage": "Update changelogs [skip ci]", /** - * The commit message to use when commiting changefiles during 'rush change --commit' + * The commit message to use when committing changefiles during 'rush change --commit' * * If no commit message is set it will default to 'Rush change' */ @@ -258,6 +265,37 @@ "postRushx": [] }, + /** + * Installation variants allow you to maintain a parallel set of configuration files that can be + * used to build the entire monorepo with an alternate set of dependencies. For example, suppose + * you upgrade all your projects to use a new release of an important framework, but during a transition period + * you intend to maintain compatibility with the old release. In this situation, you probably want your + * CI validation to build the entire repo twice: once with the old release, and once with the new release. + * + * Rush "installation variants" correspond to sets of config files located under this folder: + * + * common/config/rush/variants/ + * + * The variant folder can contain an alternate common-versions.json file. Its "preferredVersions" field can be used + * to select older versions of dependencies (within a loose SemVer range specified in your package.json files). + * To install a variant, run "rush install --variant ". + * + * For more details and instructions, see this article: https://rushjs.io/pages/advanced/installation_variants/ + */ + "variants": [ + // { + // /** + // * The folder name for this variant. + // */ + // "variantName": "old-sdk", + // + // /** + // * An informative description + // */ + // "description": "Build this repo using the previous release of the SDK" + // } + ], + /** * Rush can collect anonymous telemetry about everyday developer activity such as * success/failure of installs, builds, and other operations. You can use this to identify