Skip to content
Open
78 changes: 74 additions & 4 deletions apps/rush/src/MinimalRushConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@

import * as path from 'node:path';

import { FileSystem, JsonFile } from '@rushstack/node-core-library';
import { FileSystem, JsonFile, PackageJsonLookup } from '@rushstack/node-core-library';
import { RushConfiguration } from '@microsoft/rush-lib';
import { EnvironmentConfiguration } from '@microsoft/rush-lib/lib/api/EnvironmentConfiguration';
import { RushConstants } from '@microsoft/rush-lib/lib/logic/RushConstants';
import { RushCommandLineParser } from '@microsoft/rush-lib/lib/cli/RushCommandLineParser';
import { isSupportedReporterName, type ReporterName } from '@rushstack/rush-reporter';

import { getRushPreviewVersion } from './RushPreviewVersion';

interface IMinimalRushConfigurationJson {
rushMinimumVersion: string;
Expand Down Expand Up @@ -52,16 +56,35 @@ export class MinimalRushConfiguration {
}

public static loadFromDefaultLocation(): MinimalRushConfiguration | undefined {
const showVerbose: boolean = !RushCommandLineParser.shouldRestrictConsoleOutput();
const rushJsonLocation: string | undefined = RushConfiguration.tryFindRushJsonLocation({
showVerbose: !RushCommandLineParser.shouldRestrictConsoleOutput()
showVerbose: false
});
if (rushJsonLocation) {
const minimalRushConfigurationJson: IMinimalRushConfigurationJson | undefined =
_loadConfigurationJson(rushJsonLocation);
Comment on lines 60 to 65

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in ba8c9f1. Legacy presentation ownership is determined even when loading rush.json fails, restoring the exact discovery line and blank line. Regressions cover malformed legacy, explicit/emergency legacy, help, custom/pass-through options, quiet mode, and explicit machine-output suppression. Descendants retain their caller-owned discovery writer and incompatible-engine stdout guard.

Published head: 3ce44c666a51b87ecfc8dbb07c74fb054bcbfc7b. Owning/combined local regression coverage passed; new hosted CI is being verified separately.

const explicitReporter: ReporterName | undefined = _getExplicitReporter(process.argv.slice(2));
const legacyFallbackRequested: boolean =
explicitReporter === 'legacy' ||
process.env.RUSH_REPORTER?.trim().toLowerCase() === 'legacy' ||
_hasHelpControl(process.argv.slice(2));
let configuration: MinimalRushConfiguration | undefined;
let legacyPresentation: boolean = legacyFallbackRequested || explicitReporter === undefined;
if (minimalRushConfigurationJson) {
return new MinimalRushConfiguration(minimalRushConfigurationJson, rushJsonLocation);
configuration = new MinimalRushConfiguration(minimalRushConfigurationJson, rushJsonLocation);
const currentPackageVersion: string = PackageJsonLookup.loadOwnPackageJson(__dirname).version;
const effectiveRushVersion: string = getRushPreviewVersion() ?? configuration.rushVersion;
legacyPresentation =
legacyFallbackRequested ||
effectiveRushVersion !== currentPackageVersion ||
(!configuration.useRushReporter && explicitReporter === undefined);
}
return undefined;
if (showVerbose && legacyPresentation) {
// Preserve discovery even when the full engine must report a configuration load error.
console.log('Found configuration in ' + rushJsonLocation);
console.log('');
}
return configuration;
} else {
return undefined;
}
Expand Down Expand Up @@ -94,6 +117,53 @@ export class MinimalRushConfiguration {
public get useRushReporter(): boolean {
return this.#useRushReporter;
}

/**
* The repository's common temp folder, used for invocation-scoped reporter logs.
*/
public get commonTempFolder(): string {
return (
EnvironmentConfiguration._getRushTempFolderOverride(process.env) ??
path.resolve(this.#commonRushConfigFolder, '..', '..', 'temp')
);
}
}

function _getExplicitReporter(argv: readonly string[]): ReporterName | undefined {
for (let index: number = 0; index < argv.length; index++) {
const argument: string = argv[index];
if (argument === '--') {
break;
}
let value: string | undefined;
if (argument === '--reporter') {
const nextArgument: string | undefined = argv[index + 1];
if (!nextArgument || nextArgument.startsWith('-')) {
continue;
}
value = nextArgument;
index++;
} else if (argument.startsWith('--reporter=')) {
value = argument.slice('--reporter='.length);
}
if (value !== undefined) {
const normalizedValue: string = value.trim().toLowerCase();
return isSupportedReporterName(normalizedValue) ? normalizedValue : undefined;
}
}
return undefined;
}

function _hasHelpControl(argv: readonly string[]): boolean {
for (const argument of argv) {
if (argument === '--') {
return false;
}
if (argument === '--help' || argument === '-h') {
return true;
}
}
return false;
}

function _loadConfigurationJson(rushJsonFilename: string): IMinimalRushConfigurationJson | undefined {
Expand Down
25 changes: 23 additions & 2 deletions apps/rush/src/RushFrontend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { randomUUID } from 'node:crypto';

import type { ILaunchOptions } from '@microsoft/rush-lib';
import { DEFAULT_SIGNAL_FLUSH_TIMEOUT_MS } from '@rushstack/rush-reporter';
import { DEFAULT_SIGNAL_FLUSH_TIMEOUT_MS, REPORTER_PROTOCOL_VERSION } from '@rushstack/rush-reporter';

import {
initializeRushReporterHostAsync,
Expand Down Expand Up @@ -139,10 +139,14 @@ export async function launchRushFrontendAsync(options: IRushFrontendOptions): Pr
processLifecycle = createProcessLifecycle()
} = options;

const engineArgv: string[] = stripReporterValueControls(process.argv.slice(2));
const actionName: string | undefined = engineArgv.find((argument: string) => !argument.startsWith('-'));
const reporterHost: IInitializedRushReporterHost = await initializeReporterHostAsync({
repositoryOptIn: configuration?.useRushReporter,
forceLegacy: rushVersionToLoad !== undefined && rushVersionToLoad !== currentPackageVersion,
selectedRushVersion: rushVersionToLoad
selectedRushVersion: rushVersionToLoad,
commonTempFolder: actionName === 'purge' ? undefined : configuration?.commonTempFolder,
actionName
});
const reporterLifecycle: RushFrontendReporterLifecycle | undefined = reporterHost.selection.enabled
? new RushFrontendReporterLifecycle(reporterHost, processLifecycle)
Expand All @@ -154,10 +158,27 @@ export async function launchRushFrontendAsync(options: IRushFrontendOptions): Pr
new Set(reporterHost.selection.reporterValueFlagsToStrip),
new Set(reporterHost.selection.reporterFlagsToStrip)
);
delete process.env.RUSH_REPORTER;
delete process.env.RUSH_LOG_LEVEL;
}
const reporterCloseAsync: () => Promise<void> = () =>
reporterLifecycle?.closeAsync() ?? reporterHost.closeAsync();
const sessionId: string = createSessionId();
if (reporterHost.selection.enabled && reporterHost.logArtifact?.path) {
reporterHost.sink.emit({
protocolVersion: REPORTER_PROTOCOL_VERSION,
sessionId,
source: { packageName: '@microsoft/rush', packageVersion: currentPackageVersion },
privacy: 'local-sensitive',
type: 'artifactAvailable',
payload: {
role: 'log',
path: reporterHost.logArtifact.path,
format: 'plaintext',
complete: false
}
});
}
const reporterLaunchOptions: IRushFrontendLaunchOptions = {
...launchOptions,
reporter: {
Expand Down
10 changes: 10 additions & 0 deletions apps/rush/src/RushPreviewVersion.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.

import { EnvironmentVariableNames } from '@microsoft/rush-lib/lib/api/EnvironmentConfiguration';

export function getRushPreviewVersion(
env: Record<string, string | undefined> = process.env
): string | undefined {
return env[EnvironmentVariableNames.RUSH_PREVIEW_VERSION] || undefined;
}
Loading
Loading