diff --git a/common/changes/@microsoft/rush/chore-support-users-to-provide-their-own-assets-file-for-init-subspace_2025-02-25-07-23.json b/common/changes/@microsoft/rush/chore-support-users-to-provide-their-own-assets-file-for-init-subspace_2025-02-25-07-23.json new file mode 100644 index 00000000000..18ec6c85231 --- /dev/null +++ b/common/changes/@microsoft/rush/chore-support-users-to-provide-their-own-assets-file-for-init-subspace_2025-02-25-07-23.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@microsoft/rush", + "comment": "Allow a monorepo to provide custom config file templates for the `rush init-subspace` command", + "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 132c5a307bc..244080e4b0d 100644 --- a/common/reviews/api/rush-lib.api.md +++ b/common/reviews/api/rush-lib.api.md @@ -1544,6 +1544,7 @@ export class SubspacesConfiguration { readonly preventSelectingAllSubspaces: boolean; static requireValidSubspaceName(subspaceName: string, splitWorkspaceCompatibility?: boolean): void; readonly splitWorkspaceCompatibility: boolean; + readonly subspaceInitAssetsFolder?: string; readonly subspaceJsonFilePath: string; readonly subspaceNames: ReadonlySet; // (undocumented) diff --git a/libraries/rush-lib/assets/rush-init/common/config/rush/subspaces.json b/libraries/rush-lib/assets/rush-init/common/config/rush/subspaces.json index d3c3ae8c516..0f7e4816b10 100644 --- a/libraries/rush-lib/assets/rush-init/common/config/rush/subspaces.json +++ b/libraries/rush-lib/assets/rush-init/common/config/rush/subspaces.json @@ -11,6 +11,11 @@ */ "subspacesEnabled": false, + /** + * the starting assets folder relative to rush.json location you want to use when init a subspace + */ + // "subspaceInitAssetsFolder": "", + /** * (DEPRECATED) This is a temporary workaround for migrating from an earlier prototype * of this feature: https://github.com/microsoft/rushstack/pull/3481 diff --git a/libraries/rush-lib/src/api/SubspacesConfiguration.ts b/libraries/rush-lib/src/api/SubspacesConfiguration.ts index 91dbe477be3..a116f642116 100644 --- a/libraries/rush-lib/src/api/SubspacesConfiguration.ts +++ b/libraries/rush-lib/src/api/SubspacesConfiguration.ts @@ -25,6 +25,7 @@ export interface ISubspacesConfigurationJson { splitWorkspaceCompatibility?: boolean; preventSelectingAllSubspaces?: boolean; subspaceNames: string[]; + subspaceInitAssetsFolder?: string; } /** @@ -60,11 +61,17 @@ export class SubspacesConfiguration { */ public readonly subspaceNames: ReadonlySet; + /** + * rush-init Subspace assets location used during `rush init-subspace` + */ + public readonly subspaceInitAssetsFolder?: string; + private constructor(configuration: Readonly, subspaceJsonFilePath: string) { this.subspaceJsonFilePath = subspaceJsonFilePath; this.subspacesEnabled = configuration.subspacesEnabled; this.splitWorkspaceCompatibility = !!configuration.splitWorkspaceCompatibility; this.preventSelectingAllSubspaces = !!configuration.preventSelectingAllSubspaces; + this.subspaceInitAssetsFolder = configuration.subspaceInitAssetsFolder; const subspaceNames: Set = new Set(); for (const subspaceName of configuration.subspaceNames) { SubspacesConfiguration.requireValidSubspaceName(subspaceName, this.splitWorkspaceCompatibility); diff --git a/libraries/rush-lib/src/cli/actions/InitSubspaceAction.ts b/libraries/rush-lib/src/cli/actions/InitSubspaceAction.ts index 445e2f91860..4ec0780fbaa 100644 --- a/libraries/rush-lib/src/cli/actions/InitSubspaceAction.ts +++ b/libraries/rush-lib/src/cli/actions/InitSubspaceAction.ts @@ -9,6 +9,7 @@ import { type ISubspacesConfigurationJson, SubspacesConfiguration } from '../../ import { Async, FileSystem, JsonFile } from '@rushstack/node-core-library'; import { ConsoleTerminalProvider, Terminal } from '@rushstack/terminal'; import { copyTemplateFileAsync } from '../../utilities/templateUtilities'; +import * as path from 'path'; export class InitSubspaceAction extends BaseRushAction { private readonly _subspaceNameParameter: IRequiredCommandLineStringParameter; @@ -58,7 +59,10 @@ export class InitSubspaceAction extends BaseRushAction { } const subspaceConfigPath: string = `${this.rushConfiguration.commonFolder}/config/subspaces/${newSubspaceName}`; - const assetsSubfolder: string = `${assetsFolderPath}/rush-init`; + const defaultAssetsSubfolder: string = `${assetsFolderPath}/rush-init`; + const userDefinedAssetsFolder: string | undefined = subspacesConfiguration.subspaceInitAssetsFolder + ? `${this.rushConfiguration.rushJsonFolder}/${subspacesConfiguration.subspaceInitAssetsFolder}` + : undefined; const templateFilePaths: string[] = [ '[dot]npmrc', '.pnpmfile.cjs', @@ -70,9 +74,14 @@ export class InitSubspaceAction extends BaseRushAction { await Async.forEachAsync( templateFilePaths, async (templateFilePath) => { - const sourcePath: string = `${assetsSubfolder}/common/config/rush/${templateFilePath}`; + const defaultAssetSourcePath: string = `${defaultAssetsSubfolder}/common/config/rush/${templateFilePath}`; const destinationPath: string = `${subspaceConfigPath}/${templateFilePath.replace('[dot]', '.')}`; - await copyTemplateFileAsync(sourcePath, destinationPath, true); + await copyTemplateFileAsync(defaultAssetSourcePath, destinationPath, true); + if (userDefinedAssetsFolder) { + // if user provided their own assets file for subspace initiation + // we just copy and overwrite the default files + await copyTemplateFileAsync(userDefinedAssetsFolder, destinationPath, true); + } }, { concurrency: 10 } ); diff --git a/libraries/rush-lib/src/schemas/subspaces.schema.json b/libraries/rush-lib/src/schemas/subspaces.schema.json index 5322a806a7b..e5cb6031c3e 100644 --- a/libraries/rush-lib/src/schemas/subspaces.schema.json +++ b/libraries/rush-lib/src/schemas/subspaces.schema.json @@ -27,6 +27,10 @@ "items": { "type": "string" } + }, + "subspaceInitAssetsFolder": { + "description": "Where assets located for init a new subspace", + "type": "string" } } }