feat(core): show progress on ci if graph construction takes longer than expected (#29392)
Progress spinners currently only show up when the terminal is a tty. This updates it to show static text on CI, but at a longer duration
This commit is contained in:
parent
ba1641d7fd
commit
3c3d2e5f82
@ -77,10 +77,7 @@ import {
|
|||||||
FLUSH_SYNC_GENERATOR_CHANGES_TO_DISK,
|
FLUSH_SYNC_GENERATOR_CHANGES_TO_DISK,
|
||||||
type HandleFlushSyncGeneratorChangesToDiskMessage,
|
type HandleFlushSyncGeneratorChangesToDiskMessage,
|
||||||
} from '../message-types/flush-sync-generator-changes-to-disk';
|
} from '../message-types/flush-sync-generator-changes-to-disk';
|
||||||
import {
|
import { DelayedSpinner } from '../../utils/delayed-spinner';
|
||||||
DelayedSpinner,
|
|
||||||
SHOULD_SHOW_SPINNERS,
|
|
||||||
} from '../../utils/delayed-spinner';
|
|
||||||
|
|
||||||
const DAEMON_ENV_SETTINGS = {
|
const DAEMON_ENV_SETTINGS = {
|
||||||
NX_PROJECT_GLOB_CACHE: 'false',
|
NX_PROJECT_GLOB_CACHE: 'false',
|
||||||
@ -199,16 +196,13 @@ export class DaemonClient {
|
|||||||
sourceMaps: ConfigurationSourceMaps;
|
sourceMaps: ConfigurationSourceMaps;
|
||||||
}> {
|
}> {
|
||||||
let spinner: DelayedSpinner;
|
let spinner: DelayedSpinner;
|
||||||
if (SHOULD_SHOW_SPINNERS) {
|
|
||||||
// If the graph takes a while to load, we want to show a spinner.
|
// If the graph takes a while to load, we want to show a spinner.
|
||||||
spinner = new DelayedSpinner(
|
spinner = new DelayedSpinner(
|
||||||
'Calculating the project graph on the Nx Daemon',
|
'Calculating the project graph on the Nx Daemon'
|
||||||
500
|
|
||||||
).scheduleMessageUpdate(
|
).scheduleMessageUpdate(
|
||||||
'Calculating the project graph on the Nx Daemon is taking longer than expected. Re-run with NX_DAEMON=false to see more details.',
|
'Calculating the project graph on the Nx Daemon is taking longer than expected. Re-run with NX_DAEMON=false to see more details.',
|
||||||
30_000
|
{ ciDelay: 60_000, delay: 30_000 }
|
||||||
);
|
);
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
const response = await this.sendToDaemonViaQueue({
|
const response = await this.sendToDaemonViaQueue({
|
||||||
type: 'REQUEST_PROJECT_GRAPH',
|
type: 'REQUEST_PROJECT_GRAPH',
|
||||||
|
|||||||
@ -44,7 +44,7 @@ import {
|
|||||||
ConfigurationSourceMaps,
|
ConfigurationSourceMaps,
|
||||||
mergeMetadata,
|
mergeMetadata,
|
||||||
} from './utils/project-configuration-utils';
|
} from './utils/project-configuration-utils';
|
||||||
import { DelayedSpinner, SHOULD_SHOW_SPINNERS } from '../utils/delayed-spinner';
|
import { DelayedSpinner } from '../utils/delayed-spinner';
|
||||||
|
|
||||||
let storedFileMap: FileMap | null = null;
|
let storedFileMap: FileMap | null = null;
|
||||||
let storedAllWorkspaceFiles: FileData[] | null = null;
|
let storedAllWorkspaceFiles: FileData[] | null = null;
|
||||||
@ -323,24 +323,28 @@ async function updateProjectGraphWithPlugins(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (inProgressPlugins.size === 1) {
|
if (inProgressPlugins.size === 1) {
|
||||||
return `Creating project graph dependencies with ${
|
spinner.setMessage(
|
||||||
|
`Creating project graph dependencies with ${
|
||||||
inProgressPlugins.keys()[0]
|
inProgressPlugins.keys()[0]
|
||||||
}`;
|
}`
|
||||||
|
);
|
||||||
} else if (process.env.NX_VERBOSE_LOGGING === 'true') {
|
} else if (process.env.NX_VERBOSE_LOGGING === 'true') {
|
||||||
return [
|
spinner.setMessage(
|
||||||
|
[
|
||||||
`Creating project graph dependencies with ${inProgressPlugins.size} plugins`,
|
`Creating project graph dependencies with ${inProgressPlugins.size} plugins`,
|
||||||
...Array.from(inProgressPlugins).map((p) => ` - ${p}`),
|
...Array.from(inProgressPlugins).map((p) => ` - ${p}`),
|
||||||
].join('\n');
|
].join('\n')
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
return `Creating project graph dependencies with ${inProgressPlugins.size} plugins`;
|
spinner.setMessage(
|
||||||
|
`Creating project graph dependencies with ${inProgressPlugins.size} plugins`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SHOULD_SHOW_SPINNERS) {
|
|
||||||
spinner = new DelayedSpinner(
|
spinner = new DelayedSpinner(
|
||||||
`Creating project graph dependencies with ${plugins.length} plugins`
|
`Creating project graph dependencies with ${plugins.length} plugins`
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
createDependencyPlugins.map(async (plugin) => {
|
createDependencyPlugins.map(async (plugin) => {
|
||||||
@ -439,22 +443,26 @@ export async function applyProjectMetadata(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (inProgressPlugins.size === 1) {
|
if (inProgressPlugins.size === 1) {
|
||||||
return `Creating project metadata with ${inProgressPlugins.keys()[0]}`;
|
spinner.setMessage(
|
||||||
|
`Creating project metadata with ${inProgressPlugins.keys()[0]}`
|
||||||
|
);
|
||||||
} else if (process.env.NX_VERBOSE_LOGGING === 'true') {
|
} else if (process.env.NX_VERBOSE_LOGGING === 'true') {
|
||||||
return [
|
spinner.setMessage(
|
||||||
|
[
|
||||||
`Creating project metadata with ${inProgressPlugins.size} plugins`,
|
`Creating project metadata with ${inProgressPlugins.size} plugins`,
|
||||||
...Array.from(inProgressPlugins).map((p) => ` - ${p}`),
|
...Array.from(inProgressPlugins).map((p) => ` - ${p}`),
|
||||||
].join('\n');
|
].join('\n')
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
return `Creating project metadata with ${inProgressPlugins.size} plugins`;
|
spinner.setMessage(
|
||||||
|
`Creating project metadata with ${inProgressPlugins.size} plugins`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SHOULD_SHOW_SPINNERS) {
|
|
||||||
spinner = new DelayedSpinner(
|
spinner = new DelayedSpinner(
|
||||||
`Creating project metadata with ${plugins.length} plugins`
|
`Creating project metadata with ${plugins.length} plugins`
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
const promises = plugins.map(async (plugin) => {
|
const promises = plugins.map(async (plugin) => {
|
||||||
if (plugin.createMetadata) {
|
if (plugin.createMetadata) {
|
||||||
|
|||||||
@ -31,11 +31,7 @@ import {
|
|||||||
} from '../error-types';
|
} from '../error-types';
|
||||||
import { CreateNodesResult } from '../plugins/public-api';
|
import { CreateNodesResult } from '../plugins/public-api';
|
||||||
import { isGlobPattern } from '../../utils/globs';
|
import { isGlobPattern } from '../../utils/globs';
|
||||||
import { isOnDaemon } from '../../daemon/is-on-daemon';
|
import { DelayedSpinner } from '../../utils/delayed-spinner';
|
||||||
import {
|
|
||||||
DelayedSpinner,
|
|
||||||
SHOULD_SHOW_SPINNERS,
|
|
||||||
} from '../../utils/delayed-spinner';
|
|
||||||
|
|
||||||
export type SourceInformation = [file: string | null, plugin: string];
|
export type SourceInformation = [file: string | null, plugin: string];
|
||||||
export type ConfigurationSourceMaps = Record<
|
export type ConfigurationSourceMaps = Record<
|
||||||
@ -339,22 +335,26 @@ export async function createProjectConfigurations(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (inProgressPlugins.size === 1) {
|
if (inProgressPlugins.size === 1) {
|
||||||
return `Creating project graph nodes with ${inProgressPlugins.keys()[0]}`;
|
spinner.setMessage(
|
||||||
|
`Creating project graph nodes with ${inProgressPlugins.keys()[0]}`
|
||||||
|
);
|
||||||
} else if (process.env.NX_VERBOSE_LOGGING === 'true') {
|
} else if (process.env.NX_VERBOSE_LOGGING === 'true') {
|
||||||
return [
|
spinner.setMessage(
|
||||||
|
[
|
||||||
`Creating project graph nodes with ${inProgressPlugins.size} plugins`,
|
`Creating project graph nodes with ${inProgressPlugins.size} plugins`,
|
||||||
...Array.from(inProgressPlugins).map((p) => ` - ${p}`),
|
...Array.from(inProgressPlugins).map((p) => ` - ${p}`),
|
||||||
].join('\n');
|
].join('\n')
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
return `Creating project graph nodes with ${inProgressPlugins.size} plugins`;
|
spinner.setMessage(
|
||||||
|
`Creating project graph nodes with ${inProgressPlugins.size} plugins`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SHOULD_SHOW_SPINNERS) {
|
|
||||||
spinner = new DelayedSpinner(
|
spinner = new DelayedSpinner(
|
||||||
`Creating project graph nodes with ${plugins.length} plugins`
|
`Creating project graph nodes with ${plugins.length} plugins`
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
const results: Array<ReturnType<LoadedNxPlugin['createNodes'][1]>> = [];
|
const results: Array<ReturnType<LoadedNxPlugin['createNodes'][1]>> = [];
|
||||||
const errors: Array<
|
const errors: Array<
|
||||||
|
|||||||
@ -1,4 +1,10 @@
|
|||||||
import * as ora from 'ora';
|
import * as ora from 'ora';
|
||||||
|
import { isCI } from './is-ci';
|
||||||
|
|
||||||
|
export type DelayedSpinnerOptions = {
|
||||||
|
delay?: number;
|
||||||
|
ciDelay?: number;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class that allows to delay the creation of a spinner, as well
|
* A class that allows to delay the creation of a spinner, as well
|
||||||
@ -10,18 +16,26 @@ export class DelayedSpinner {
|
|||||||
spinner: ora.Ora;
|
spinner: ora.Ora;
|
||||||
timeouts: NodeJS.Timeout[] = [];
|
timeouts: NodeJS.Timeout[] = [];
|
||||||
initial: number = Date.now();
|
initial: number = Date.now();
|
||||||
|
lastMessage: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new {@link DelayedSpinner} instance.
|
* Constructs a new {@link DelayedSpinner} instance.
|
||||||
*
|
*
|
||||||
* @param message The message to display in the spinner
|
* @param opts The options for the spinner
|
||||||
* @param ms The number of milliseconds to wait before creating the spinner
|
|
||||||
*/
|
*/
|
||||||
constructor(message: string, ms: number = 500) {
|
constructor(message: string, opts?: DelayedSpinnerOptions) {
|
||||||
|
opts = normalizeDelayedSpinnerOpts(opts);
|
||||||
|
const delay = SHOULD_SHOW_SPINNERS ? opts.delay : opts.ciDelay;
|
||||||
|
|
||||||
this.timeouts.push(
|
this.timeouts.push(
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
if (!SHOULD_SHOW_SPINNERS) {
|
||||||
|
console.warn(message);
|
||||||
|
} else {
|
||||||
this.spinner = ora(message);
|
this.spinner = ora(message);
|
||||||
}, ms).unref()
|
}
|
||||||
|
this.lastMessage = message;
|
||||||
|
}, delay).unref()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,7 +46,12 @@ export class DelayedSpinner {
|
|||||||
* @returns The {@link DelayedSpinner} instance
|
* @returns The {@link DelayedSpinner} instance
|
||||||
*/
|
*/
|
||||||
setMessage(message: string) {
|
setMessage(message: string) {
|
||||||
|
if (this.spinner && SHOULD_SHOW_SPINNERS) {
|
||||||
this.spinner.text = message;
|
this.spinner.text = message;
|
||||||
|
} else if (this.lastMessage && this.lastMessage !== message) {
|
||||||
|
console.warn(message);
|
||||||
|
this.lastMessage = message;
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,15 +59,18 @@ export class DelayedSpinner {
|
|||||||
* Schedules an update to the message of the spinner. Useful for
|
* Schedules an update to the message of the spinner. Useful for
|
||||||
* changing the message after a certain amount of time has passed.
|
* changing the message after a certain amount of time has passed.
|
||||||
*
|
*
|
||||||
* @param message The message to display in the spinner
|
* @param opts The options for the update
|
||||||
* @param delay How long to wait before updating the message
|
|
||||||
* @returns The {@link DelayedSpinner} instance
|
* @returns The {@link DelayedSpinner} instance
|
||||||
*/
|
*/
|
||||||
scheduleMessageUpdate(message: string, delay: number) {
|
scheduleMessageUpdate(message: string, opts?: DelayedSpinnerOptions) {
|
||||||
|
opts = normalizeDelayedSpinnerOpts(opts);
|
||||||
this.timeouts.push(
|
this.timeouts.push(
|
||||||
setTimeout(() => {
|
setTimeout(
|
||||||
this.spinner.text = message;
|
() => {
|
||||||
}, delay).unref()
|
this.setMessage(message);
|
||||||
|
},
|
||||||
|
SHOULD_SHOW_SPINNERS ? opts.delay : opts.ciDelay
|
||||||
|
).unref()
|
||||||
);
|
);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -62,4 +84,13 @@ export class DelayedSpinner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SHOULD_SHOW_SPINNERS = process.stdout.isTTY;
|
const SHOULD_SHOW_SPINNERS = process.stdout.isTTY && !isCI();
|
||||||
|
|
||||||
|
function normalizeDelayedSpinnerOpts(
|
||||||
|
opts: DelayedSpinnerOptions | null | undefined
|
||||||
|
) {
|
||||||
|
opts ??= {};
|
||||||
|
opts.delay ??= 500;
|
||||||
|
opts.ciDelay ??= 10_000;
|
||||||
|
return opts;
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user