Skip to content

Commit

Permalink
Merge pull request #2900 from chengcyber/feat-rush-plugins
Browse files Browse the repository at this point in the history
[rush] Add plugin and cloud build cache with rush plugins
  • Loading branch information
octogonz authored Nov 11, 2021
2 parents 53eba52 + 0b0f778 commit 7fc5f92
Show file tree
Hide file tree
Showing 82 changed files with 4,615 additions and 2,591 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* This configuration file manages Rush's plugin feature.
*/
{
"plugins": [
/**
* Each item defines a plugin configuration used by Rush.
*/
/*[BEGIN "DEMO"]*/
{
/**
* The name of the rush plugin package.
*/
"packageName": "@scope/my-rush-plugin",
/**
* The name of the plugin provided by rush plugin package
*/
"pluginName": "my-plugin-name",
/**
* Autoinstaller name used to install the plugin.
*/
"autoinstallerName": "plugins"
}
/*[END "DEMO"]*/
]
}
7 changes: 5 additions & 2 deletions apps/rush-lib/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@
},
"license": "MIT",
"dependencies": {
"@azure/identity": "~1.0.0",
"@azure/storage-blob": "~12.3.0",
"@pnpm/link-bins": "~5.3.7",
"@rushstack/heft-config-file": "workspace:*",
"@rushstack/node-core-library": "workspace:*",
Expand Down Expand Up @@ -51,6 +49,7 @@
"semver": "~7.3.0",
"ssri": "~8.0.0",
"strict-uri-encode": "~2.0.0",
"tapable": "2.2.1",
"tar": "~5.0.5",
"true-case-path": "~2.2.1",
"z-schema": "~3.18.3"
Expand Down Expand Up @@ -80,5 +79,9 @@
"@types/z-schema": "3.16.31",
"jest": "~25.4.0",
"typescript": "~4.4.2"
},
"publishOnlyDependencies": {
"@rushstack/rush-amazon-s3-build-cache-plugin": "workspace:*",
"@rushstack/rush-azure-storage-build-cache-plugin": "workspace:*"
}
}
168 changes: 40 additions & 128 deletions apps/rush-lib/src/api/BuildCacheConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,110 +6,55 @@ import {
JsonFile,
JsonSchema,
FileSystem,
JsonObject,
AlreadyReportedError,
ITerminal,
Import
ITerminal
} from '@rushstack/node-core-library';

import { RushConfiguration } from './RushConfiguration';
import { FileSystemBuildCacheProvider } from '../logic/buildCache/FileSystemBuildCacheProvider';
import { RushConstants } from '../logic/RushConstants';
import { CloudBuildCacheProviderBase } from '../logic/buildCache/CloudBuildCacheProviderBase';
import { ICloudBuildCacheProvider } from '../logic/buildCache/ICloudBuildCacheProvider';
import { RushUserConfiguration } from './RushUserConfiguration';
import { EnvironmentConfiguration } from './EnvironmentConfiguration';
import { CacheEntryId, GetCacheEntryIdFunction } from '../logic/buildCache/CacheEntryId';

const AzureStorageBuildCacheProviderModule: typeof import('../logic/buildCache/AzureStorageBuildCacheProvider') =
Import.lazy('../logic/buildCache/AzureStorageBuildCacheProvider', require);
import type {
AzureEnvironmentNames,
AzureStorageBuildCacheProvider
} from '../logic/buildCache/AzureStorageBuildCacheProvider';
const AmazonS3BuildCacheProviderModule: typeof import('../logic/buildCache/AmazonS3/AmazonS3BuildCacheProvider') =
Import.lazy('../logic/buildCache/AmazonS3/AmazonS3BuildCacheProvider', require);
import type { AmazonS3BuildCacheProvider } from '../logic/buildCache/AmazonS3/AmazonS3BuildCacheProvider';
import type { ICloudBuildCacheProviderFactory, RushSession } from '../pluginFramework/RushSession';

/**
* Describes the file structure for the "common/config/rush/build-cache.json" config file.
*/
interface IBaseBuildCacheJson {
buildCacheEnabled: boolean;
cacheProvider: 'azure-blob-storage' | 'amazon-s3' | 'local-only';
cacheProvider: string;
cacheEntryNamePattern?: string;
}

interface IAzureBlobStorageBuildCacheJson extends IBaseBuildCacheJson {
cacheProvider: 'azure-blob-storage';

azureBlobStorageConfiguration: IAzureStorageConfigurationJson;
}

interface IAmazonS3BuildCacheJson extends IBaseBuildCacheJson {
cacheProvider: 'amazon-s3';

amazonS3Configuration: IAmazonS3ConfigurationJson;
}

interface ILocalBuildCacheJson extends IBaseBuildCacheJson {
cacheProvider: 'local-only';
/**
* @public
*/
export interface ILocalBuildCacheJson extends IBaseBuildCacheJson {
readonly cacheProvider: 'local-only';
}

type IBuildCacheJson = IAzureBlobStorageBuildCacheJson | IAmazonS3BuildCacheJson | ILocalBuildCacheJson;

interface IAzureStorageConfigurationJson {
/**
* The name of the the Azure storage account to use for build cache.
*/
storageAccountName: string;

/**
* The name of the container in the Azure storage account to use for build cache.
*/
storageContainerName: string;

/**
* The Azure environment the storage account exists in. Defaults to AzureCloud.
*/
azureEnvironment?: AzureEnvironmentNames;

/**
* An optional prefix for cache item blob names.
*/
blobPrefix?: string;

/**
* If set to true, allow writing to the cache. Defaults to false.
*/
isCacheWriteAllowed?: boolean;
/**
* @beta
*/
export interface ICloudBuildCacheJson extends IBaseBuildCacheJson {
readonly cacheProvider: string;
[otherConfigKey: string]: JsonObject;
}

interface IAmazonS3ConfigurationJson {
/**
* The Amazon S3 region of the bucket to use for build cache (e.g. "us-east-1").
*/
s3Region: string;

/**
* The name of the bucket in Amazon S3 to use for build cache.
*/
s3Bucket: string;

/**
* An optional prefix ("folder") for cache items.
*/
s3Prefix?: string;

/**
* If set to true, allow writing to the cache. Defaults to false.
*/
isCacheWriteAllowed?: boolean;
}
/**
* @beta
*/
export type IBuildCacheJson = ICloudBuildCacheJson | ILocalBuildCacheJson;

interface IBuildCacheConfigurationOptions {
buildCacheJson: IBuildCacheJson;
getCacheEntryId: GetCacheEntryIdFunction;
rushConfiguration: RushConfiguration;
rushUserConfiguration: RushUserConfiguration;
rushSession: RushSession;
}

/**
Expand All @@ -130,7 +75,7 @@ export class BuildCacheConfiguration {

public readonly getCacheEntryId: GetCacheEntryIdFunction;
public readonly localCacheProvider: FileSystemBuildCacheProvider;
public readonly cloudCacheProvider: CloudBuildCacheProviderBase | undefined;
public readonly cloudCacheProvider: ICloudBuildCacheProvider | undefined;

private constructor(options: IBuildCacheConfigurationOptions) {
this.buildCacheEnabled =
Expand All @@ -143,29 +88,14 @@ export class BuildCacheConfiguration {
});

const { buildCacheJson } = options;
switch (buildCacheJson.cacheProvider) {
case 'local-only': {
// Don't configure a cloud cache provider
break;
}

case 'azure-blob-storage': {
this.cloudCacheProvider = this._createAzureStorageBuildCacheProvider(
buildCacheJson.azureBlobStorageConfiguration
);
break;
}

case 'amazon-s3': {
this.cloudCacheProvider = this._createAmazonS3BuildCacheProvider(
buildCacheJson.amazonS3Configuration
);
break;
}

default: {
throw new Error(`Unexpected cache provider: ${(buildCacheJson as IBuildCacheJson).cacheProvider}`);
// Don't configure a cloud cache provider if local-only
if (buildCacheJson.cacheProvider !== 'local-only') {
const cloudCacheProviderFactory: ICloudBuildCacheProviderFactory | undefined =
options.rushSession.getCloudBuildCacheProviderFactory(buildCacheJson.cacheProvider);
if (!cloudCacheProviderFactory) {
throw new Error(`Unexpected cache provider: ${buildCacheJson.cacheProvider}`);
}
this.cloudCacheProvider = cloudCacheProviderFactory(buildCacheJson as ICloudBuildCacheJson);
}
}

Expand All @@ -175,13 +105,14 @@ export class BuildCacheConfiguration {
*/
public static async tryLoadAsync(
terminal: ITerminal,
rushConfiguration: RushConfiguration
rushConfiguration: RushConfiguration,
rushSession: RushSession
): Promise<BuildCacheConfiguration | undefined> {
const jsonFilePath: string = BuildCacheConfiguration.getBuildCacheConfigFilePath(rushConfiguration);
if (!FileSystem.exists(jsonFilePath)) {
return undefined;
}
return await BuildCacheConfiguration._loadAsync(jsonFilePath, terminal, rushConfiguration);
return await BuildCacheConfiguration._loadAsync(jsonFilePath, terminal, rushConfiguration, rushSession);
}

/**
Expand All @@ -190,7 +121,8 @@ export class BuildCacheConfiguration {
*/
public static async loadAndRequireEnabledAsync(
terminal: ITerminal,
rushConfiguration: RushConfiguration
rushConfiguration: RushConfiguration,
rushSession: RushSession
): Promise<BuildCacheConfiguration> {
const jsonFilePath: string = BuildCacheConfiguration.getBuildCacheConfigFilePath(rushConfiguration);
if (!FileSystem.exists(jsonFilePath)) {
Expand All @@ -204,7 +136,8 @@ export class BuildCacheConfiguration {
const buildCacheConfiguration: BuildCacheConfiguration = await BuildCacheConfiguration._loadAsync(
jsonFilePath,
terminal,
rushConfiguration
rushConfiguration,
rushSession
);

if (!buildCacheConfiguration.buildCacheEnabled) {
Expand All @@ -220,7 +153,8 @@ export class BuildCacheConfiguration {
private static async _loadAsync(
jsonFilePath: string,
terminal: ITerminal,
rushConfiguration: RushConfiguration
rushConfiguration: RushConfiguration,
rushSession: RushSession
): Promise<BuildCacheConfiguration> {
const buildCacheJson: IBuildCacheJson = await JsonFile.loadAndValidateAsync(
jsonFilePath,
Expand All @@ -242,34 +176,12 @@ export class BuildCacheConfiguration {
buildCacheJson,
getCacheEntryId,
rushConfiguration,
rushUserConfiguration
rushUserConfiguration,
rushSession
});
}

public static getBuildCacheConfigFilePath(rushConfiguration: RushConfiguration): string {
return path.resolve(rushConfiguration.commonRushConfigFolder, RushConstants.buildCacheFilename);
}

private _createAzureStorageBuildCacheProvider(
azureStorageConfigurationJson: IAzureStorageConfigurationJson
): AzureStorageBuildCacheProvider {
return new AzureStorageBuildCacheProviderModule.AzureStorageBuildCacheProvider({
storageAccountName: azureStorageConfigurationJson.storageAccountName,
storageContainerName: azureStorageConfigurationJson.storageContainerName,
azureEnvironment: azureStorageConfigurationJson.azureEnvironment,
blobPrefix: azureStorageConfigurationJson.blobPrefix,
isCacheWriteAllowed: !!azureStorageConfigurationJson.isCacheWriteAllowed
});
}

private _createAmazonS3BuildCacheProvider(
amazonS3ConfigurationJson: IAmazonS3ConfigurationJson
): AmazonS3BuildCacheProvider {
return new AmazonS3BuildCacheProviderModule.AmazonS3BuildCacheProvider({
s3Region: amazonS3ConfigurationJson.s3Region,
s3Bucket: amazonS3ConfigurationJson.s3Bucket,
s3Prefix: amazonS3ConfigurationJson.s3Prefix,
isCacheWriteAllowed: !!amazonS3ConfigurationJson.isCacheWriteAllowed
});
}
}
30 changes: 30 additions & 0 deletions apps/rush-lib/src/api/CommandLineConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ import {

const EXPECTED_PHASE_NAME_PREFIX: '_phase:' = '_phase:';

export interface IShellCommandTokenContext {
packageFolder: string;
}

/**
* Custom Commands and Options for the Rush Command Line
*/
Expand All @@ -33,6 +37,16 @@ export class CommandLineConfiguration {
RushConstants.rebuildCommandName
]);

/**
* These path will be prepended to the PATH environment variable
*/
private _additionalPathFolders: string[] = [];

/**
* shellCommand from plugin custom command line configuration needs to be expanded with tokens
*/
private _shellCommandTokenContext: IShellCommandTokenContext | undefined;

public static readonly defaultBuildCommandJson: CommandJson = {
commandKind: RushConstants.bulkCommandKind,
name: RushConstants.buildCommandName,
Expand Down Expand Up @@ -345,4 +359,20 @@ export class CommandLineConfiguration {

return new CommandLineConfiguration(commandLineJson);
}

public get additionalPathFolders(): Readonly<string[]> {
return this._additionalPathFolders;
}

public prependAdditionalPathFolder(pathFolder: string): void {
this._additionalPathFolders.unshift(pathFolder);
}

public get shellCommandTokenContext(): Readonly<IShellCommandTokenContext> | undefined {
return this._shellCommandTokenContext;
}

public set shellCommandTokenContext(tokenContext: IShellCommandTokenContext | undefined) {
this._shellCommandTokenContext = tokenContext;
}
}
5 changes: 3 additions & 2 deletions apps/rush-lib/src/api/EnvironmentConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export interface IEnvironmentConfigurationInitializeOptions {
* Names of environment variables used by Rush.
* @public
*/
export const enum EnvironmentVariableNames {
export enum EnvironmentVariableNames {
/**
* This variable overrides the temporary folder used by Rush.
* The default value is "common/temp" under the repository root.
Expand Down Expand Up @@ -154,6 +154,7 @@ export const enum EnvironmentVariableNames {
/**
* Provides Rush-specific environment variable data. All Rush environment variables must start with "RUSH_". This class
* is designed to be used by RushConfiguration.
* @public
*
* @remarks
* Initialize will throw if any unknown parameters are present.
Expand Down Expand Up @@ -474,7 +475,7 @@ export class EnvironmentConfiguration {
* this function returns undefined.
*
* @example
* If the following path exists on disk: C:\Folder1\folder2\
* If the following path exists on disk: `C:\Folder1\folder2\`
* _normalizeFirstExistingFolderPath('c:\\folder1\\folder2\\temp\\subfolder')
* returns 'C:\\Folder1\\folder2\\temp\\subfolder'
*/
Expand Down
Loading

0 comments on commit 7fc5f92

Please sign in to comment.