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] Adds support for a separate rush-projects.json configuration file #4881

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
@@ -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",
william2958 marked this conversation as resolved.
Show resolved Hide resolved
"type": "none"
}
],
"packageName": "@microsoft/rush"
}
5 changes: 5 additions & 0 deletions common/reviews/api/rush-lib.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 | undefined;
william2958 marked this conversation as resolved.
Show resolved Hide resolved
readonly shrinkwrapFilename: string;
get shrinkwrapFilePhrase(): string;
// @beta
Expand Down Expand Up @@ -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';
Expand Down
40 changes: 39 additions & 1 deletion libraries/rush-lib/src/api/RushConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,14 @@ export interface IRushConfigurationJson {
variants?: unknown;
}

/**
* This represents the JSON data structure for the "projects.json" configuration file.
william2958 marked this conversation as resolved.
Show resolved Hide resolved
* See projects.schema.json for documentation
*/
export interface IRushProjectsJson {
projects: IRushConfigurationProjectJson[];
}

/**
* The filter parameters to search from all projects
*/
Expand Down Expand Up @@ -247,6 +255,13 @@ export class RushConfiguration {
*/
public readonly rushConfigurationJson: IRushConfigurationJson;

/**
* Gets the JSON data structure for the "projects.json" configuration file.
william2958 marked this conversation as resolved.
Show resolved Hide resolved
*
* @internal
*/
public readonly rushProjectsJson: IRushProjectsJson | undefined;

/**
* The absolute path to the "rush.json" configuration file that was loaded to construct this object.
*/
Expand Down Expand Up @@ -867,9 +882,32 @@ 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}`
);
william2958 marked this conversation as resolved.
Show resolved Hide resolved
let rushProjects: IRushConfigurationProjectJson[] | undefined;
if (FileSystem.exists(resolvedRushProjectsFilename)) {
const rushProjectsJson: IRushProjectsJson = JsonFile.load(resolvedRushProjectsFilename);
william2958 marked this conversation as resolved.
Show resolved Hide resolved
rushProjects = rushProjectsJson.projects;
}
william2958 marked this conversation as resolved.
Show resolved Hide resolved
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;
}
if (!rushProjects) {
william2958 marked this conversation as resolved.
Show resolved Hide resolved
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)
);
Expand Down
5 changes: 5 additions & 0 deletions libraries/rush-lib/src/logic/RushConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
148 changes: 148 additions & 0 deletions libraries/rush-lib/src/schemas/projects.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the filename is rush-projects.json then the schema filename must be rush-projects.schema.json

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking the same thing, but the rush-project.schema.json file already exists and I feel like it might be confusing to just have rush-project.schema.json and rush-projects.schema.json files

"$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": {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of duplicating this in a second schema, update this and the rush.json schema to allow anything in the projects property and extract this to its own schema and validate the projects object separately.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to use a "rush-project-config.schema.json"

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This schema does not seem to be actually importing or using rush-project-config.schema.json.

@iclanton @D4N14L do we actually have an example of a schema referencing another schema in our code base? In the past I think anything.schema.json was used in this way, but today nothing seems to import it.

My concern is whether VS Code will fetch the URL correctly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what it looks like, when you do a ref to another json schema, doesn't that schema need to be uploaded to a server first? So I guess I would need to create the rush-project-config.schema.json, upload it, then add the reference in rush.schema.json?

"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"]
}
2 changes: 1 addition & 1 deletion libraries/rush-lib/src/schemas/rush.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -354,5 +354,5 @@
}
},
"additionalProperties": false,
"required": ["rushVersion", "projects"]
"required": ["rushVersion"]
}
Loading