From ec0071ccd89b45f16e212454c58721003a65ed96 Mon Sep 17 00:00:00 2001 From: Xi Huang <3360621+yumikohey@users.noreply.github.com> Date: Thu, 24 Sep 2026 18:30:48 -0700 Subject: [PATCH] [rush] Add an optional "description" field for rush.json project entries Allow project entries in rush.json to specify an optional, human-readable "description" string, and expose it as the new (beta) RushConfigurationProject.description property. Rush does not interpret the value; it is available to people and tools reading the project inventory. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- ...-project-description_2026-09-25-01-31-10.json | 11 +++++++++++ common/reviews/api/rush-lib.api.md | 2 ++ libraries/rush-lib/assets/rush-init/rush.json | 7 +++++++ .../rush-lib/src/api/RushConfigurationProject.ts | 16 +++++++++++++++- .../src/api/test/RushConfiguration.test.ts | 2 ++ .../rush-lib/src/api/test/repo/rush-npm.json | 1 + libraries/rush-lib/src/schemas/rush.schema.json | 4 ++++ 7 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 common/changes/@microsoft/rush/rush-json-project-description_2026-09-25-01-31-10.json diff --git a/common/changes/@microsoft/rush/rush-json-project-description_2026-09-25-01-31-10.json b/common/changes/@microsoft/rush/rush-json-project-description_2026-09-25-01-31-10.json new file mode 100644 index 00000000000..fa27298a6ac --- /dev/null +++ b/common/changes/@microsoft/rush/rush-json-project-description_2026-09-25-01-31-10.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "Add an optional \"description\" field for project entries in rush.json, exposed as the new `RushConfigurationProject.description` API.", + "type": "none", + "packageName": "@microsoft/rush" + } + ], + "packageName": "@microsoft/rush", + "email": "3360621+yumikohey@users.noreply.github.com" +} \ 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 1b712f18dda..cf12eb383d8 100644 --- a/common/reviews/api/rush-lib.api.md +++ b/common/reviews/api/rush-lib.api.md @@ -1799,6 +1799,8 @@ export class RushConfigurationProject { get cyclicDependencyProjects(): Set; readonly decoupledLocalDependencies: Set; get dependencyProjects(): ReadonlySet; + // @beta + readonly description: string | undefined; // @deprecated get downstreamDependencyProjects(): string[]; // @beta diff --git a/libraries/rush-lib/assets/rush-init/rush.json b/libraries/rush-lib/assets/rush-init/rush.json index 33fec400088..22f59883256 100644 --- a/libraries/rush-lib/assets/rush-init/rush.json +++ b/libraries/rush-lib/assets/rush-init/rush.json @@ -389,6 +389,13 @@ */ "projectFolder": "apps/my-app", + /** + * An optional human-readable description of the project, for example a one-line + * summary of its purpose. Rush does not interpret this value, but it is available + * to tools and plugins via the Rush API. + */ + /*[LINE "HYPOTHETICAL"]*/ "description": "The main web application for the example repo", + /** * This field is only used if "subspacesEnabled" is true in subspaces.json. * It specifies the subspace that this project belongs to. If omitted, then the diff --git a/libraries/rush-lib/src/api/RushConfigurationProject.ts b/libraries/rush-lib/src/api/RushConfigurationProject.ts index 505ce8cdcc3..caa49ba2968 100644 --- a/libraries/rush-lib/src/api/RushConfigurationProject.ts +++ b/libraries/rush-lib/src/api/RushConfigurationProject.ts @@ -22,6 +22,7 @@ import type { Subspace } from './Subspace'; export interface IRushConfigurationProjectJson { packageName: string; projectFolder: string; + description?: string; reviewCategory?: string; decoupledLocalDependencies: string[]; cyclicDependencyProjects?: string[]; @@ -95,6 +96,18 @@ export class RushConfigurationProject { */ public readonly projectRelativeFolder: string; + /** + * An optional human-readable description of the project, as specified by the `"description"` + * field in `rush.json`, or `undefined` if no description was provided. + * + * @remarks + * Rush does not interpret this value; it is intended to help people and tools understand + * the purpose of the project. + * + * @beta + */ + public readonly description: string | undefined; + /** * The project-specific Rush configuration folder. * @@ -211,10 +224,11 @@ export class RushConfigurationProject { /** @internal */ public constructor(options: IRushConfigurationProjectOptions) { const { projectJson, rushConfiguration, tempProjectName, allowedProjectTags } = options; - const { packageName, projectFolder: projectRelativeFolder } = projectJson; + const { packageName, projectFolder: projectRelativeFolder, description } = projectJson; this.rushConfiguration = rushConfiguration; this.packageName = packageName; this.projectRelativeFolder = projectRelativeFolder; + this.description = description; validateRelativePathField(projectRelativeFolder, 'projectFolder', rushConfiguration.rushJsonFile); diff --git a/libraries/rush-lib/src/api/test/RushConfiguration.test.ts b/libraries/rush-lib/src/api/test/RushConfiguration.test.ts index 4c99d470dea..c7590482fa6 100644 --- a/libraries/rush-lib/src/api/test/RushConfiguration.test.ts +++ b/libraries/rush-lib/src/api/test/RushConfiguration.test.ts @@ -104,10 +104,12 @@ describe(RushConfiguration.name, () => { expect(project1.tempProjectName).toEqual('@rush-temp/project1'); expect(project1.unscopedTempProjectName).toEqual('project1'); expect(project1.skipRushCheck).toEqual(false); + expect(project1.description).toEqual('An example project with a description'); // Validate project2 settings const project2: RushConfigurationProject = rushConfiguration.getProjectByName('project2')!; expect(project2.skipRushCheck).toEqual(true); + expect(project2.description).toBeUndefined(); }); it('can load repo/rush-pnpm.json', () => { diff --git a/libraries/rush-lib/src/api/test/repo/rush-npm.json b/libraries/rush-lib/src/api/test/repo/rush-npm.json index 5f448332dcd..b2aac7fc9a7 100644 --- a/libraries/rush-lib/src/api/test/repo/rush-npm.json +++ b/libraries/rush-lib/src/api/test/repo/rush-npm.json @@ -27,6 +27,7 @@ { "packageName": "project1", "projectFolder": "project1", + "description": "An example project with a description", "reviewCategory": "third-party", "tags": ["frontend", "ui"], "versionPolicyName": "testPolicy" diff --git a/libraries/rush-lib/src/schemas/rush.schema.json b/libraries/rush-lib/src/schemas/rush.schema.json index 801ccdafc3b..8da94b74f0b 100644 --- a/libraries/rush-lib/src/schemas/rush.schema.json +++ b/libraries/rush-lib/src/schemas/rush.schema.json @@ -356,6 +356,10 @@ "description": "The path to the project folder relative to the Rush config file.", "type": "string" }, + "description": { + "description": "An optional human-readable description of the project, for example a one-line summary of its purpose. Rush does not interpret this value, but it is available to tools and plugins via the Rush API.", + "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"