From 1c06383f9ac75c1d61e15995213881f45477c9f5 Mon Sep 17 00:00:00 2001 From: William Huang Date: Mon, 12 Aug 2024 16:13:27 -0700 Subject: [PATCH 1/7] Adds support for a seperate rush-projects.json configuration file --- ...perate-rush-projects_2024-08-12-23-13.json | 10 ++ common/reviews/api/rush-lib.api.md | 5 + .../rush-lib/src/api/RushConfiguration.ts | 35 ++++- libraries/rush-lib/src/logic/RushConstants.ts | 5 + .../rush-lib/src/schemas/projects.schema.json | 148 ++++++++++++++++++ .../rush-lib/src/schemas/rush.schema.json | 2 +- 6 files changed, 203 insertions(+), 2 deletions(-) create mode 100644 common/changes/@microsoft/rush/will-seperate-rush-projects_2024-08-12-23-13.json create mode 100644 libraries/rush-lib/src/schemas/projects.schema.json diff --git a/common/changes/@microsoft/rush/will-seperate-rush-projects_2024-08-12-23-13.json b/common/changes/@microsoft/rush/will-seperate-rush-projects_2024-08-12-23-13.json new file mode 100644 index 00000000000..1cc90407c26 --- /dev/null +++ b/common/changes/@microsoft/rush/will-seperate-rush-projects_2024-08-12-23-13.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@microsoft/rush", + "comment": "Adds the option of seperately defining the list of rush projects in a dedicated \"rush-projects.json\" file", + "type": "none" + } + ], + "packageName": "@microsoft/rush" +} \ No newline at end of file diff --git a/common/reviews/api/rush-lib.api.md b/common/reviews/api/rush-lib.api.md index 95f430832c7..485fcf48686 100644 --- a/common/reviews/api/rush-lib.api.md +++ b/common/reviews/api/rush-lib.api.md @@ -1229,6 +1229,10 @@ export class RushConfiguration { // // @internal (undocumented) readonly _rushPluginsConfiguration: RushPluginsConfiguration; + // Warning: (ae-forgotten-export) The symbol "IRushProjectsJson" needs to be exported by the entry point index.d.ts + // + // @internal + readonly rushProjectsJson: IRushProjectsJson; readonly shrinkwrapFilename: string; get shrinkwrapFilePhrase(): string; // @beta @@ -1351,6 +1355,7 @@ export class RushConstants { static readonly rushPluginManifestFilename: 'rush-plugin-manifest.json'; static readonly rushPluginsConfigFilename: 'rush-plugins.json'; static readonly rushProjectConfigFilename: 'rush-project.json'; + static readonly rushProjectsFilename: 'rush-projects.json'; static readonly rushRecyclerFolderName: 'rush-recycler'; static readonly rushTempFolderName: 'temp'; static readonly rushTempNpmScope: '@rush-temp'; diff --git a/libraries/rush-lib/src/api/RushConfiguration.ts b/libraries/rush-lib/src/api/RushConfiguration.ts index f3fa0cbd6e4..66eeeb71af5 100644 --- a/libraries/rush-lib/src/api/RushConfiguration.ts +++ b/libraries/rush-lib/src/api/RushConfiguration.ts @@ -175,6 +175,14 @@ export interface IRushConfigurationJson { variants?: unknown; } +/** + * This represents the JSON data structure for the "projects.json" configuration file. + * See projects.schema.json for documentation + */ +export interface IRushProjectsJson { + projects: IRushConfigurationProjectJson[]; +} + /** * The filter parameters to search from all projects */ @@ -247,6 +255,13 @@ export class RushConfiguration { */ public readonly rushConfigurationJson: IRushConfigurationJson; + /** + * Gets the JSON data structure for the "projects.json" configuration file. + * + * @internal + */ + public readonly rushProjectsJson: IRushProjectsJson | undefined; + /** * The absolute path to the "rush.json" configuration file that was loaded to construct this object. */ @@ -867,9 +882,27 @@ export class RushConfiguration { throw new InternalError('The default subspace was not created'); } + // Look for rush projects in a seperate file first, and if it does not exist fallback onto rush.json + + const resolvedRushProjectsFilename: string = path.resolve( + `${path.dirname(this.rushJsonFile)}/${RushConstants.rushProjectsFilename}` + ); + let rushProjects: IRushConfigurationProjectJson[]; + if (FileSystem.exists(resolvedRushProjectsFilename)) { + // Load the rush.json before we fix the casing. If the case is wrong on a case-sensitive filesystem, + // the next line show throw. + const rushProjectsJson: IRushProjectsJson = JsonFile.load(resolvedRushProjectsFilename); + rushProjects = rushProjectsJson.projects; + } else if (this.rushConfigurationJson.projects) { + rushProjects = this.rushConfigurationJson.projects; + } else { + throw new Error( + `The rush.json is missing a projects field, and a seperate ${RushConstants.rushProjectsFilename} file is missing. Rush projects need to be defined in one of the two places.` + ); + } // Sort the projects array in alphabetical order. This ensures that the packages // are processed in a deterministic order by the various Rush algorithms. - const sortedProjectJsons: IRushConfigurationProjectJson[] = this.rushConfigurationJson.projects.slice(0); + const sortedProjectJsons: IRushConfigurationProjectJson[] = rushProjects.slice(0); sortedProjectJsons.sort((a: IRushConfigurationProjectJson, b: IRushConfigurationProjectJson) => a.packageName.localeCompare(b.packageName) ); diff --git a/libraries/rush-lib/src/logic/RushConstants.ts b/libraries/rush-lib/src/logic/RushConstants.ts index ad0099d7cc1..09a21d523d8 100644 --- a/libraries/rush-lib/src/logic/RushConstants.ts +++ b/libraries/rush-lib/src/logic/RushConstants.ts @@ -17,6 +17,11 @@ export class RushConstants { */ public static readonly rushJsonFilename: 'rush.json' = 'rush.json'; + /** + * The filename ("rush-projects.json") for the root-level projects configuration file. + */ + public static readonly rushProjectsFilename: 'rush-projects.json' = 'rush-projects.json'; + /** * The filename ("browser-approved-packages.json") for an optional policy configuration file * that stores a list of NPM packages that have been approved for usage by Rush projects. diff --git a/libraries/rush-lib/src/schemas/projects.schema.json b/libraries/rush-lib/src/schemas/projects.schema.json new file mode 100644 index 00000000000..7d3d9f02a59 --- /dev/null +++ b/libraries/rush-lib/src/schemas/projects.schema.json @@ -0,0 +1,148 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Rush main config File", + "description": "The main configuration file for the Rush multi-project build tool. See http://rushjs.io for details.", + "type": "object", + + "definitions": { + "environmentVariables": { + "description": "Environment variables for the package manager", + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "override": { + "type": "boolean" + } + }, + "additionalProperties": false + } + } + }, + + "properties": { + "$schema": { + "description": "Part of the JSON Schema standard, this optional keyword declares the URL of the schema that the file conforms to. Editors may download the schema and use it to perform syntax highlighting.", + "type": "string" + }, + "projects": { + "description": "A list of projects managed by this tool.", + "type": "array", + "items": { + "type": "object", + "properties": { + "packageName": { + "description": "The NPM package name of the project.", + "type": "string" + }, + "projectFolder": { + "description": "The path to the project folder relative to the Rush config file.", + "type": "string" + }, + "reviewCategory": { + "description": "An optional category for usage in the \"browser-approved-packages.json\" and \"nonbrowser-approved-packages.json\" files. Only strings from reviewCategories are allowed here.", + "type": "string" + }, + "cyclicDependencyProjects": { + "description": "(Deprecated) This field was renamed to \"decoupledLocalDependencies\".", + "type": "array", + "items": { + "type": "string" + } + }, + "decoupledLocalDependencies": { + "description": "A list of local projects that appear as devDependencies for this project, but cannot be locally linked because it would create a cyclic dependency; instead, the last published version will be installed in the Common folder.", + "type": "array", + "items": { + "type": "string" + } + }, + "shouldPublish": { + "description": "A flag indicating that changes to this project will be published to npm, which affects the Rush change and publish workflows.", + "type": "boolean" + }, + "skipRushCheck": { + "description": "If true, then this project will be ignored by the \"rush check\" command. The default value is false.", + "type": "boolean" + }, + "versionPolicyName": { + "description": "An optional version policy associated with the project. Version policies are defined in \"version-policies.json\" file.", + "type": "string" + }, + "publishFolder": { + "description": "Facilitates postprocessing of a project's files prior to publishing. If specified, the \"publishFolder\" is the relative path to a subfolder of the project folder. The \"rush publish\" command will publish the subfolder instead of the project folder. The subfolder must contain its own package.json file, which is typically a build output.", + "type": "string" + }, + "tags": { + "description": "An optional set of custom tags that can be used to select this project. For example, adding \"my-custom-tag\" will allow this project to be selected by the command \"rush list --only tag:my-custom-tag\". The tag name must be one or more words separated by hyphens or slashes, where a word may contain lowercase ASCII letters, digits, \".\", and \"@\" characters.", + "type": "array", + "items": { + "type": "string", + "pattern": "^[a-z0-9.@]+([-/][a-z0-9.@]+)*$" + } + }, + "subspaceName": { + "description": "(EXPERIMENTAL) An optional entry for specifying which subspace this project belongs to if the subspaces feature is enabled.", + "type": "string" + } + }, + "additionalProperties": false, + "required": ["packageName", "projectFolder"] + } + }, + "eventHooks": { + "description": "Hooks are customized script actions that Rush executes when specific events occur.", + "type": "object", + "properties": { + "preRushInstall": { + "description": "The list of scripts to run before the Rush installation starts.", + "type": "array", + "items": { + "type": "string" + } + }, + "postRushInstall": { + "description": "The list of scripts to run after the Rush installation finishes.", + "type": "array", + "items": { + "type": "string" + } + }, + "preRushBuild": { + "description": "The list of scripts to run before the Rush build command starts.", + "type": "array", + "items": { + "type": "string" + } + }, + "postRushBuild": { + "description": "The list of scripts to run after the Rush build command finishes.", + "type": "array", + "items": { + "type": "string" + } + }, + "preRushx": { + "description": "The list of scripts to run before rushx starts.", + "type": "array", + "items": { + "type": "string" + } + }, + "postRushx": { + "description": "The list of scripts to run after rushx finishes.", + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false, + "required": ["projects"] +} diff --git a/libraries/rush-lib/src/schemas/rush.schema.json b/libraries/rush-lib/src/schemas/rush.schema.json index 46965cbbd41..b1577ecc636 100644 --- a/libraries/rush-lib/src/schemas/rush.schema.json +++ b/libraries/rush-lib/src/schemas/rush.schema.json @@ -354,5 +354,5 @@ } }, "additionalProperties": false, - "required": ["rushVersion", "projects"] + "required": ["rushVersion"] } From e898f196f5a4af8908788f8dbf3c9ebcb9d74e1f Mon Sep 17 00:00:00 2001 From: William Huang Date: Mon, 12 Aug 2024 16:24:33 -0700 Subject: [PATCH 2/7] Show better errors if projects are defined both in rush.json and rush-projects.json --- common/reviews/api/rush-lib.api.md | 2 +- libraries/rush-lib/src/api/RushConfiguration.ts | 15 ++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/common/reviews/api/rush-lib.api.md b/common/reviews/api/rush-lib.api.md index 485fcf48686..ae6dcaf372e 100644 --- a/common/reviews/api/rush-lib.api.md +++ b/common/reviews/api/rush-lib.api.md @@ -1232,7 +1232,7 @@ export class RushConfiguration { // Warning: (ae-forgotten-export) The symbol "IRushProjectsJson" needs to be exported by the entry point index.d.ts // // @internal - readonly rushProjectsJson: IRushProjectsJson; + readonly rushProjectsJson: IRushProjectsJson | undefined; readonly shrinkwrapFilename: string; get shrinkwrapFilePhrase(): string; // @beta diff --git a/libraries/rush-lib/src/api/RushConfiguration.ts b/libraries/rush-lib/src/api/RushConfiguration.ts index 66eeeb71af5..cbd4d728ea6 100644 --- a/libraries/rush-lib/src/api/RushConfiguration.ts +++ b/libraries/rush-lib/src/api/RushConfiguration.ts @@ -887,15 +887,20 @@ export class RushConfiguration { const resolvedRushProjectsFilename: string = path.resolve( `${path.dirname(this.rushJsonFile)}/${RushConstants.rushProjectsFilename}` ); - let rushProjects: IRushConfigurationProjectJson[]; + let rushProjects: IRushConfigurationProjectJson[] | undefined; if (FileSystem.exists(resolvedRushProjectsFilename)) { - // Load the rush.json before we fix the casing. If the case is wrong on a case-sensitive filesystem, - // the next line show throw. const rushProjectsJson: IRushProjectsJson = JsonFile.load(resolvedRushProjectsFilename); rushProjects = rushProjectsJson.projects; - } else if (this.rushConfigurationJson.projects) { + } + if (this.rushConfigurationJson.projects) { + if (rushProjects) { + throw new Error( + `When using the ${RushConstants.rushProjectsFilename} configuration file, the "projects" field of the ${RushConstants.rushJsonFilename} is no longer allowed.` + ); + } rushProjects = this.rushConfigurationJson.projects; - } else { + } + if (!rushProjects) { throw new Error( `The rush.json is missing a projects field, and a seperate ${RushConstants.rushProjectsFilename} file is missing. Rush projects need to be defined in one of the two places.` ); From 6ab7fd2c33598ec3eb5632bc4977d1723415fbac Mon Sep 17 00:00:00 2001 From: William Huang Date: Mon, 26 Aug 2024 14:14:44 -0700 Subject: [PATCH 3/7] Address PR comments --- common/reviews/api/rush-lib.api.md | 2 +- .../rush-lib/src/api/RushConfiguration.ts | 13 +- .../rush-lib/src/schemas/projects.schema.json | 136 +----------------- .../schemas/rush-project-config.schema.json | 67 +++++++++ .../rush-lib/src/schemas/rush.schema.json | 64 +-------- 5 files changed, 80 insertions(+), 202 deletions(-) create mode 100644 libraries/rush-lib/src/schemas/rush-project-config.schema.json diff --git a/common/reviews/api/rush-lib.api.md b/common/reviews/api/rush-lib.api.md index ae6dcaf372e..5ff29db6e96 100644 --- a/common/reviews/api/rush-lib.api.md +++ b/common/reviews/api/rush-lib.api.md @@ -1232,7 +1232,7 @@ export class RushConfiguration { // Warning: (ae-forgotten-export) The symbol "IRushProjectsJson" needs to be exported by the entry point index.d.ts // // @internal - readonly rushProjectsJson: IRushProjectsJson | undefined; + readonly _rushProjectsJson: IRushProjectsJson | undefined; readonly shrinkwrapFilename: string; get shrinkwrapFilePhrase(): string; // @beta diff --git a/libraries/rush-lib/src/api/RushConfiguration.ts b/libraries/rush-lib/src/api/RushConfiguration.ts index cbd4d728ea6..8edaa39617f 100644 --- a/libraries/rush-lib/src/api/RushConfiguration.ts +++ b/libraries/rush-lib/src/api/RushConfiguration.ts @@ -260,7 +260,7 @@ export class RushConfiguration { * * @internal */ - public readonly rushProjectsJson: IRushProjectsJson | undefined; + public readonly _rushProjectsJson: IRushProjectsJson | undefined; /** * The absolute path to the "rush.json" configuration file that was loaded to construct this object. @@ -884,13 +884,15 @@ export class RushConfiguration { // Look for rush projects in a seperate file first, and if it does not exist fallback onto rush.json - const resolvedRushProjectsFilename: string = path.resolve( - `${path.dirname(this.rushJsonFile)}/${RushConstants.rushProjectsFilename}` - ); + const resolvedRushProjectsFilename: string = `${this.rushJsonFolder}/${RushConstants.rushProjectsFilename}`; let rushProjects: IRushConfigurationProjectJson[] | undefined; - if (FileSystem.exists(resolvedRushProjectsFilename)) { + try { const rushProjectsJson: IRushProjectsJson = JsonFile.load(resolvedRushProjectsFilename); rushProjects = rushProjectsJson.projects; + } catch (e) { + if (!FileSystem.isNotExistError(e)) { + throw e; + } } if (this.rushConfigurationJson.projects) { if (rushProjects) { @@ -900,6 +902,7 @@ export class RushConfiguration { } rushProjects = this.rushConfigurationJson.projects; } + if (!rushProjects) { throw new Error( `The rush.json is missing a projects field, and a seperate ${RushConstants.rushProjectsFilename} file is missing. Rush projects need to be defined in one of the two places.` diff --git a/libraries/rush-lib/src/schemas/projects.schema.json b/libraries/rush-lib/src/schemas/projects.schema.json index 7d3d9f02a59..b2008bddd03 100644 --- a/libraries/rush-lib/src/schemas/projects.schema.json +++ b/libraries/rush-lib/src/schemas/projects.schema.json @@ -1,146 +1,16 @@ { "$schema": "http://json-schema.org/draft-04/schema#", - "title": "Rush main config File", - "description": "The main configuration file for the Rush multi-project build tool. See http://rushjs.io for details.", + "title": "Rush main project list config File", + "description": "The configuration file for the projects used in a Rush monorepo.", "type": "object", - "definitions": { - "environmentVariables": { - "description": "Environment variables for the package manager", - "type": "object", - "additionalProperties": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "override": { - "type": "boolean" - } - }, - "additionalProperties": false - } - } - }, - "properties": { "$schema": { "description": "Part of the JSON Schema standard, this optional keyword declares the URL of the schema that the file conforms to. Editors may download the schema and use it to perform syntax highlighting.", "type": "string" }, "projects": { - "description": "A list of projects managed by this tool.", - "type": "array", - "items": { - "type": "object", - "properties": { - "packageName": { - "description": "The NPM package name of the project.", - "type": "string" - }, - "projectFolder": { - "description": "The path to the project folder relative to the Rush config file.", - "type": "string" - }, - "reviewCategory": { - "description": "An optional category for usage in the \"browser-approved-packages.json\" and \"nonbrowser-approved-packages.json\" files. Only strings from reviewCategories are allowed here.", - "type": "string" - }, - "cyclicDependencyProjects": { - "description": "(Deprecated) This field was renamed to \"decoupledLocalDependencies\".", - "type": "array", - "items": { - "type": "string" - } - }, - "decoupledLocalDependencies": { - "description": "A list of local projects that appear as devDependencies for this project, but cannot be locally linked because it would create a cyclic dependency; instead, the last published version will be installed in the Common folder.", - "type": "array", - "items": { - "type": "string" - } - }, - "shouldPublish": { - "description": "A flag indicating that changes to this project will be published to npm, which affects the Rush change and publish workflows.", - "type": "boolean" - }, - "skipRushCheck": { - "description": "If true, then this project will be ignored by the \"rush check\" command. The default value is false.", - "type": "boolean" - }, - "versionPolicyName": { - "description": "An optional version policy associated with the project. Version policies are defined in \"version-policies.json\" file.", - "type": "string" - }, - "publishFolder": { - "description": "Facilitates postprocessing of a project's files prior to publishing. If specified, the \"publishFolder\" is the relative path to a subfolder of the project folder. The \"rush publish\" command will publish the subfolder instead of the project folder. The subfolder must contain its own package.json file, which is typically a build output.", - "type": "string" - }, - "tags": { - "description": "An optional set of custom tags that can be used to select this project. For example, adding \"my-custom-tag\" will allow this project to be selected by the command \"rush list --only tag:my-custom-tag\". The tag name must be one or more words separated by hyphens or slashes, where a word may contain lowercase ASCII letters, digits, \".\", and \"@\" characters.", - "type": "array", - "items": { - "type": "string", - "pattern": "^[a-z0-9.@]+([-/][a-z0-9.@]+)*$" - } - }, - "subspaceName": { - "description": "(EXPERIMENTAL) An optional entry for specifying which subspace this project belongs to if the subspaces feature is enabled.", - "type": "string" - } - }, - "additionalProperties": false, - "required": ["packageName", "projectFolder"] - } - }, - "eventHooks": { - "description": "Hooks are customized script actions that Rush executes when specific events occur.", - "type": "object", - "properties": { - "preRushInstall": { - "description": "The list of scripts to run before the Rush installation starts.", - "type": "array", - "items": { - "type": "string" - } - }, - "postRushInstall": { - "description": "The list of scripts to run after the Rush installation finishes.", - "type": "array", - "items": { - "type": "string" - } - }, - "preRushBuild": { - "description": "The list of scripts to run before the Rush build command starts.", - "type": "array", - "items": { - "type": "string" - } - }, - "postRushBuild": { - "description": "The list of scripts to run after the Rush build command finishes.", - "type": "array", - "items": { - "type": "string" - } - }, - "preRushx": { - "description": "The list of scripts to run before rushx starts.", - "type": "array", - "items": { - "type": "string" - } - }, - "postRushx": { - "description": "The list of scripts to run after rushx finishes.", - "type": "array", - "items": { - "type": "string" - } - } - }, - "additionalProperties": false + "description": "A list of projects managed by this tool." } }, "additionalProperties": false, diff --git a/libraries/rush-lib/src/schemas/rush-project-config.schema.json b/libraries/rush-lib/src/schemas/rush-project-config.schema.json new file mode 100644 index 00000000000..ee813fdb6e8 --- /dev/null +++ b/libraries/rush-lib/src/schemas/rush-project-config.schema.json @@ -0,0 +1,67 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Project list managed by rush.", + "description": "A list of projects managed by rush.", + "type": "array", + "items": { + "type": "object", + "properties": { + "packageName": { + "description": "The NPM package name of the project.", + "type": "string" + }, + "projectFolder": { + "description": "The path to the project folder relative to the Rush config file.", + "type": "string" + }, + "reviewCategory": { + "description": "An optional category for usage in the \"browser-approved-packages.json\" and \"nonbrowser-approved-packages.json\" files. Only strings from reviewCategories are allowed here.", + "type": "string" + }, + "cyclicDependencyProjects": { + "description": "(Deprecated) This field was renamed to \"decoupledLocalDependencies\".", + "type": "array", + "items": { + "type": "string" + } + }, + "decoupledLocalDependencies": { + "description": "A list of local projects that appear as devDependencies for this project, but cannot be locally linked because it would create a cyclic dependency; instead, the last published version will be installed in the Common folder.", + "type": "array", + "items": { + "type": "string" + } + }, + "shouldPublish": { + "description": "A flag indicating that changes to this project will be published to npm, which affects the Rush change and publish workflows.", + "type": "boolean" + }, + "skipRushCheck": { + "description": "If true, then this project will be ignored by the \"rush check\" command. The default value is false.", + "type": "boolean" + }, + "versionPolicyName": { + "description": "An optional version policy associated with the project. Version policies are defined in \"version-policies.json\" file.", + "type": "string" + }, + "publishFolder": { + "description": "Facilitates postprocessing of a project's files prior to publishing. If specified, the \"publishFolder\" is the relative path to a subfolder of the project folder. The \"rush publish\" command will publish the subfolder instead of the project folder. The subfolder must contain its own package.json file, which is typically a build output.", + "type": "string" + }, + "tags": { + "description": "An optional set of custom tags that can be used to select this project. For example, adding \"my-custom-tag\" will allow this project to be selected by the command \"rush list --only tag:my-custom-tag\". The tag name must be one or more words separated by hyphens or slashes, where a word may contain lowercase ASCII letters, digits, \".\", and \"@\" characters.", + "type": "array", + "items": { + "type": "string", + "pattern": "^[a-z0-9.@]+([-/][a-z0-9.@]+)*$" + } + }, + "subspaceName": { + "description": "(EXPERIMENTAL) An optional entry for specifying which subspace this project belongs to if the subspaces feature is enabled.", + "type": "string" + } + }, + "additionalProperties": false, + "required": ["packageName", "projectFolder"] + } +} diff --git a/libraries/rush-lib/src/schemas/rush.schema.json b/libraries/rush-lib/src/schemas/rush.schema.json index b1577ecc636..498b4ca7b88 100644 --- a/libraries/rush-lib/src/schemas/rush.schema.json +++ b/libraries/rush-lib/src/schemas/rush.schema.json @@ -239,69 +239,7 @@ } }, "projects": { - "description": "A list of projects managed by this tool.", - "type": "array", - "items": { - "type": "object", - "properties": { - "packageName": { - "description": "The NPM package name of the project.", - "type": "string" - }, - "projectFolder": { - "description": "The path to the project folder relative to the Rush config file.", - "type": "string" - }, - "reviewCategory": { - "description": "An optional category for usage in the \"browser-approved-packages.json\" and \"nonbrowser-approved-packages.json\" files. Only strings from reviewCategories are allowed here.", - "type": "string" - }, - "cyclicDependencyProjects": { - "description": "(Deprecated) This field was renamed to \"decoupledLocalDependencies\".", - "type": "array", - "items": { - "type": "string" - } - }, - "decoupledLocalDependencies": { - "description": "A list of local projects that appear as devDependencies for this project, but cannot be locally linked because it would create a cyclic dependency; instead, the last published version will be installed in the Common folder.", - "type": "array", - "items": { - "type": "string" - } - }, - "shouldPublish": { - "description": "A flag indicating that changes to this project will be published to npm, which affects the Rush change and publish workflows.", - "type": "boolean" - }, - "skipRushCheck": { - "description": "If true, then this project will be ignored by the \"rush check\" command. The default value is false.", - "type": "boolean" - }, - "versionPolicyName": { - "description": "An optional version policy associated with the project. Version policies are defined in \"version-policies.json\" file.", - "type": "string" - }, - "publishFolder": { - "description": "Facilitates postprocessing of a project's files prior to publishing. If specified, the \"publishFolder\" is the relative path to a subfolder of the project folder. The \"rush publish\" command will publish the subfolder instead of the project folder. The subfolder must contain its own package.json file, which is typically a build output.", - "type": "string" - }, - "tags": { - "description": "An optional set of custom tags that can be used to select this project. For example, adding \"my-custom-tag\" will allow this project to be selected by the command \"rush list --only tag:my-custom-tag\". The tag name must be one or more words separated by hyphens or slashes, where a word may contain lowercase ASCII letters, digits, \".\", and \"@\" characters.", - "type": "array", - "items": { - "type": "string", - "pattern": "^[a-z0-9.@]+([-/][a-z0-9.@]+)*$" - } - }, - "subspaceName": { - "description": "(EXPERIMENTAL) An optional entry for specifying which subspace this project belongs to if the subspaces feature is enabled.", - "type": "string" - } - }, - "additionalProperties": false, - "required": ["packageName", "projectFolder"] - } + "description": "A list of projects managed by this tool." }, "eventHooks": { "description": "Hooks are customized script actions that Rush executes when specific events occur.", From 9b06de269db9e99663fc9ad41616852cad7f725a Mon Sep 17 00:00:00 2001 From: William Huang Date: Mon, 26 Aug 2024 14:15:54 -0700 Subject: [PATCH 4/7] Update libraries/rush-lib/src/api/RushConfiguration.ts Co-authored-by: Kenrick --- libraries/rush-lib/src/api/RushConfiguration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/rush-lib/src/api/RushConfiguration.ts b/libraries/rush-lib/src/api/RushConfiguration.ts index 8edaa39617f..a4715287f44 100644 --- a/libraries/rush-lib/src/api/RushConfiguration.ts +++ b/libraries/rush-lib/src/api/RushConfiguration.ts @@ -176,7 +176,7 @@ export interface IRushConfigurationJson { } /** - * This represents the JSON data structure for the "projects.json" configuration file. + * This represents the JSON data structure for the "rush-projects.json" configuration file. * See projects.schema.json for documentation */ export interface IRushProjectsJson { From d7a534cfa4ba8b6c937bf43bcaa8618e9368e65a Mon Sep 17 00:00:00 2001 From: William Huang Date: Mon, 26 Aug 2024 14:16:00 -0700 Subject: [PATCH 5/7] Update libraries/rush-lib/src/api/RushConfiguration.ts Co-authored-by: Kenrick --- libraries/rush-lib/src/api/RushConfiguration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/rush-lib/src/api/RushConfiguration.ts b/libraries/rush-lib/src/api/RushConfiguration.ts index a4715287f44..14a27c965d4 100644 --- a/libraries/rush-lib/src/api/RushConfiguration.ts +++ b/libraries/rush-lib/src/api/RushConfiguration.ts @@ -256,7 +256,7 @@ export class RushConfiguration { public readonly rushConfigurationJson: IRushConfigurationJson; /** - * Gets the JSON data structure for the "projects.json" configuration file. + * Gets the JSON data structure for the "rush-projects.json" configuration file. * * @internal */ From c833e4ca43c4c4d444ebba4553c5ba65c9484010 Mon Sep 17 00:00:00 2001 From: William Huang Date: Tue, 27 Aug 2024 12:44:44 -0700 Subject: [PATCH 6/7] Update common/changes/@microsoft/rush/will-seperate-rush-projects_2024-08-12-23-13.json Co-authored-by: Pete Gonzalez <4673363+octogonz@users.noreply.github.com> --- .../rush/will-seperate-rush-projects_2024-08-12-23-13.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/changes/@microsoft/rush/will-seperate-rush-projects_2024-08-12-23-13.json b/common/changes/@microsoft/rush/will-seperate-rush-projects_2024-08-12-23-13.json index 1cc90407c26..17d7921228a 100644 --- a/common/changes/@microsoft/rush/will-seperate-rush-projects_2024-08-12-23-13.json +++ b/common/changes/@microsoft/rush/will-seperate-rush-projects_2024-08-12-23-13.json @@ -2,7 +2,7 @@ "changes": [ { "packageName": "@microsoft/rush", - "comment": "Adds the option of seperately defining the list of rush projects in a dedicated \"rush-projects.json\" file", + "comment": "Enable Rush projects to be defined in a dedicated file \"rush-projects.json\" instead of in \"rush.json\"", "type": "none" } ], From 004a6615334f5acd64c7c92b5d40163769c472ee Mon Sep 17 00:00:00 2001 From: William Huang Date: Tue, 27 Aug 2024 12:49:46 -0700 Subject: [PATCH 7/7] Add schema validation for rush-projects.json --- libraries/rush-lib/src/api/RushConfiguration.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/rush-lib/src/api/RushConfiguration.ts b/libraries/rush-lib/src/api/RushConfiguration.ts index 14a27c965d4..345c6e7d6e4 100644 --- a/libraries/rush-lib/src/api/RushConfiguration.ts +++ b/libraries/rush-lib/src/api/RushConfiguration.ts @@ -38,6 +38,7 @@ import { type IPnpmOptionsJson, PnpmOptionsConfiguration } from '../logic/pnpm/P import { type INpmOptionsJson, NpmOptionsConfiguration } from '../logic/npm/NpmOptionsConfiguration'; import { type IYarnOptionsJson, YarnOptionsConfiguration } from '../logic/yarn/YarnOptionsConfiguration'; import schemaJson from '../schemas/rush.schema.json'; +import projectSchemaJson from '../schemas/projects.schema.json'; import type * as DependencyAnalyzerModuleType from '../logic/DependencyAnalyzer'; import type { PackageManagerOptionsConfigurationBase } from '../logic/base/BasePackageManagerOptionsConfiguration'; @@ -216,6 +217,7 @@ export interface ITryFindRushJsonLocationOptions { */ export class RushConfiguration { private static _jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); + private static _projectsJsonSchema: JsonSchema = JsonSchema.fromLoadedObject(projectSchemaJson); private readonly _pathTrees: Map>; @@ -888,6 +890,7 @@ export class RushConfiguration { let rushProjects: IRushConfigurationProjectJson[] | undefined; try { const rushProjectsJson: IRushProjectsJson = JsonFile.load(resolvedRushProjectsFilename); + RushConfiguration._projectsJsonSchema.validateObject(rushProjectsJson, resolvedRushProjectsFilename); rushProjects = rushProjectsJson.projects; } catch (e) { if (!FileSystem.isNotExistError(e)) {