Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "@microsoft/rush",
"comment": "Add repository configuration for opting into and configuring the experimental Rush reporter.",
"type": "patch"
}
],
"packageName": "@microsoft/rush",
"email": "TheLarkInn@users.noreply.github.com"
}
8 changes: 8 additions & 0 deletions common/reviews/api/rush-lib.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,7 @@ export interface IExperimentsJson {
usePnpmLockfileOnlyThenFrozenLockfileForRushUpdate?: boolean;
usePnpmPreferFrozenLockfileForRushUpdate?: boolean;
usePnpmSyncForInjectedDependencies?: boolean;
useRushReporter?: boolean;
}

// @beta
Expand Down Expand Up @@ -971,6 +972,11 @@ export interface _IRushProjectJson {
operationSettings?: IOperationSettings[];
}

// @beta
export interface IRushReportingConfiguration {
readonly agentEnvironmentVariables: readonly string[];
}

// @beta (undocumented)
export interface IRushSessionOptions {
// (undocumented)
Expand Down Expand Up @@ -1471,6 +1477,8 @@ export class RushConfiguration {
get projectsByName(): ReadonlyMap<string, RushConfigurationProject>;
// @beta
get projectsByTag(): ReadonlyMap<string, ReadonlySet<RushConfigurationProject>>;
// @beta
readonly reportingConfiguration: IRushReportingConfiguration;
readonly repositoryDefaultBranch: string;
get repositoryDefaultFullyQualifiedRemoteBranch(): string;
readonly repositoryDefaultRemote: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,5 +141,11 @@
* must implement the optional file-based methods for this to take effect; otherwise it falls back to the
* buffer-based approach.
*/
/*[LINE "HYPOTHETICAL"]*/ "useDirectFileTransfersForBuildCache": true
/*[LINE "HYPOTHETICAL"]*/ "useDirectFileTransfersForBuildCache": true,

/**
* If true, Rush may use the experimental Rush reporter system. If omitted or false,
* Rush preserves the legacy reporting behavior.
*/
/*[LINE "HYPOTHETICAL"]*/ "useRushReporter": true
}
13 changes: 13 additions & 0 deletions libraries/rush-lib/assets/rush-init/rush.json
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,19 @@
*/
/*[LINE "HYPOTHETICAL"]*/ "telemetryEnabled": false,

/**
* Configures repository settings used by the experimental Rush reporter system.
*/
/*[BEGIN "HYPOTHETICAL"]*/
"reporting": {
/**
* Additional environment variable names that identify an agent environment.
* The built-in COPILOT_CLI variable does not need to be listed here.
*/
"agentEnvironmentVariables": ["MY_AGENT_CLI", "ANOTHER_AGENT"]
},
/*[END "HYPOTHETICAL"]*/

/**
* Allows creation of hotfix changes. This feature is experimental so it is disabled by default.
* If this is set, 'rush change' only allows a 'hotfix' change type to be specified. This change type
Expand Down
6 changes: 6 additions & 0 deletions libraries/rush-lib/src/api/ExperimentsConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,12 @@ export interface IExperimentsJson {
* effect; otherwise it falls back to the buffer-based approach.
*/
useDirectFileTransfersForBuildCache?: boolean;

/**
* If true, Rush may use the experimental Rush reporter system. If omitted or false,
* Rush preserves the legacy reporting behavior.
*/
useRushReporter?: boolean;
}

const _EXPERIMENTS_JSON_SCHEMA: JsonSchema = JsonSchema.fromLoadedObject(schemaJson);
Expand Down
25 changes: 25 additions & 0 deletions libraries/rush-lib/src/api/RushConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,21 @@ export interface IRushVariantOptionsJson {
description: string;
}

interface IRushReportingConfigurationJson {
agentEnvironmentVariables?: string[];
}

/**
* Repository settings used by the Rush reporter system.
* @beta
*/
export interface IRushReportingConfiguration {
/**
* Additional environment variable names that identify an agent environment.
*/
readonly agentEnvironmentVariables: readonly string[];
}

/**
* This represents the JSON data structure for the "rush.json" configuration file.
* See rush.schema.json for documentation.
Expand Down Expand Up @@ -184,6 +199,7 @@ export interface IRushConfigurationJson {
yarnOptions?: IYarnOptionsJson;
ensureConsistentVersions?: boolean;
variants?: IRushVariantOptionsJson[];
reporting?: IRushReportingConfigurationJson;
}

/**
Expand Down Expand Up @@ -523,6 +539,12 @@ export class RushConfiguration {
*/
public readonly telemetryEnabled: boolean;

/**
* Repository settings used by the Rush reporter system.
* @beta
*/
public readonly reportingConfiguration: IRushReportingConfiguration;

/**
* {@inheritDoc NpmOptionsConfiguration}
*/
Expand Down Expand Up @@ -853,6 +875,9 @@ export class RushConfiguration {
}

this.telemetryEnabled = !!rushConfigurationJson.telemetryEnabled;
this.reportingConfiguration = {
agentEnvironmentVariables: rushConfigurationJson.reporting?.agentEnvironmentVariables || []
};
this.eventHooks = new EventHooks(rushConfigurationJson.eventHooks || {});

this.versionPolicyConfigurationFilePath = path.join(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.

import * as path from 'node:path';

import { FileSystem, JsonFile } from '@rushstack/node-core-library';

import { ExperimentsConfiguration } from '../ExperimentsConfiguration';

const TEMP_FOLDER: string = path.join(__dirname, 'temp', ExperimentsConfiguration.name);
const EXPERIMENTS_JSON_PATH: string = path.join(TEMP_FOLDER, 'experiments.json');

describe(ExperimentsConfiguration.name, () => {
beforeEach(() => {
FileSystem.ensureEmptyFolder(TEMP_FOLDER);
});

afterEach(() => {
FileSystem.ensureEmptyFolder(TEMP_FOLDER);
});

it('preserves legacy reporting behavior when the experiment file is absent', () => {
const experimentsConfiguration: ExperimentsConfiguration = new ExperimentsConfiguration(
EXPERIMENTS_JSON_PATH
);

expect(experimentsConfiguration.configuration.useRushReporter).toBeUndefined();
});

it('loads the Rush reporter opt-in', () => {
JsonFile.save({ useRushReporter: true }, EXPERIMENTS_JSON_PATH);

const experimentsConfiguration: ExperimentsConfiguration = new ExperimentsConfiguration(
EXPERIMENTS_JSON_PATH
);

expect(experimentsConfiguration.configuration.useRushReporter).toBe(true);
});

it('keeps an explicit false value disabled', () => {
JsonFile.save({ useRushReporter: false }, EXPERIMENTS_JSON_PATH);

const experimentsConfiguration: ExperimentsConfiguration = new ExperimentsConfiguration(
EXPERIMENTS_JSON_PATH
);

expect(experimentsConfiguration.configuration.useRushReporter).toBe(false);
});

it('rejects a non-boolean Rush reporter opt-in', () => {
JsonFile.save({ useRushReporter: 'yes' }, EXPERIMENTS_JSON_PATH);

expect(() => new ExperimentsConfiguration(EXPERIMENTS_JSON_PATH)).toThrow(/useRushReporter/);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.

import * as path from 'node:path';

import { FileSystem, JsonFile } from '@rushstack/node-core-library';

import { Rush } from '../Rush';
import { RushConfiguration } from '../RushConfiguration';

const TEMP_FOLDER: string = path.join(__dirname, 'temp', 'RushConfigurationReporting');
const RUSH_JSON_PATH: string = path.join(TEMP_FOLDER, 'rush.json');

function writeRushJson(reporting?: unknown): void {
JsonFile.save(
{
rushVersion: Rush.version,
pnpmVersion: '10.0.0',
projects: [],
...(reporting === undefined ? {} : { reporting })
},
RUSH_JSON_PATH
);
}

describe('RushConfiguration reporting configuration', () => {
beforeEach(() => {
FileSystem.ensureEmptyFolder(TEMP_FOLDER);
});

afterEach(() => {
FileSystem.ensureEmptyFolder(TEMP_FOLDER);
});

it('defaults agent environment variables to an empty array', () => {
writeRushJson();

const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(RUSH_JSON_PATH);

expect(rushConfiguration.reportingConfiguration.agentEnvironmentVariables).toEqual([]);
});

it('loads configured agent environment variables', () => {
writeRushJson({
agentEnvironmentVariables: ['MY_AGENT_CLI', 'ANOTHER_AGENT']
});

const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(RUSH_JSON_PATH);

expect(rushConfiguration.reportingConfiguration.agentEnvironmentVariables).toEqual([
'MY_AGENT_CLI',
'ANOTHER_AGENT'
]);
});

it('rejects invalid agent environment variables', () => {
writeRushJson({
agentEnvironmentVariables: ['MY_AGENT_CLI', 123]
});

expect(() => RushConfiguration.loadFromConfigurationFile(RUSH_JSON_PATH)).toThrow(
/agentEnvironmentVariables/
);
});

it('rejects unsupported reporting settings', () => {
writeRushJson({
agentEnvironmentVariables: [],
defaultReporter: 'ai'
});

expect(() => RushConfiguration.loadFromConfigurationFile(RUSH_JSON_PATH)).toThrow(/defaultReporter/);
});
});
6 changes: 5 additions & 1 deletion libraries/rush-lib/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ export {

export { ApprovedPackagesPolicy } from './api/ApprovedPackagesPolicy';

export { RushConfiguration, type ITryFindRushJsonLocationOptions } from './api/RushConfiguration';
export {
RushConfiguration,
type IRushReportingConfiguration,
type ITryFindRushJsonLocationOptions
} from './api/RushConfiguration';

export { Subspace } from './api/Subspace';
export { SubspacesConfiguration } from './api/SubspacesConfiguration';
Expand Down
4 changes: 4 additions & 0 deletions libraries/rush-lib/src/schemas/experiments.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@
"useDirectFileTransfersForBuildCache": {
"description": "If true, the build cache will use file-based APIs to transfer cache entries to and from cloud storage. This avoids loading the entire cache entry into memory, which can prevent out-of-memory errors for large build outputs and allow cache entries to exceed the limit of a single Buffer. The cloud cache provider plugin must implement the optional file-based methods for this to take effect; otherwise it falls back to the buffer-based approach.",
"type": "boolean"
},
"useRushReporter": {
"description": "If true, Rush may use the experimental Rush reporter system. If omitted or false, Rush preserves the legacy reporting behavior.",
"type": "boolean"
}
},
"additionalProperties": false
Expand Down
16 changes: 16 additions & 0 deletions libraries/rush-lib/src/schemas/rush.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,22 @@
"description": "Indicates whether telemetry data should be collected and stored in the Rush temp folder during Rush runs.",
"type": "boolean"
},
"reporting": {
"description": "Configures repository settings used by the Rush reporter system.",
"type": "object",
"properties": {
"agentEnvironmentVariables": {
"description": "Additional environment variable names that identify an agent environment.",
"type": "array",
"items": {
"type": "string",
"minLength": 1
},
"uniqueItems": true
}
},
"additionalProperties": false
},
"allowedProjectTags": {
"description": "This is an optional, but recommended, list of allowed tags that can be applied to Rush projects using the \"tags\" setting in this file. This list is useful for preventing mistakes such as misspelling, and it also provides a centralized place to document your tags. If \"allowedProjectTags\" list is not specified, then any valid tag is allowed. A 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",
Expand Down