@oclif/multi-stage-output 0.5.9 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/components/stages.js +6 -5
- package/lib/multi-stage-output.d.ts +67 -32
- package/lib/multi-stage-output.js +113 -82
- package/lib/stage-tracker.d.ts +8 -7
- package/lib/stage-tracker.js +34 -16
- package/package.json +1 -1
package/lib/components/stages.js
CHANGED
|
@@ -86,7 +86,7 @@ function StageEntries({ compactionLevel, design, error, hasStageTime, stageSpeci
|
|
|
86
86
|
React.createElement(CompactStage, { stage: stage, status: status, design: design, error: error, stageSpecificBlock: stageSpecificBlock, stageTracker: stageTracker, direction: compactionLevel >= 6 ? 'row' : 'column' })),
|
|
87
87
|
status !== 'pending' && status !== 'skipped' && hasStageTime && (React.createElement(Box, { display: compactionLevel === 0 ? 'flex' : status === 'current' ? 'flex' : 'none' },
|
|
88
88
|
React.createElement(Text, null, " "),
|
|
89
|
-
React.createElement(Timer, { color: "dim", isStopped: status === 'completed', unit: timerUnit })))),
|
|
89
|
+
React.createElement(Timer, { color: "dim", isStopped: status === 'completed' || status === 'paused', unit: timerUnit })))),
|
|
90
90
|
compactionLevel === 0 &&
|
|
91
91
|
stageSpecificBlock &&
|
|
92
92
|
stageSpecificBlock.length > 0 &&
|
|
@@ -208,8 +208,8 @@ export function determineCompactionLevel({ design = constructDesignParams(), has
|
|
|
208
208
|
1;
|
|
209
209
|
let cLevel = 0;
|
|
210
210
|
const levels = [
|
|
211
|
-
// 1: only
|
|
212
|
-
(remainingHeight) => remainingHeight - stagesHeight + 1,
|
|
211
|
+
// 1: only current stages, with stage specific info nested under the stage
|
|
212
|
+
(remainingHeight) => remainingHeight - stagesHeight + Math.max(stageTracker.current.length, 1),
|
|
213
213
|
// 2: hide the elapsed time
|
|
214
214
|
(remainingHeight) => remainingHeight - 1,
|
|
215
215
|
// 3: hide the title (subtract 1 for title and 1 for paddingBottom)
|
|
@@ -232,7 +232,8 @@ export function determineCompactionLevel({ design = constructDesignParams(), has
|
|
|
232
232
|
}
|
|
233
233
|
// It's possible that the collapsed stage might extend beyond the terminal width.
|
|
234
234
|
// If so, we need to bump the compaction level up to 7 so that the stage specific info is hidden
|
|
235
|
-
if (cLevel === 6 &&
|
|
235
|
+
if (cLevel === 6 &&
|
|
236
|
+
stageTracker.current.map((c) => calculateWidthOfCompactStage(c)).reduce((acc, width) => acc + width, 0) >= columns) {
|
|
236
237
|
cLevel = 7;
|
|
237
238
|
}
|
|
238
239
|
return {
|
|
@@ -328,7 +329,7 @@ export function Stages({ compactionLevel, design = constructDesignParams(), erro
|
|
|
328
329
|
React.createElement(ErrorBoundary, { getFallbackText: () => preStages.map((s) => (s.label ? `${s.label}: ${s.value}` : s.value)).join('\n') },
|
|
329
330
|
React.createElement(Infos, { design: design, error: error, keyValuePairs: preStages })))),
|
|
330
331
|
React.createElement(Box, { flexDirection: "column", marginLeft: 1, paddingBottom: padding },
|
|
331
|
-
React.createElement(ErrorBoundary, { getFallbackText: () => stageTracker.current ?? 'unknown' },
|
|
332
|
+
React.createElement(ErrorBoundary, { getFallbackText: () => stageTracker.current[0] ?? 'unknown' },
|
|
332
333
|
React.createElement(StageEntries, { compactionLevel: actualLevelOfCompaction, design: design, error: error, hasStageTime: hasStageTime, stageSpecificBlock: stageSpecific, stageTracker: stageTracker, timerUnit: timerUnit }))),
|
|
333
334
|
postStages && postStages.length > 0 && (React.createElement(Box, { flexDirection: "column", marginLeft: 1 },
|
|
334
335
|
React.createElement(ErrorBoundary, { getFallbackText: () => postStages.map((s) => (s.label ? `${s.label}: ${s.value}` : s.value)).join('\n') },
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { Instance } from 'ink';
|
|
2
|
+
import { FormattedKeyValue, InfoBlock, KeyValuePair, SimpleMessage, StageInfoBlock, StagesProps } from './components/stages.js';
|
|
3
|
+
import { Design, RequiredDesign } from './design.js';
|
|
4
|
+
import { StageStatus, StageTracker } from './stage-tracker.js';
|
|
4
5
|
export type MultiStageOutputOptions<T extends Record<string, unknown>> = {
|
|
5
6
|
/**
|
|
6
7
|
* Stages to render.
|
|
@@ -51,26 +52,72 @@ export type MultiStageOutputOptions<T extends Record<string, unknown>> = {
|
|
|
51
52
|
*/
|
|
52
53
|
readonly jsonEnabled: boolean;
|
|
53
54
|
};
|
|
54
|
-
|
|
55
|
-
private readonly ciInstance;
|
|
55
|
+
declare class CIMultiStageOutput<T extends Record<string, unknown>> {
|
|
56
56
|
private data?;
|
|
57
57
|
private readonly design;
|
|
58
58
|
private readonly hasElapsedTime?;
|
|
59
59
|
private readonly hasStageTime?;
|
|
60
|
-
private
|
|
60
|
+
private lastUpdateTime;
|
|
61
|
+
private readonly messageTimeout;
|
|
61
62
|
private readonly postStagesBlock?;
|
|
62
63
|
private readonly preStagesBlock?;
|
|
64
|
+
private readonly seenStages;
|
|
63
65
|
private readonly stages;
|
|
64
66
|
private readonly stageSpecificBlock?;
|
|
65
|
-
private readonly
|
|
66
|
-
private
|
|
67
|
-
private readonly timerUnit
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
private readonly startTime;
|
|
68
|
+
private readonly startTimes;
|
|
69
|
+
private readonly timerUnit;
|
|
70
|
+
constructor({ data, design, postStagesBlock, preStagesBlock, showElapsedTime, showStageTime, stageSpecificBlock, stages, timerUnit, title, }: MultiStageOutputOptions<T>);
|
|
71
|
+
stop(stageTracker: StageTracker): void;
|
|
72
|
+
update(stageTracker: StageTracker, data?: Partial<T>): void;
|
|
73
|
+
private printInfo;
|
|
74
|
+
}
|
|
75
|
+
declare class MultiStageOutputBase<T extends Record<string, unknown>> implements Disposable {
|
|
76
|
+
protected readonly ciInstance: CIMultiStageOutput<T> | undefined;
|
|
77
|
+
protected data?: Partial<T>;
|
|
78
|
+
protected readonly design: RequiredDesign;
|
|
79
|
+
protected readonly hasElapsedTime?: boolean;
|
|
80
|
+
protected readonly hasStageTime?: boolean;
|
|
81
|
+
protected readonly inkInstance: Instance | undefined;
|
|
82
|
+
protected readonly postStagesBlock?: InfoBlock<T>;
|
|
83
|
+
protected readonly preStagesBlock?: InfoBlock<T>;
|
|
84
|
+
protected readonly stages: readonly string[] | string[];
|
|
85
|
+
protected readonly stageSpecificBlock?: StageInfoBlock<T>;
|
|
86
|
+
protected readonly stageTracker: StageTracker;
|
|
87
|
+
protected stopped: boolean;
|
|
88
|
+
protected readonly timerUnit?: 'ms' | 's';
|
|
89
|
+
protected readonly title?: string;
|
|
90
|
+
constructor({ data, design, jsonEnabled, postStagesBlock, preStagesBlock, showElapsedTime, showStageTime, stageSpecificBlock, stages, timerUnit, title, }: MultiStageOutputOptions<T>, allowParallelTasks?: boolean);
|
|
70
91
|
/**
|
|
71
92
|
* Stop multi-stage output from running with a failed status.
|
|
72
93
|
*/
|
|
73
94
|
error(): void;
|
|
95
|
+
protected formatKeyValuePairs(infoBlock: InfoBlock<T> | StageInfoBlock<T> | undefined): FormattedKeyValue[];
|
|
96
|
+
/** shared method to populate everything needed for Stages cmp */
|
|
97
|
+
protected generateStagesInput(opts?: {
|
|
98
|
+
compactionLevel?: number;
|
|
99
|
+
}): StagesProps;
|
|
100
|
+
protected rerender(): void;
|
|
101
|
+
/**
|
|
102
|
+
* Stop multi-stage output from running.
|
|
103
|
+
*
|
|
104
|
+
* The stage currently running will be changed to the provided `finalStatus`.
|
|
105
|
+
*
|
|
106
|
+
* @param finalStatus - The status to set the current stage to.
|
|
107
|
+
* @returns void
|
|
108
|
+
*/
|
|
109
|
+
stop(finalStatus?: StageStatus): void;
|
|
110
|
+
[Symbol.dispose](): void;
|
|
111
|
+
/**
|
|
112
|
+
* Updates the data of the component.
|
|
113
|
+
*
|
|
114
|
+
* @param data - The partial data object to update the component's data with.
|
|
115
|
+
* @returns void
|
|
116
|
+
*/
|
|
117
|
+
updateData(data: Partial<T>): void;
|
|
118
|
+
}
|
|
119
|
+
export declare class MultiStageOutput<T extends Record<string, unknown>> extends MultiStageOutputBase<T> {
|
|
120
|
+
constructor(options: MultiStageOutputOptions<T>);
|
|
74
121
|
/**
|
|
75
122
|
* Go to a stage, marking any stages in between the current stage and the provided stage as completed.
|
|
76
123
|
*
|
|
@@ -102,26 +149,14 @@ export declare class MultiStageOutput<T extends Record<string, unknown>> impleme
|
|
|
102
149
|
* @returns void
|
|
103
150
|
*/
|
|
104
151
|
skipTo(stage: string, data?: Partial<T>): void;
|
|
105
|
-
/**
|
|
106
|
-
* Stop multi-stage output from running.
|
|
107
|
-
*
|
|
108
|
-
* The stage currently running will be changed to the provided `finalStatus`.
|
|
109
|
-
*
|
|
110
|
-
* @param finalStatus - The status to set the current stage to.
|
|
111
|
-
* @returns void
|
|
112
|
-
*/
|
|
113
|
-
stop(finalStatus?: StageStatus): void;
|
|
114
|
-
[Symbol.dispose](): void;
|
|
115
|
-
/**
|
|
116
|
-
* Updates the data of the component.
|
|
117
|
-
*
|
|
118
|
-
* @param data - The partial data object to update the component's data with.
|
|
119
|
-
* @returns void
|
|
120
|
-
*/
|
|
121
|
-
updateData(data: Partial<T>): void;
|
|
122
|
-
private formatKeyValuePairs;
|
|
123
|
-
/** shared method to populate everything needed for Stages cmp */
|
|
124
|
-
private generateStagesInput;
|
|
125
|
-
private rerender;
|
|
126
152
|
private update;
|
|
127
153
|
}
|
|
154
|
+
export declare class ParallelMultiStageOutput<T extends Record<string, unknown>> extends MultiStageOutputBase<T> {
|
|
155
|
+
constructor(options: MultiStageOutputOptions<T>);
|
|
156
|
+
pauseStage(stage: string, data?: Partial<T>): void;
|
|
157
|
+
resumeStage(stage: string, data?: Partial<T>): void;
|
|
158
|
+
startStage(stage: string, data?: Partial<T>): void;
|
|
159
|
+
stopStage(stage: string, data?: Partial<T>): void;
|
|
160
|
+
private update;
|
|
161
|
+
}
|
|
162
|
+
export {};
|
|
@@ -150,7 +150,7 @@ class CIMultiStageOutput {
|
|
|
150
150
|
}
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
|
-
|
|
153
|
+
class MultiStageOutputBase {
|
|
154
154
|
ciInstance;
|
|
155
155
|
data;
|
|
156
156
|
design;
|
|
@@ -165,7 +165,7 @@ export class MultiStageOutput {
|
|
|
165
165
|
stopped = false;
|
|
166
166
|
timerUnit;
|
|
167
167
|
title;
|
|
168
|
-
constructor({ data, design, jsonEnabled = false, postStagesBlock, preStagesBlock, showElapsedTime, showStageTime, stageSpecificBlock, stages, timerUnit, title, }) {
|
|
168
|
+
constructor({ data, design, jsonEnabled = false, postStagesBlock, preStagesBlock, showElapsedTime, showStageTime, stageSpecificBlock, stages, timerUnit, title, }, allowParallelTasks) {
|
|
169
169
|
this.data = data;
|
|
170
170
|
this.design = constructDesignParams(design);
|
|
171
171
|
this.stages = stages;
|
|
@@ -175,7 +175,7 @@ export class MultiStageOutput {
|
|
|
175
175
|
this.hasElapsedTime = showElapsedTime ?? true;
|
|
176
176
|
this.hasStageTime = showStageTime ?? true;
|
|
177
177
|
this.timerUnit = timerUnit ?? 'ms';
|
|
178
|
-
this.stageTracker = new StageTracker(stages);
|
|
178
|
+
this.stageTracker = new StageTracker(stages, { allowParallelTasks });
|
|
179
179
|
this.stageSpecificBlock = stageSpecificBlock;
|
|
180
180
|
if (jsonEnabled)
|
|
181
181
|
return;
|
|
@@ -204,6 +204,89 @@ export class MultiStageOutput {
|
|
|
204
204
|
error() {
|
|
205
205
|
this.stop('failed');
|
|
206
206
|
}
|
|
207
|
+
formatKeyValuePairs(infoBlock) {
|
|
208
|
+
return (infoBlock?.map((info) => {
|
|
209
|
+
const formattedData = info.get ? info.get(this.data) : undefined;
|
|
210
|
+
return {
|
|
211
|
+
color: info.color,
|
|
212
|
+
isBold: info.bold,
|
|
213
|
+
neverCollapse: info.neverCollapse,
|
|
214
|
+
type: info.type,
|
|
215
|
+
value: formattedData,
|
|
216
|
+
...(info.type === 'message' ? {} : { label: info.label }),
|
|
217
|
+
...('stage' in info ? { stage: info.stage } : {}),
|
|
218
|
+
};
|
|
219
|
+
}) ?? []);
|
|
220
|
+
}
|
|
221
|
+
/** shared method to populate everything needed for Stages cmp */
|
|
222
|
+
generateStagesInput(opts) {
|
|
223
|
+
const { compactionLevel } = opts ?? {};
|
|
224
|
+
return {
|
|
225
|
+
compactionLevel,
|
|
226
|
+
design: this.design,
|
|
227
|
+
hasElapsedTime: this.hasElapsedTime,
|
|
228
|
+
hasStageTime: this.hasStageTime,
|
|
229
|
+
postStagesBlock: this.formatKeyValuePairs(this.postStagesBlock),
|
|
230
|
+
preStagesBlock: this.formatKeyValuePairs(this.preStagesBlock),
|
|
231
|
+
stageSpecificBlock: this.formatKeyValuePairs(this.stageSpecificBlock),
|
|
232
|
+
stageTracker: this.stageTracker,
|
|
233
|
+
timerUnit: this.timerUnit,
|
|
234
|
+
title: this.title,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
rerender() {
|
|
238
|
+
if (isInCi) {
|
|
239
|
+
this.ciInstance?.update(this.stageTracker, this.data);
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
this.inkInstance?.rerender(React.createElement(Stages, { ...this.generateStagesInput() }));
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Stop multi-stage output from running.
|
|
247
|
+
*
|
|
248
|
+
* The stage currently running will be changed to the provided `finalStatus`.
|
|
249
|
+
*
|
|
250
|
+
* @param finalStatus - The status to set the current stage to.
|
|
251
|
+
* @returns void
|
|
252
|
+
*/
|
|
253
|
+
stop(finalStatus = 'completed') {
|
|
254
|
+
if (this.stopped)
|
|
255
|
+
return;
|
|
256
|
+
this.stopped = true;
|
|
257
|
+
this.stageTracker.stop(this.stageTracker.current[0] ?? this.stages[0], finalStatus);
|
|
258
|
+
if (isInCi) {
|
|
259
|
+
this.ciInstance?.stop(this.stageTracker);
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
// The underlying components expect an Error, although they don't currently use anything on the error - they check if it exists.
|
|
263
|
+
// Instead of refactoring the components to take a boolean, we pass in a placeholder Error,
|
|
264
|
+
// which, gives us the flexibility in the future to pass in an actual Error if we want
|
|
265
|
+
const error = finalStatus === 'failed' ? new Error('Error') : undefined;
|
|
266
|
+
const stagesInput = { ...this.generateStagesInput({ compactionLevel: 0 }), ...(error ? { error } : {}) };
|
|
267
|
+
this.inkInstance?.rerender(React.createElement(Stages, { ...stagesInput, compactionLevel: 0 }));
|
|
268
|
+
this.inkInstance?.unmount();
|
|
269
|
+
}
|
|
270
|
+
[Symbol.dispose]() {
|
|
271
|
+
this.inkInstance?.unmount();
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Updates the data of the component.
|
|
275
|
+
*
|
|
276
|
+
* @param data - The partial data object to update the component's data with.
|
|
277
|
+
* @returns void
|
|
278
|
+
*/
|
|
279
|
+
updateData(data) {
|
|
280
|
+
if (this.stopped)
|
|
281
|
+
return;
|
|
282
|
+
this.data = { ...this.data, ...data };
|
|
283
|
+
this.rerender();
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
export class MultiStageOutput extends MultiStageOutputBase {
|
|
287
|
+
constructor(options) {
|
|
288
|
+
super(options);
|
|
289
|
+
}
|
|
207
290
|
/**
|
|
208
291
|
* Go to a stage, marking any stages in between the current stage and the provided stage as completed.
|
|
209
292
|
*
|
|
@@ -222,7 +305,7 @@ export class MultiStageOutput {
|
|
|
222
305
|
if (!this.stages.includes(stage))
|
|
223
306
|
return;
|
|
224
307
|
// prevent going to a previous stage
|
|
225
|
-
if (this.stages.indexOf(stage) < this.stages.indexOf(this.stageTracker.current ?? this.stages[0]))
|
|
308
|
+
if (this.stages.indexOf(stage) < this.stages.indexOf(this.stageTracker.current[0] ?? this.stages[0]))
|
|
226
309
|
return;
|
|
227
310
|
this.update(stage, 'completed', data);
|
|
228
311
|
}
|
|
@@ -235,7 +318,7 @@ export class MultiStageOutput {
|
|
|
235
318
|
next(data) {
|
|
236
319
|
if (this.stopped)
|
|
237
320
|
return;
|
|
238
|
-
const nextStageIndex = this.stages.indexOf(this.stageTracker.current ?? this.stages[0]) + 1;
|
|
321
|
+
const nextStageIndex = this.stages.indexOf(this.stageTracker.current[0] ?? this.stages[0]) + 1;
|
|
239
322
|
if (nextStageIndex < this.stages.length) {
|
|
240
323
|
this.update(this.stages[nextStageIndex], 'completed', data);
|
|
241
324
|
}
|
|
@@ -258,93 +341,41 @@ export class MultiStageOutput {
|
|
|
258
341
|
if (!this.stages.includes(stage))
|
|
259
342
|
return;
|
|
260
343
|
// prevent going to a previous stage
|
|
261
|
-
if (this.stages.indexOf(stage) < this.stages.indexOf(this.stageTracker.current ?? this.stages[0]))
|
|
344
|
+
if (this.stages.indexOf(stage) < this.stages.indexOf(this.stageTracker.current[0] ?? this.stages[0]))
|
|
262
345
|
return;
|
|
263
346
|
this.update(stage, 'skipped', data);
|
|
264
347
|
}
|
|
265
|
-
|
|
266
|
-
* Stop multi-stage output from running.
|
|
267
|
-
*
|
|
268
|
-
* The stage currently running will be changed to the provided `finalStatus`.
|
|
269
|
-
*
|
|
270
|
-
* @param finalStatus - The status to set the current stage to.
|
|
271
|
-
* @returns void
|
|
272
|
-
*/
|
|
273
|
-
stop(finalStatus = 'completed') {
|
|
274
|
-
if (this.stopped)
|
|
275
|
-
return;
|
|
276
|
-
this.stopped = true;
|
|
277
|
-
this.stageTracker.refresh(this.stageTracker.current ?? this.stages[0], {
|
|
278
|
-
finalStatus,
|
|
279
|
-
});
|
|
280
|
-
if (isInCi) {
|
|
281
|
-
this.ciInstance?.stop(this.stageTracker);
|
|
282
|
-
return;
|
|
283
|
-
}
|
|
284
|
-
// The underlying components expect an Error, although they don't currently use anything on the error - they check if it exists.
|
|
285
|
-
// Instead of refactoring the components to take a boolean, we pass in a placeholder Error,
|
|
286
|
-
// which, gives us the flexibility in the future to pass in an actual Error if we want
|
|
287
|
-
const error = finalStatus === 'failed' ? new Error('Error') : undefined;
|
|
288
|
-
const stagesInput = { ...this.generateStagesInput({ compactionLevel: 0 }), ...(error ? { error } : {}) };
|
|
289
|
-
this.inkInstance?.rerender(React.createElement(Stages, { ...stagesInput, compactionLevel: 0 }));
|
|
290
|
-
this.inkInstance?.unmount();
|
|
291
|
-
}
|
|
292
|
-
[Symbol.dispose]() {
|
|
293
|
-
this.inkInstance?.unmount();
|
|
294
|
-
}
|
|
295
|
-
/**
|
|
296
|
-
* Updates the data of the component.
|
|
297
|
-
*
|
|
298
|
-
* @param data - The partial data object to update the component's data with.
|
|
299
|
-
* @returns void
|
|
300
|
-
*/
|
|
301
|
-
updateData(data) {
|
|
302
|
-
if (this.stopped)
|
|
303
|
-
return;
|
|
348
|
+
update(stage, bypassStatus, data) {
|
|
304
349
|
this.data = { ...this.data, ...data };
|
|
350
|
+
this.stageTracker.refresh(stage, { bypassStatus });
|
|
305
351
|
this.rerender();
|
|
306
352
|
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
color: info.color,
|
|
312
|
-
isBold: info.bold,
|
|
313
|
-
neverCollapse: info.neverCollapse,
|
|
314
|
-
type: info.type,
|
|
315
|
-
value: formattedData,
|
|
316
|
-
...(info.type === 'message' ? {} : { label: info.label }),
|
|
317
|
-
...('stage' in info ? { stage: info.stage } : {}),
|
|
318
|
-
};
|
|
319
|
-
}) ?? []);
|
|
353
|
+
}
|
|
354
|
+
export class ParallelMultiStageOutput extends MultiStageOutputBase {
|
|
355
|
+
constructor(options) {
|
|
356
|
+
super(options, true);
|
|
320
357
|
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
const { compactionLevel } = opts ?? {};
|
|
324
|
-
return {
|
|
325
|
-
compactionLevel,
|
|
326
|
-
design: this.design,
|
|
327
|
-
hasElapsedTime: this.hasElapsedTime,
|
|
328
|
-
hasStageTime: this.hasStageTime,
|
|
329
|
-
postStagesBlock: this.formatKeyValuePairs(this.postStagesBlock),
|
|
330
|
-
preStagesBlock: this.formatKeyValuePairs(this.preStagesBlock),
|
|
331
|
-
stageSpecificBlock: this.formatKeyValuePairs(this.stageSpecificBlock),
|
|
332
|
-
stageTracker: this.stageTracker,
|
|
333
|
-
timerUnit: this.timerUnit,
|
|
334
|
-
title: this.title,
|
|
335
|
-
};
|
|
358
|
+
pauseStage(stage, data) {
|
|
359
|
+
this.update(stage, 'paused', data);
|
|
336
360
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
this.ciInstance?.update(this.stageTracker, this.data);
|
|
340
|
-
}
|
|
341
|
-
else {
|
|
342
|
-
this.inkInstance?.rerender(React.createElement(Stages, { ...this.generateStagesInput() }));
|
|
343
|
-
}
|
|
361
|
+
resumeStage(stage, data) {
|
|
362
|
+
this.update(stage, 'current', data);
|
|
344
363
|
}
|
|
345
|
-
|
|
364
|
+
startStage(stage, data) {
|
|
365
|
+
this.update(stage, 'current', data);
|
|
366
|
+
}
|
|
367
|
+
stopStage(stage, data) {
|
|
368
|
+
this.update(stage, 'completed', data);
|
|
369
|
+
}
|
|
370
|
+
update(stage, status, data) {
|
|
371
|
+
if (this.stopped)
|
|
372
|
+
return;
|
|
373
|
+
if (!this.stages.includes(stage))
|
|
374
|
+
return;
|
|
375
|
+
if (this.stageTracker.get(stage) === 'completed')
|
|
376
|
+
return;
|
|
346
377
|
this.data = { ...this.data, ...data };
|
|
347
|
-
this.stageTracker.
|
|
378
|
+
this.stageTracker.update(stage, status);
|
|
348
379
|
this.rerender();
|
|
349
380
|
}
|
|
350
381
|
}
|
package/lib/stage-tracker.d.ts
CHANGED
|
@@ -1,23 +1,24 @@
|
|
|
1
1
|
export type StageStatus = 'aborted' | 'async' | 'completed' | 'current' | 'failed' | 'paused' | 'pending' | 'skipped' | 'warning';
|
|
2
2
|
export declare class StageTracker {
|
|
3
3
|
private stages;
|
|
4
|
-
current: string
|
|
4
|
+
current: string[];
|
|
5
|
+
private allowParallelTasks;
|
|
5
6
|
private map;
|
|
6
7
|
private markers;
|
|
7
|
-
constructor(stages: readonly string[] | string[]
|
|
8
|
+
constructor(stages: readonly string[] | string[], opts?: {
|
|
9
|
+
allowParallelTasks?: boolean;
|
|
10
|
+
});
|
|
8
11
|
get size(): number;
|
|
9
12
|
entries(): IterableIterator<[string, StageStatus]>;
|
|
10
13
|
get(stage: string): StageStatus | undefined;
|
|
11
|
-
getCurrent(): {
|
|
12
|
-
stage: string;
|
|
13
|
-
status: StageStatus;
|
|
14
|
-
} | undefined;
|
|
15
14
|
indexOf(stage: string): number;
|
|
16
15
|
refresh(nextStage: string, opts?: {
|
|
17
16
|
finalStatus?: StageStatus;
|
|
18
17
|
bypassStatus?: StageStatus;
|
|
19
18
|
}): void;
|
|
20
19
|
set(stage: string, status: StageStatus): void;
|
|
20
|
+
stop(currentStage: string, finalStatus: StageStatus): void;
|
|
21
|
+
update(stage: string, status: StageStatus): void;
|
|
21
22
|
values(): IterableIterator<StageStatus>;
|
|
22
|
-
private
|
|
23
|
+
private stopStage;
|
|
23
24
|
}
|
package/lib/stage-tracker.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { Performance } from '@oclif/core/performance';
|
|
2
2
|
export class StageTracker {
|
|
3
3
|
stages;
|
|
4
|
-
current;
|
|
4
|
+
current = [];
|
|
5
|
+
allowParallelTasks;
|
|
5
6
|
map = new Map();
|
|
6
7
|
markers = new Map();
|
|
7
|
-
constructor(stages) {
|
|
8
|
+
constructor(stages, opts) {
|
|
8
9
|
this.stages = stages;
|
|
9
10
|
this.map = new Map(stages.map((stage) => [stage, 'pending']));
|
|
11
|
+
this.allowParallelTasks = opts?.allowParallelTasks ?? false;
|
|
10
12
|
}
|
|
11
13
|
get size() {
|
|
12
14
|
return this.map.size;
|
|
@@ -17,14 +19,6 @@ export class StageTracker {
|
|
|
17
19
|
get(stage) {
|
|
18
20
|
return this.map.get(stage);
|
|
19
21
|
}
|
|
20
|
-
getCurrent() {
|
|
21
|
-
if (this.current) {
|
|
22
|
-
return {
|
|
23
|
-
stage: this.current,
|
|
24
|
-
status: this.map.get(this.current),
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
22
|
indexOf(stage) {
|
|
29
23
|
return this.stages.indexOf(stage);
|
|
30
24
|
}
|
|
@@ -37,8 +31,7 @@ export class StageTracker {
|
|
|
37
31
|
continue;
|
|
38
32
|
// .stop() was called with a finalStatus
|
|
39
33
|
if (nextStage === stage && opts?.finalStatus) {
|
|
40
|
-
this.
|
|
41
|
-
this.stopMarker(stage);
|
|
34
|
+
this.stopStage(stage, opts.finalStatus);
|
|
42
35
|
continue;
|
|
43
36
|
}
|
|
44
37
|
// set the current stage
|
|
@@ -57,8 +50,7 @@ export class StageTracker {
|
|
|
57
50
|
}
|
|
58
51
|
// any stage before the current stage should be marked as completed (if it hasn't been marked as skipped or failed yet)
|
|
59
52
|
if (stages.indexOf(nextStage) > stages.indexOf(stage)) {
|
|
60
|
-
this.
|
|
61
|
-
this.stopMarker(stage);
|
|
53
|
+
this.stopStage(stage, 'completed');
|
|
62
54
|
continue;
|
|
63
55
|
}
|
|
64
56
|
// default to pending
|
|
@@ -67,14 +59,40 @@ export class StageTracker {
|
|
|
67
59
|
}
|
|
68
60
|
set(stage, status) {
|
|
69
61
|
if (status === 'current') {
|
|
70
|
-
this.current
|
|
62
|
+
if (!this.current.includes(stage)) {
|
|
63
|
+
this.current.push(stage);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
this.current = this.current.filter((s) => s !== stage);
|
|
71
68
|
}
|
|
72
69
|
this.map.set(stage, status);
|
|
73
70
|
}
|
|
71
|
+
stop(currentStage, finalStatus) {
|
|
72
|
+
if (this.allowParallelTasks) {
|
|
73
|
+
for (const [stage, status] of this.entries()) {
|
|
74
|
+
if (status === 'current') {
|
|
75
|
+
this.stopStage(stage, finalStatus);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
this.refresh(currentStage, { finalStatus });
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
update(stage, status) {
|
|
84
|
+
if (status === 'completed' || status === 'failed' || status === 'aborted') {
|
|
85
|
+
this.stopStage(stage, status);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
this.set(stage, status);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
74
91
|
values() {
|
|
75
92
|
return this.map.values();
|
|
76
93
|
}
|
|
77
|
-
|
|
94
|
+
stopStage(stage, status) {
|
|
95
|
+
this.set(stage, status);
|
|
78
96
|
const marker = this.markers.get(stage);
|
|
79
97
|
if (marker && !marker.stopped) {
|
|
80
98
|
marker.stop();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oclif/multi-stage-output",
|
|
3
3
|
"description": "Terminal output for oclif commands with multiple stages",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.6.0",
|
|
5
5
|
"author": "Salesforce",
|
|
6
6
|
"bugs": "https://github.com/oclif/multi-stage-output/issues",
|
|
7
7
|
"dependencies": {
|