@lage-run/reporters 1.5.1 → 1.7.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/AdoReporter.d.ts +3 -0
- package/lib/AdoReporter.js +2 -2
- package/lib/AdoReporter.js.map +1 -1
- package/lib/BasicReporter.d.ts +15 -1
- package/lib/BasicReporter.js +38 -29
- package/lib/BasicReporter.js.map +1 -1
- package/lib/ChromeTraceEventsReporter.d.ts +3 -0
- package/lib/ChromeTraceEventsReporter.js +4 -5
- package/lib/ChromeTraceEventsReporter.js.map +1 -1
- package/lib/GithubActionsReporter.d.ts +3 -0
- package/lib/GithubActionsReporter.js +2 -2
- package/lib/GithubActionsReporter.js.map +1 -1
- package/lib/GroupedReporter.d.ts +9 -9
- package/lib/GroupedReporter.js +42 -63
- package/lib/GroupedReporter.js.map +1 -1
- package/lib/JsonReporter.d.ts +5 -1
- package/lib/JsonReporter.js +3 -3
- package/lib/JsonReporter.js.map +1 -1
- package/lib/LogReporter.d.ts +24 -2
- package/lib/LogReporter.js +63 -79
- package/lib/LogReporter.js.map +1 -1
- package/lib/ProgressReporter.d.ts +24 -4
- package/lib/ProgressReporter.js +108 -119
- package/lib/ProgressReporter.js.map +1 -1
- package/lib/VerboseFileLogReporter.d.ts +6 -1
- package/lib/VerboseFileLogReporter.js +27 -21
- package/lib/VerboseFileLogReporter.js.map +1 -1
- package/lib/formatDuration.d.ts +10 -0
- package/lib/formatDuration.js +61 -0
- package/lib/formatDuration.js.map +1 -0
- package/lib/formatHelpers.d.ts +13 -0
- package/lib/formatHelpers.js +61 -0
- package/lib/formatHelpers.js.map +1 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +13 -0
- package/lib/index.js.map +1 -1
- package/lib/slowestTargetRuns.js +2 -2
- package/lib/slowestTargetRuns.js.map +1 -1
- package/lib/types/TargetLogData.d.ts +5 -0
- package/package.json +8 -10
- package/lib/formatBytes.d.ts +0 -1
- package/lib/formatBytes.js +0 -13
- package/lib/formatBytes.js.map +0 -1
- package/lib/gradient.d.ts +0 -6
- package/lib/gradient.js +0 -18
- package/lib/gradient.js.map +0 -1
- package/lib/types/progressBarTypes.d.ts +0 -12
- package/lib/types/progressBarTypes.js +0 -4
- package/lib/types/progressBarTypes.js.map +0 -1
package/lib/AdoReporter.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type { TargetRun } from "@lage-run/scheduler-types";
|
|
2
2
|
import { GroupedReporter } from "./GroupedReporter.js";
|
|
3
|
+
/**
|
|
4
|
+
* Reporter that formats logs for Azure DevOps, optionally with grouping.
|
|
5
|
+
*/
|
|
3
6
|
export declare class AdoReporter extends GroupedReporter {
|
|
4
7
|
protected formatGroupStart(packageName: string, task: string, status: string, duration?: [number, number]): string;
|
|
5
8
|
protected formatGroupEnd(): string;
|
package/lib/AdoReporter.js
CHANGED
|
@@ -8,7 +8,7 @@ Object.defineProperty(exports, "AdoReporter", {
|
|
|
8
8
|
return AdoReporter;
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
|
-
const
|
|
11
|
+
const _formatDuration = require("./formatDuration.js");
|
|
12
12
|
const _chalk = /*#__PURE__*/ _interop_require_default(require("chalk"));
|
|
13
13
|
const _GroupedReporter = require("./GroupedReporter.js");
|
|
14
14
|
function _interop_require_default(obj) {
|
|
@@ -18,7 +18,7 @@ function _interop_require_default(obj) {
|
|
|
18
18
|
}
|
|
19
19
|
class AdoReporter extends _GroupedReporter.GroupedReporter {
|
|
20
20
|
formatGroupStart(packageName, task, status, duration) {
|
|
21
|
-
return `##[group] ${_GroupedReporter.colors.pkg(packageName)} ${_GroupedReporter.colors.task(task)} ${status}${duration ? `, took ${(0,
|
|
21
|
+
return `##[group] ${_GroupedReporter.colors.pkg(packageName)} ${_GroupedReporter.colors.task(task)} ${status}${duration ? `, took ${(0, _formatDuration.formatHrtime)(duration)}` : ""}\n`;
|
|
22
22
|
}
|
|
23
23
|
formatGroupEnd() {
|
|
24
24
|
return `##[endgroup]\n`;
|
package/lib/AdoReporter.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/AdoReporter.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"sources":["../src/AdoReporter.ts"],"sourcesContent":["import { formatHrtime } from \"./formatDuration.js\";\nimport chalk from \"chalk\";\nimport type { TargetRun } from \"@lage-run/scheduler-types\";\nimport { colors, GroupedReporter } from \"./GroupedReporter.js\";\n\n/**\n * Reporter that formats logs for Azure DevOps, optionally with grouping.\n */\nexport class AdoReporter extends GroupedReporter {\n protected formatGroupStart(packageName: string, task: string, status: string, duration?: [number, number]): string {\n return `##[group] ${colors.pkg(packageName)} ${colors.task(task)} ${status}${duration ? `, took ${formatHrtime(duration)}` : \"\"}\\n`;\n }\n\n protected formatGroupEnd(): string {\n return `##[endgroup]\\n`;\n }\n\n protected writeSummaryHeader(): void {\n this.logStream.write(chalk.cyanBright(`##[section]Summary\\n`));\n }\n\n protected writeSummaryFooter(): void {\n // ADO sections have no closing marker\n }\n\n protected writeFailures(failed: string[], targetRuns: Map<string, TargetRun<unknown>>): void {\n let packagesMessage = `##vso[task.logissue type=error]Your build failed on the following packages => `;\n\n for (const targetId of failed) {\n const target = targetRuns.get(targetId)?.target;\n\n if (target) {\n const { packageName, task } = target;\n const taskLogs = this.logEntries.get(targetId);\n\n packagesMessage += `[${packageName} ${task}], `;\n\n this.logStream.write(`##[error] [${chalk.magenta(packageName)} ${chalk.cyan(task)}] ${chalk.redBright(\"ERROR DETECTED\")}\\n`);\n\n if (taskLogs) {\n for (const entry of taskLogs) {\n // Log each entry separately to prevent truncation\n this.logStream.write(`##[error] ${entry.msg}\\n`);\n }\n }\n }\n }\n\n packagesMessage += \"find the error logs above with the prefix '##[error]!'\\n\";\n this.logStream.write(packagesMessage);\n }\n}\n"],"names":["AdoReporter","GroupedReporter","formatGroupStart","packageName","task","status","duration","colors","pkg","formatHrtime","formatGroupEnd","writeSummaryHeader","logStream","write","chalk","cyanBright","writeSummaryFooter","writeFailures","failed","targetRuns","packagesMessage","targetId","target","get","taskLogs","logEntries","magenta","cyan","redBright","entry","msg"],"mappings":";;;;+BAQaA;;;eAAAA;;;gCARgB;8DACX;iCAEsB;;;;;;AAKjC,MAAMA,oBAAoBC,gCAAe;IACpCC,iBAAiBC,WAAmB,EAAEC,IAAY,EAAEC,MAAc,EAAEC,QAA2B,EAAU;QACjH,OAAO,CAAC,UAAU,EAAEC,uBAAM,CAACC,GAAG,CAACL,aAAa,CAAC,EAAEI,uBAAM,CAACH,IAAI,CAACA,MAAM,CAAC,EAAEC,SAASC,WAAW,CAAC,OAAO,EAAEG,IAAAA,4BAAY,EAACH,WAAW,GAAG,GAAG,EAAE,CAAC;IACrI;IAEUI,iBAAyB;QACjC,OAAO,CAAC,cAAc,CAAC;IACzB;IAEUC,qBAA2B;QACnC,IAAI,CAACC,SAAS,CAACC,KAAK,CAACC,cAAK,CAACC,UAAU,CAAC,CAAC,oBAAoB,CAAC;IAC9D;IAEUC,qBAA2B;IACnC,sCAAsC;IACxC;IAEUC,cAAcC,MAAgB,EAAEC,UAA2C,EAAQ;QAC3F,IAAIC,kBAAkB,CAAC,8EAA8E,CAAC;QAEtG,KAAK,MAAMC,YAAYH,OAAQ;YAC7B,MAAMI,SAASH,WAAWI,GAAG,CAACF,WAAWC;YAEzC,IAAIA,QAAQ;gBACV,MAAM,EAAEnB,WAAW,EAAEC,IAAI,EAAE,GAAGkB;gBAC9B,MAAME,WAAW,IAAI,CAACC,UAAU,CAACF,GAAG,CAACF;gBAErCD,mBAAmB,CAAC,CAAC,EAAEjB,YAAY,CAAC,EAAEC,KAAK,GAAG,CAAC;gBAE/C,IAAI,CAACQ,SAAS,CAACC,KAAK,CAAC,CAAC,WAAW,EAAEC,cAAK,CAACY,OAAO,CAACvB,aAAa,CAAC,EAAEW,cAAK,CAACa,IAAI,CAACvB,MAAM,EAAE,EAAEU,cAAK,CAACc,SAAS,CAAC,kBAAkB,EAAE,CAAC;gBAE3H,IAAIJ,UAAU;oBACZ,KAAK,MAAMK,SAASL,SAAU;wBAC5B,kDAAkD;wBAClD,IAAI,CAACZ,SAAS,CAACC,KAAK,CAAC,CAAC,UAAU,EAAEgB,MAAMC,GAAG,CAAC,EAAE,CAAC;oBACjD;gBACF;YACF;QACF;QAEAV,mBAAmB;QACnB,IAAI,CAACR,SAAS,CAACC,KAAK,CAACO;IACvB;AACF"}
|
package/lib/BasicReporter.d.ts
CHANGED
|
@@ -1,16 +1,30 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { LogEntry, Reporter } from "@lage-run/logger";
|
|
2
2
|
import type { SchedulerRunSummary } from "@lage-run/scheduler-types";
|
|
3
|
+
import type { Writable } from "stream";
|
|
4
|
+
/**
|
|
5
|
+
* Shows running/remaining target counts and completed targets, but does not display
|
|
6
|
+
* the names of running targets for efficiency.
|
|
7
|
+
*/
|
|
3
8
|
export declare class BasicReporter implements Reporter {
|
|
4
9
|
private taskData;
|
|
5
10
|
private updateTimer;
|
|
6
11
|
private startTimer;
|
|
12
|
+
private logMemory;
|
|
13
|
+
private logStream;
|
|
7
14
|
constructor(params?: {
|
|
8
15
|
concurrency?: number;
|
|
9
16
|
version?: string;
|
|
10
17
|
frequency?: number;
|
|
18
|
+
/** Whether to capture and report main process memory usage on target completion */
|
|
19
|
+
logMemory?: boolean;
|
|
20
|
+
/** Stream for output (defaults to process.stdout) */
|
|
21
|
+
logStream?: Writable;
|
|
11
22
|
});
|
|
12
23
|
log(entry: LogEntry): void;
|
|
13
24
|
summarize(schedulerRunSummary: SchedulerRunSummary): void;
|
|
25
|
+
/** Clear the update timer */
|
|
26
|
+
cleanup(): void;
|
|
14
27
|
private reportCompletion;
|
|
15
28
|
private renderStatus;
|
|
29
|
+
private print;
|
|
16
30
|
}
|
package/lib/BasicReporter.js
CHANGED
|
@@ -9,9 +9,8 @@ Object.defineProperty(exports, "BasicReporter", {
|
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
11
|
const _chalk = /*#__PURE__*/ _interop_require_default(require("chalk"));
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const _formatBytes = require("./formatBytes.js");
|
|
12
|
+
const _formatDuration = require("./formatDuration.js");
|
|
13
|
+
const _formatHelpers = require("./formatHelpers.js");
|
|
15
14
|
function _define_property(obj, key, value) {
|
|
16
15
|
if (key in obj) {
|
|
17
16
|
Object.defineProperty(obj, key, {
|
|
@@ -52,7 +51,6 @@ const colors = {
|
|
|
52
51
|
task: _chalk.default.hex("#00DDDD"),
|
|
53
52
|
pkg: _chalk.default.hex("#FFD66B")
|
|
54
53
|
};
|
|
55
|
-
const hrLine = "┈".repeat(80);
|
|
56
54
|
const icons = {
|
|
57
55
|
success: "✓",
|
|
58
56
|
failed: "✗",
|
|
@@ -64,12 +62,6 @@ const terminal = {
|
|
|
64
62
|
showCursor: "\x1b[?25h",
|
|
65
63
|
clearLine: "\x1b[2K\r"
|
|
66
64
|
};
|
|
67
|
-
const fancy = (str)=>(0, _gradient.gradient)({
|
|
68
|
-
r: 237,
|
|
69
|
-
g: 178,
|
|
70
|
-
b: 77
|
|
71
|
-
}, "cyan")(str);
|
|
72
|
-
const print = (message)=>process.stdout.write(message + "\n");
|
|
73
65
|
class BasicReporter {
|
|
74
66
|
log(entry) {
|
|
75
67
|
const data = entry.data;
|
|
@@ -91,49 +83,55 @@ class BasicReporter {
|
|
|
91
83
|
this.reportCompletion({
|
|
92
84
|
target: data.target,
|
|
93
85
|
status: data.status,
|
|
94
|
-
duration: data.duration
|
|
86
|
+
duration: data.duration,
|
|
87
|
+
memoryUsage: data.memoryUsage
|
|
95
88
|
});
|
|
96
89
|
}
|
|
97
90
|
}
|
|
98
91
|
}
|
|
99
92
|
summarize(schedulerRunSummary) {
|
|
100
93
|
clearInterval(this.updateTimer);
|
|
101
|
-
|
|
94
|
+
this.logStream.write(terminal.clearLine);
|
|
102
95
|
const { targetRuns, targetRunByStatus, duration } = schedulerRunSummary;
|
|
103
96
|
const { failed, aborted, skipped, success, pending } = targetRunByStatus;
|
|
104
97
|
if (targetRuns.size > 0) {
|
|
105
|
-
print(colors.summary(`\nSummary`));
|
|
106
|
-
print(hrLine);
|
|
107
|
-
print(`success: ${success.length}, skipped: ${skipped.length}, pending: ${pending.length}, aborted: ${aborted.length}, failed: ${failed.length}`);
|
|
108
|
-
print(`worker restarts: ${schedulerRunSummary.workerRestarts}, max worker memory usage: ${(0,
|
|
98
|
+
this.print(colors.summary(`\nSummary`));
|
|
99
|
+
this.print(_formatHelpers.hrLine);
|
|
100
|
+
this.print(`success: ${success.length}, skipped: ${skipped.length}, pending: ${pending.length}, aborted: ${aborted.length}, failed: ${failed.length}`);
|
|
101
|
+
this.print(`worker restarts: ${schedulerRunSummary.workerRestarts}, max worker memory usage: ${(0, _formatHelpers.formatBytes)(schedulerRunSummary.maxWorkerMemoryUsage)}`);
|
|
109
102
|
} else {
|
|
110
|
-
print("Nothing has been run.");
|
|
103
|
+
this.print("Nothing has been run.");
|
|
111
104
|
}
|
|
112
|
-
print(hrLine);
|
|
105
|
+
this.print(_formatHelpers.hrLine);
|
|
113
106
|
for (const targetId of failed){
|
|
114
107
|
const target = targetRuns.get(targetId)?.target;
|
|
115
108
|
if (target) {
|
|
116
109
|
const failureLogs = this.taskData.get(targetId)?.logEntries;
|
|
117
|
-
print(`[${colors.pkg(target.packageName ?? "<root>")} ${colors.task(target.task)}] ${colors.failed("ERROR DETECTED")}`);
|
|
110
|
+
this.print(`[${colors.pkg(target.packageName ?? "<root>")} ${colors.task(target.task)}] ${colors.failed("ERROR DETECTED")}`);
|
|
118
111
|
if (failureLogs) {
|
|
119
112
|
for (const entry of failureLogs){
|
|
120
|
-
print(entry.msg);
|
|
113
|
+
this.print(entry.msg);
|
|
121
114
|
}
|
|
122
115
|
}
|
|
123
|
-
print(hrLine);
|
|
116
|
+
this.print(_formatHelpers.hrLine);
|
|
124
117
|
}
|
|
125
118
|
}
|
|
126
119
|
const allCacheHits = [
|
|
127
120
|
...targetRuns.values()
|
|
128
121
|
].filter((run)=>!run.target.hidden).length === skipped.length;
|
|
129
|
-
const allCacheHitText = allCacheHits ?
|
|
130
|
-
print(`Took a total of ${(0,
|
|
122
|
+
const allCacheHitText = allCacheHits ? (0, _formatHelpers.fancyGradient)(`All targets skipped!`) : "";
|
|
123
|
+
this.print(`Took a total of ${(0, _formatDuration.formatHrtime)(duration)} to complete. ${allCacheHitText}`);
|
|
124
|
+
}
|
|
125
|
+
/** Clear the update timer */ cleanup() {
|
|
126
|
+
clearInterval(this.updateTimer);
|
|
127
|
+
this.updateTimer = undefined;
|
|
131
128
|
}
|
|
132
129
|
reportCompletion(completion) {
|
|
133
130
|
const icon = icons[completion.status];
|
|
134
131
|
const statusColor = colors[completion.status];
|
|
135
|
-
const durationText = completion.duration ? ` (${(0,
|
|
136
|
-
const
|
|
132
|
+
const durationText = completion.duration ? ` (${(0, _formatDuration.formatHrtime)(completion.duration)})` : "";
|
|
133
|
+
const memText = (0, _formatHelpers.formatMemoryUsage)(completion.memoryUsage, this.logMemory);
|
|
134
|
+
const message = `${statusColor(`${icon} ${completion.status.padEnd(8)}`)} ${colors.label(completion.target.label)}${colors.duration(durationText + memText)}`;
|
|
137
135
|
this.renderStatus(message);
|
|
138
136
|
}
|
|
139
137
|
renderStatus(completedTaskMessage) {
|
|
@@ -156,20 +154,31 @@ class BasicReporter {
|
|
|
156
154
|
}
|
|
157
155
|
const percentage = Math.round(completed / total * 100);
|
|
158
156
|
output += `${timestamp} Completed: ${completed}/${total} (${percentage}%) [${running} running, ${pending} pending]`;
|
|
159
|
-
|
|
157
|
+
this.logStream.write(output);
|
|
158
|
+
}
|
|
159
|
+
print(message) {
|
|
160
|
+
this.logStream.write(message + "\n");
|
|
160
161
|
}
|
|
161
162
|
constructor(params = {}){
|
|
162
163
|
_define_property(this, "taskData", new Map());
|
|
163
164
|
_define_property(this, "updateTimer", void 0);
|
|
164
165
|
_define_property(this, "startTimer", void 0);
|
|
166
|
+
_define_property(this, "logMemory", void 0);
|
|
167
|
+
_define_property(this, "logStream", void 0);
|
|
165
168
|
const { concurrency = 0, version = "0.0.0", frequency = 500 } = params;
|
|
166
|
-
|
|
169
|
+
this.logMemory = !!params.logMemory;
|
|
170
|
+
this.logStream = params.logStream || process.stdout;
|
|
171
|
+
this.print(`${(0, _formatHelpers.fancyGradient)("lage")} - Version ${version} - ${concurrency} Workers`);
|
|
167
172
|
this.startTimer = ()=>{
|
|
168
173
|
this.updateTimer = setInterval(()=>this.renderStatus(), frequency);
|
|
169
174
|
this.updateTimer.unref();
|
|
170
175
|
this.startTimer = ()=>{};
|
|
171
176
|
};
|
|
172
|
-
|
|
173
|
-
|
|
177
|
+
if (!params.logStream) {
|
|
178
|
+
// Only hide and show the cursor if writing to the default stdout
|
|
179
|
+
// (definitely don't want the exit handler if writing to a custom stream)
|
|
180
|
+
process.stdout.write(terminal.hideCursor);
|
|
181
|
+
process.on("exit", ()=>process.stdout.write(terminal.showCursor));
|
|
182
|
+
}
|
|
174
183
|
}
|
|
175
184
|
}
|
package/lib/BasicReporter.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/BasicReporter.ts"],"sourcesContent":["import { type LogEntry, type Reporter } from \"@lage-run/logger\";\nimport type { SchedulerRunSummary, TargetStatus } from \"@lage-run/scheduler-types\";\nimport type { Target } from \"@lage-run/target-graph\";\nimport chalk from \"chalk\";\nimport { gradient } from \"./gradient.js\";\nimport { formatDuration, hrToSeconds } from \"@lage-run/format-hrtime\";\nimport { formatBytes } from \"./formatBytes.js\";\n\ntype CoarseStatus = \"completed\" | \"running\" | \"pending\";\n\nconst coarseStatus: Record<TargetStatus, CoarseStatus> = {\n success: \"completed\",\n failed: \"completed\",\n skipped: \"completed\",\n aborted: \"completed\",\n running: \"running\",\n pending: \"pending\",\n queued: \"pending\",\n};\n\ntype CompletionStatus = \"success\" | \"failed\" | \"skipped\" | \"aborted\";\nconst isCompletionStatus = (status: TargetStatus): status is CompletionStatus => coarseStatus[status] === \"completed\";\n\nconst colors = {\n label: chalk.white,\n timestamp: chalk.gray,\n duration: chalk.gray,\n success: chalk.green,\n failed: chalk.red,\n skipped: chalk.gray,\n aborted: chalk.yellow,\n summary: chalk.cyanBright,\n task: chalk.hex(\"#00DDDD\"),\n pkg: chalk.hex(\"#FFD66B\"),\n};\n\nconst hrLine = \"┈\".repeat(80);\n\nconst icons: Record<CompletionStatus, string> = {\n success: \"✓\",\n failed: \"✗\",\n skipped: \"-\",\n aborted: \"-\",\n};\n\nconst terminal = {\n hideCursor: \"\\x1b[?25l\",\n showCursor: \"\\x1b[?25h\",\n clearLine: \"\\x1b[2K\\r\",\n};\n\nconst fancy = (str: string) => gradient({ r: 237, g: 178, b: 77 }, \"cyan\")(str);\nconst print = (message: string) => process.stdout.write(message + \"\\n\");\n\nexport class BasicReporter implements Reporter {\n private taskData = new Map<string, { target: Target; status: TargetStatus; logEntries: LogEntry[] }>();\n private updateTimer: NodeJS.Timeout | undefined;\n private startTimer: () => void;\n\n constructor(params: { concurrency?: number; version?: string; frequency?: number } = {}) {\n const { concurrency = 0, version = \"0.0.0\", frequency = 500 } = params;\n print(`${fancy(\"lage\")} - Version ${version} - ${concurrency} Workers`);\n\n this.startTimer = () => {\n this.updateTimer = setInterval(() => this.renderStatus(), frequency);\n this.updateTimer.unref();\n this.startTimer = () => {};\n };\n\n process.stdout.write(terminal.hideCursor);\n process.on(\"exit\", () => process.stdout.write(terminal.showCursor));\n }\n\n public log(entry: LogEntry): void {\n const data = entry.data;\n if (!data?.target || data.target.hidden) return;\n\n let taskData = this.taskData.get(data.target.id);\n if (!taskData) {\n taskData = { target: data.target, status: \"pending\", logEntries: [] };\n this.taskData.set(data.target.id, taskData);\n }\n\n this.startTimer();\n taskData.logEntries.push(entry);\n\n if (data.status) {\n taskData.status = data.status;\n if (isCompletionStatus(data.status)) {\n this.reportCompletion({ target: data.target, status: data.status, duration: data.duration });\n }\n }\n }\n\n public summarize(schedulerRunSummary: SchedulerRunSummary): void {\n clearInterval(this.updateTimer);\n process.stdout.write(terminal.clearLine);\n\n const { targetRuns, targetRunByStatus, duration } = schedulerRunSummary;\n const { failed, aborted, skipped, success, pending } = targetRunByStatus;\n\n if (targetRuns.size > 0) {\n print(colors.summary(`\\nSummary`));\n print(hrLine);\n print(\n `success: ${success.length}, skipped: ${skipped.length}, pending: ${pending.length}, aborted: ${aborted.length}, failed: ${failed.length}`\n );\n print(\n `worker restarts: ${schedulerRunSummary.workerRestarts}, max worker memory usage: ${formatBytes(schedulerRunSummary.maxWorkerMemoryUsage)}`\n );\n } else {\n print(\"Nothing has been run.\");\n }\n\n print(hrLine);\n\n for (const targetId of failed) {\n const target = targetRuns.get(targetId)?.target;\n if (target) {\n const failureLogs = this.taskData.get(targetId)?.logEntries;\n\n print(`[${colors.pkg(target.packageName ?? \"<root>\")} ${colors.task(target.task)}] ${colors.failed(\"ERROR DETECTED\")}`);\n\n if (failureLogs) {\n for (const entry of failureLogs) {\n print(entry.msg);\n }\n }\n print(hrLine);\n }\n }\n\n const allCacheHits = [...targetRuns.values()].filter((run) => !run.target.hidden).length === skipped.length;\n const allCacheHitText = allCacheHits ? fancy(`All targets skipped!`) : \"\";\n\n print(`Took a total of ${formatDuration(hrToSeconds(duration))} to complete. ${allCacheHitText}`);\n }\n\n private reportCompletion(completion: { target: Target; status: CompletionStatus; duration?: [number, number] }) {\n const icon = icons[completion.status];\n const statusColor = colors[completion.status];\n const durationText = completion.duration ? ` (${formatDuration(hrToSeconds(completion.duration))})` : \"\";\n\n const message = `${statusColor(`${icon} ${completion.status.padEnd(8)}`)} ${colors.label(completion.target.label)}${colors.duration(durationText)}`;\n this.renderStatus(message);\n }\n\n private renderStatus(completedTaskMessage?: string) {\n const counts: Record<CoarseStatus, number> = { completed: 0, running: 0, pending: 0 };\n for (const data of this.taskData.values()) {\n counts[coarseStatus[data.status]]++;\n }\n const { completed, running, pending } = counts;\n const total = this.taskData.size;\n const timestamp = colors.timestamp(`[${new Date().toLocaleTimeString(\"en-US\", { hour12: false })}]`);\n\n let output = terminal.clearLine;\n if (completedTaskMessage) {\n output += `${timestamp} ${completedTaskMessage}\\n`;\n }\n const percentage = Math.round((completed / total) * 100);\n output += `${timestamp} Completed: ${completed}/${total} (${percentage}%) [${running} running, ${pending} pending]`;\n process.stdout.write(output);\n }\n}\n"],"names":["BasicReporter","coarseStatus","success","failed","skipped","aborted","running","pending","queued","isCompletionStatus","status","colors","label","chalk","white","timestamp","gray","duration","green","red","yellow","summary","cyanBright","task","hex","pkg","hrLine","repeat","icons","terminal","hideCursor","showCursor","clearLine","fancy","str","gradient","r","g","b","print","message","process","stdout","write","log","entry","data","target","hidden","taskData","get","id","logEntries","set","startTimer","push","reportCompletion","summarize","schedulerRunSummary","clearInterval","updateTimer","targetRuns","targetRunByStatus","size","length","workerRestarts","formatBytes","maxWorkerMemoryUsage","targetId","failureLogs","packageName","msg","allCacheHits","values","filter","run","allCacheHitText","formatDuration","hrToSeconds","completion","icon","statusColor","durationText","padEnd","renderStatus","completedTaskMessage","counts","completed","total","Date","toLocaleTimeString","hour12","output","percentage","Math","round","params","Map","concurrency","version","frequency","setInterval","unref","on"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../src/BasicReporter.ts"],"sourcesContent":["import type { LogEntry, Reporter } from \"@lage-run/logger\";\nimport type { SchedulerRunSummary, TargetStatus } from \"@lage-run/scheduler-types\";\nimport type { Target } from \"@lage-run/target-graph\";\nimport type { Writable } from \"stream\";\nimport chalk from \"chalk\";\nimport { formatHrtime } from \"./formatDuration.js\";\nimport { fancyGradient, formatBytes, formatMemoryUsage, hrLine } from \"./formatHelpers.js\";\n\ntype CoarseStatus = \"completed\" | \"running\" | \"pending\";\n\nconst coarseStatus: Record<TargetStatus, CoarseStatus> = {\n success: \"completed\",\n failed: \"completed\",\n skipped: \"completed\",\n aborted: \"completed\",\n running: \"running\",\n pending: \"pending\",\n queued: \"pending\",\n};\n\ntype CompletionStatus = \"success\" | \"failed\" | \"skipped\" | \"aborted\";\nconst isCompletionStatus = (status: TargetStatus): status is CompletionStatus => coarseStatus[status] === \"completed\";\n\nconst colors = {\n label: chalk.white,\n timestamp: chalk.gray,\n duration: chalk.gray,\n success: chalk.green,\n failed: chalk.red,\n skipped: chalk.gray,\n aborted: chalk.yellow,\n summary: chalk.cyanBright,\n task: chalk.hex(\"#00DDDD\"),\n pkg: chalk.hex(\"#FFD66B\"),\n};\n\nconst icons: Record<CompletionStatus, string> = {\n success: \"✓\",\n failed: \"✗\",\n skipped: \"-\",\n aborted: \"-\",\n};\n\nconst terminal = {\n hideCursor: \"\\x1b[?25l\",\n showCursor: \"\\x1b[?25h\",\n clearLine: \"\\x1b[2K\\r\",\n};\n\n/**\n * Shows running/remaining target counts and completed targets, but does not display\n * the names of running targets for efficiency.\n */\nexport class BasicReporter implements Reporter {\n private taskData = new Map<string, { target: Target; status: TargetStatus; logEntries: LogEntry[] }>();\n private updateTimer: NodeJS.Timeout | undefined;\n private startTimer: () => void;\n private logMemory: boolean;\n private logStream: Writable;\n\n constructor(\n params: {\n concurrency?: number;\n version?: string;\n frequency?: number;\n /** Whether to capture and report main process memory usage on target completion */\n logMemory?: boolean;\n /** Stream for output (defaults to process.stdout) */\n logStream?: Writable;\n } = {}\n ) {\n const { concurrency = 0, version = \"0.0.0\", frequency = 500 } = params;\n this.logMemory = !!params.logMemory;\n this.logStream = params.logStream || process.stdout;\n this.print(`${fancyGradient(\"lage\")} - Version ${version} - ${concurrency} Workers`);\n\n this.startTimer = () => {\n this.updateTimer = setInterval(() => this.renderStatus(), frequency);\n this.updateTimer.unref();\n this.startTimer = () => {};\n };\n\n if (!params.logStream) {\n // Only hide and show the cursor if writing to the default stdout\n // (definitely don't want the exit handler if writing to a custom stream)\n process.stdout.write(terminal.hideCursor);\n process.on(\"exit\", () => process.stdout.write(terminal.showCursor));\n }\n }\n\n public log(entry: LogEntry): void {\n const data = entry.data;\n if (!data?.target || data.target.hidden) return;\n\n let taskData = this.taskData.get(data.target.id);\n if (!taskData) {\n taskData = { target: data.target, status: \"pending\", logEntries: [] };\n this.taskData.set(data.target.id, taskData);\n }\n\n this.startTimer();\n taskData.logEntries.push(entry);\n\n if (data.status) {\n taskData.status = data.status;\n if (isCompletionStatus(data.status)) {\n this.reportCompletion({ target: data.target, status: data.status, duration: data.duration, memoryUsage: data.memoryUsage });\n }\n }\n }\n\n public summarize(schedulerRunSummary: SchedulerRunSummary): void {\n clearInterval(this.updateTimer);\n this.logStream.write(terminal.clearLine);\n\n const { targetRuns, targetRunByStatus, duration } = schedulerRunSummary;\n const { failed, aborted, skipped, success, pending } = targetRunByStatus;\n\n if (targetRuns.size > 0) {\n this.print(colors.summary(`\\nSummary`));\n this.print(hrLine);\n this.print(\n `success: ${success.length}, skipped: ${skipped.length}, pending: ${pending.length}, aborted: ${aborted.length}, failed: ${failed.length}`\n );\n this.print(\n `worker restarts: ${schedulerRunSummary.workerRestarts}, max worker memory usage: ${formatBytes(schedulerRunSummary.maxWorkerMemoryUsage)}`\n );\n } else {\n this.print(\"Nothing has been run.\");\n }\n\n this.print(hrLine);\n\n for (const targetId of failed) {\n const target = targetRuns.get(targetId)?.target;\n if (target) {\n const failureLogs = this.taskData.get(targetId)?.logEntries;\n\n this.print(`[${colors.pkg(target.packageName ?? \"<root>\")} ${colors.task(target.task)}] ${colors.failed(\"ERROR DETECTED\")}`);\n\n if (failureLogs) {\n for (const entry of failureLogs) {\n this.print(entry.msg);\n }\n }\n this.print(hrLine);\n }\n }\n\n const allCacheHits = [...targetRuns.values()].filter((run) => !run.target.hidden).length === skipped.length;\n const allCacheHitText = allCacheHits ? fancyGradient(`All targets skipped!`) : \"\";\n\n this.print(`Took a total of ${formatHrtime(duration)} to complete. ${allCacheHitText}`);\n }\n\n /** Clear the update timer */\n public cleanup(): void {\n clearInterval(this.updateTimer);\n this.updateTimer = undefined;\n }\n\n private reportCompletion(completion: {\n target: Target;\n status: CompletionStatus;\n duration?: [number, number];\n memoryUsage?: NodeJS.MemoryUsage;\n }) {\n const icon = icons[completion.status];\n const statusColor = colors[completion.status];\n const durationText = completion.duration ? ` (${formatHrtime(completion.duration)})` : \"\";\n const memText = formatMemoryUsage(completion.memoryUsage, this.logMemory);\n\n const message = `${statusColor(`${icon} ${completion.status.padEnd(8)}`)} ${colors.label(completion.target.label)}${colors.duration(durationText + memText)}`;\n this.renderStatus(message);\n }\n\n private renderStatus(completedTaskMessage?: string) {\n const counts: Record<CoarseStatus, number> = { completed: 0, running: 0, pending: 0 };\n for (const data of this.taskData.values()) {\n counts[coarseStatus[data.status]]++;\n }\n const { completed, running, pending } = counts;\n const total = this.taskData.size;\n const timestamp = colors.timestamp(`[${new Date().toLocaleTimeString(\"en-US\", { hour12: false })}]`);\n\n let output = terminal.clearLine;\n if (completedTaskMessage) {\n output += `${timestamp} ${completedTaskMessage}\\n`;\n }\n const percentage = Math.round((completed / total) * 100);\n output += `${timestamp} Completed: ${completed}/${total} (${percentage}%) [${running} running, ${pending} pending]`;\n this.logStream.write(output);\n }\n\n private print(message: string): void {\n this.logStream.write(message + \"\\n\");\n }\n}\n"],"names":["BasicReporter","coarseStatus","success","failed","skipped","aborted","running","pending","queued","isCompletionStatus","status","colors","label","chalk","white","timestamp","gray","duration","green","red","yellow","summary","cyanBright","task","hex","pkg","icons","terminal","hideCursor","showCursor","clearLine","log","entry","data","target","hidden","taskData","get","id","logEntries","set","startTimer","push","reportCompletion","memoryUsage","summarize","schedulerRunSummary","clearInterval","updateTimer","logStream","write","targetRuns","targetRunByStatus","size","print","hrLine","length","workerRestarts","formatBytes","maxWorkerMemoryUsage","targetId","failureLogs","packageName","msg","allCacheHits","values","filter","run","allCacheHitText","fancyGradient","formatHrtime","cleanup","undefined","completion","icon","statusColor","durationText","memText","formatMemoryUsage","logMemory","message","padEnd","renderStatus","completedTaskMessage","counts","completed","total","Date","toLocaleTimeString","hour12","output","percentage","Math","round","params","Map","concurrency","version","frequency","process","stdout","setInterval","unref","on"],"mappings":";;;;+BAqDaA;;;eAAAA;;;8DAjDK;gCACW;+BACyC;;;;;;;;;;;;;;;;;;;AAItE,MAAMC,eAAmD;IACvDC,SAAS;IACTC,QAAQ;IACRC,SAAS;IACTC,SAAS;IACTC,SAAS;IACTC,SAAS;IACTC,QAAQ;AACV;AAGA,MAAMC,qBAAqB,CAACC,SAAqDT,YAAY,CAACS,OAAO,KAAK;AAE1G,MAAMC,SAAS;IACbC,OAAOC,cAAK,CAACC,KAAK;IAClBC,WAAWF,cAAK,CAACG,IAAI;IACrBC,UAAUJ,cAAK,CAACG,IAAI;IACpBd,SAASW,cAAK,CAACK,KAAK;IACpBf,QAAQU,cAAK,CAACM,GAAG;IACjBf,SAASS,cAAK,CAACG,IAAI;IACnBX,SAASQ,cAAK,CAACO,MAAM;IACrBC,SAASR,cAAK,CAACS,UAAU;IACzBC,MAAMV,cAAK,CAACW,GAAG,CAAC;IAChBC,KAAKZ,cAAK,CAACW,GAAG,CAAC;AACjB;AAEA,MAAME,QAA0C;IAC9CxB,SAAS;IACTC,QAAQ;IACRC,SAAS;IACTC,SAAS;AACX;AAEA,MAAMsB,WAAW;IACfC,YAAY;IACZC,YAAY;IACZC,WAAW;AACb;AAMO,MAAM9B;IAqCJ+B,IAAIC,KAAe,EAAQ;QAChC,MAAMC,OAAOD,MAAMC,IAAI;QACvB,IAAI,CAACA,MAAMC,UAAUD,KAAKC,MAAM,CAACC,MAAM,EAAE;QAEzC,IAAIC,WAAW,IAAI,CAACA,QAAQ,CAACC,GAAG,CAACJ,KAAKC,MAAM,CAACI,EAAE;QAC/C,IAAI,CAACF,UAAU;YACbA,WAAW;gBAAEF,QAAQD,KAAKC,MAAM;gBAAExB,QAAQ;gBAAW6B,YAAY,EAAE;YAAC;YACpE,IAAI,CAACH,QAAQ,CAACI,GAAG,CAACP,KAAKC,MAAM,CAACI,EAAE,EAAEF;QACpC;QAEA,IAAI,CAACK,UAAU;QACfL,SAASG,UAAU,CAACG,IAAI,CAACV;QAEzB,IAAIC,KAAKvB,MAAM,EAAE;YACf0B,SAAS1B,MAAM,GAAGuB,KAAKvB,MAAM;YAC7B,IAAID,mBAAmBwB,KAAKvB,MAAM,GAAG;gBACnC,IAAI,CAACiC,gBAAgB,CAAC;oBAAET,QAAQD,KAAKC,MAAM;oBAAExB,QAAQuB,KAAKvB,MAAM;oBAAEO,UAAUgB,KAAKhB,QAAQ;oBAAE2B,aAAaX,KAAKW,WAAW;gBAAC;YAC3H;QACF;IACF;IAEOC,UAAUC,mBAAwC,EAAQ;QAC/DC,cAAc,IAAI,CAACC,WAAW;QAC9B,IAAI,CAACC,SAAS,CAACC,KAAK,CAACvB,SAASG,SAAS;QAEvC,MAAM,EAAEqB,UAAU,EAAEC,iBAAiB,EAAEnC,QAAQ,EAAE,GAAG6B;QACpD,MAAM,EAAE3C,MAAM,EAAEE,OAAO,EAAED,OAAO,EAAEF,OAAO,EAAEK,OAAO,EAAE,GAAG6C;QAEvD,IAAID,WAAWE,IAAI,GAAG,GAAG;YACvB,IAAI,CAACC,KAAK,CAAC3C,OAAOU,OAAO,CAAC,CAAC,SAAS,CAAC;YACrC,IAAI,CAACiC,KAAK,CAACC,qBAAM;YACjB,IAAI,CAACD,KAAK,CACR,CAAC,SAAS,EAAEpD,QAAQsD,MAAM,CAAC,WAAW,EAAEpD,QAAQoD,MAAM,CAAC,WAAW,EAAEjD,QAAQiD,MAAM,CAAC,WAAW,EAAEnD,QAAQmD,MAAM,CAAC,UAAU,EAAErD,OAAOqD,MAAM,EAAE;YAE5I,IAAI,CAACF,KAAK,CACR,CAAC,iBAAiB,EAAER,oBAAoBW,cAAc,CAAC,2BAA2B,EAAEC,IAAAA,0BAAW,EAACZ,oBAAoBa,oBAAoB,GAAG;QAE/I,OAAO;YACL,IAAI,CAACL,KAAK,CAAC;QACb;QAEA,IAAI,CAACA,KAAK,CAACC,qBAAM;QAEjB,KAAK,MAAMK,YAAYzD,OAAQ;YAC7B,MAAM+B,SAASiB,WAAWd,GAAG,CAACuB,WAAW1B;YACzC,IAAIA,QAAQ;gBACV,MAAM2B,cAAc,IAAI,CAACzB,QAAQ,CAACC,GAAG,CAACuB,WAAWrB;gBAEjD,IAAI,CAACe,KAAK,CAAC,CAAC,CAAC,EAAE3C,OAAOc,GAAG,CAACS,OAAO4B,WAAW,IAAI,UAAU,CAAC,EAAEnD,OAAOY,IAAI,CAACW,OAAOX,IAAI,EAAE,EAAE,EAAEZ,OAAOR,MAAM,CAAC,mBAAmB;gBAE3H,IAAI0D,aAAa;oBACf,KAAK,MAAM7B,SAAS6B,YAAa;wBAC/B,IAAI,CAACP,KAAK,CAACtB,MAAM+B,GAAG;oBACtB;gBACF;gBACA,IAAI,CAACT,KAAK,CAACC,qBAAM;YACnB;QACF;QAEA,MAAMS,eAAe;eAAIb,WAAWc,MAAM;SAAG,CAACC,MAAM,CAAC,CAACC,MAAQ,CAACA,IAAIjC,MAAM,CAACC,MAAM,EAAEqB,MAAM,KAAKpD,QAAQoD,MAAM;QAC3G,MAAMY,kBAAkBJ,eAAeK,IAAAA,4BAAa,EAAC,CAAC,oBAAoB,CAAC,IAAI;QAE/E,IAAI,CAACf,KAAK,CAAC,CAAC,gBAAgB,EAAEgB,IAAAA,4BAAY,EAACrD,UAAU,cAAc,EAAEmD,iBAAiB;IACxF;IAEA,2BAA2B,GAC3B,AAAOG,UAAgB;QACrBxB,cAAc,IAAI,CAACC,WAAW;QAC9B,IAAI,CAACA,WAAW,GAAGwB;IACrB;IAEQ7B,iBAAiB8B,UAKxB,EAAE;QACD,MAAMC,OAAOhD,KAAK,CAAC+C,WAAW/D,MAAM,CAAC;QACrC,MAAMiE,cAAchE,MAAM,CAAC8D,WAAW/D,MAAM,CAAC;QAC7C,MAAMkE,eAAeH,WAAWxD,QAAQ,GAAG,CAAC,EAAE,EAAEqD,IAAAA,4BAAY,EAACG,WAAWxD,QAAQ,EAAE,CAAC,CAAC,GAAG;QACvF,MAAM4D,UAAUC,IAAAA,gCAAiB,EAACL,WAAW7B,WAAW,EAAE,IAAI,CAACmC,SAAS;QAExE,MAAMC,UAAU,GAAGL,YAAY,GAAGD,KAAK,CAAC,EAAED,WAAW/D,MAAM,CAACuE,MAAM,CAAC,IAAI,EAAE,CAAC,EAAEtE,OAAOC,KAAK,CAAC6D,WAAWvC,MAAM,CAACtB,KAAK,IAAID,OAAOM,QAAQ,CAAC2D,eAAeC,UAAU;QAC7J,IAAI,CAACK,YAAY,CAACF;IACpB;IAEQE,aAAaC,oBAA6B,EAAE;QAClD,MAAMC,SAAuC;YAAEC,WAAW;YAAG/E,SAAS;YAAGC,SAAS;QAAE;QACpF,KAAK,MAAM0B,QAAQ,IAAI,CAACG,QAAQ,CAAC6B,MAAM,GAAI;YACzCmB,MAAM,CAACnF,YAAY,CAACgC,KAAKvB,MAAM,CAAC,CAAC;QACnC;QACA,MAAM,EAAE2E,SAAS,EAAE/E,OAAO,EAAEC,OAAO,EAAE,GAAG6E;QACxC,MAAME,QAAQ,IAAI,CAAClD,QAAQ,CAACiB,IAAI;QAChC,MAAMtC,YAAYJ,OAAOI,SAAS,CAAC,CAAC,CAAC,EAAE,IAAIwE,OAAOC,kBAAkB,CAAC,SAAS;YAAEC,QAAQ;QAAM,GAAG,CAAC,CAAC;QAEnG,IAAIC,SAAS/D,SAASG,SAAS;QAC/B,IAAIqD,sBAAsB;YACxBO,UAAU,GAAG3E,UAAU,CAAC,EAAEoE,qBAAqB,EAAE,CAAC;QACpD;QACA,MAAMQ,aAAaC,KAAKC,KAAK,CAAC,AAACR,YAAYC,QAAS;QACpDI,UAAU,GAAG3E,UAAU,YAAY,EAAEsE,UAAU,CAAC,EAAEC,MAAM,EAAE,EAAEK,WAAW,IAAI,EAAErF,QAAQ,UAAU,EAAEC,QAAQ,SAAS,CAAC;QACnH,IAAI,CAAC0C,SAAS,CAACC,KAAK,CAACwC;IACvB;IAEQpC,MAAM0B,OAAe,EAAQ;QACnC,IAAI,CAAC/B,SAAS,CAACC,KAAK,CAAC8B,UAAU;IACjC;IAxIA,YACEc,SAQI,CAAC,CAAC,CACN;QAhBF,uBAAQ1D,YAAW,IAAI2D;QACvB,uBAAQ/C,eAAR,KAAA;QACA,uBAAQP,cAAR,KAAA;QACA,uBAAQsC,aAAR,KAAA;QACA,uBAAQ9B,aAAR,KAAA;QAaE,MAAM,EAAE+C,cAAc,CAAC,EAAEC,UAAU,OAAO,EAAEC,YAAY,GAAG,EAAE,GAAGJ;QAChE,IAAI,CAACf,SAAS,GAAG,CAAC,CAACe,OAAOf,SAAS;QACnC,IAAI,CAAC9B,SAAS,GAAG6C,OAAO7C,SAAS,IAAIkD,QAAQC,MAAM;QACnD,IAAI,CAAC9C,KAAK,CAAC,GAAGe,IAAAA,4BAAa,EAAC,QAAQ,WAAW,EAAE4B,QAAQ,GAAG,EAAED,YAAY,QAAQ,CAAC;QAEnF,IAAI,CAACvD,UAAU,GAAG;YAChB,IAAI,CAACO,WAAW,GAAGqD,YAAY,IAAM,IAAI,CAACnB,YAAY,IAAIgB;YAC1D,IAAI,CAAClD,WAAW,CAACsD,KAAK;YACtB,IAAI,CAAC7D,UAAU,GAAG,KAAO;QAC3B;QAEA,IAAI,CAACqD,OAAO7C,SAAS,EAAE;YACrB,iEAAiE;YACjE,yEAAyE;YACzEkD,QAAQC,MAAM,CAAClD,KAAK,CAACvB,SAASC,UAAU;YACxCuE,QAAQI,EAAE,CAAC,QAAQ,IAAMJ,QAAQC,MAAM,CAAClD,KAAK,CAACvB,SAASE,UAAU;QACnE;IACF;AA6GF"}
|
|
@@ -6,6 +6,9 @@ export interface ChromeTraceEventsReporterOptions {
|
|
|
6
6
|
concurrency: number;
|
|
7
7
|
categorize?: (targetRun?: TargetRun) => string;
|
|
8
8
|
}
|
|
9
|
+
/**
|
|
10
|
+
* Reporter that generates a Chrome dev tools profile file.
|
|
11
|
+
*/
|
|
9
12
|
export declare class ChromeTraceEventsReporter implements Reporter {
|
|
10
13
|
private options;
|
|
11
14
|
private consoleLogStream;
|
|
@@ -69,11 +69,10 @@ class ChromeTraceEventsReporter {
|
|
|
69
69
|
}
|
|
70
70
|
this.events.traceEvents.push(event);
|
|
71
71
|
}
|
|
72
|
-
if (
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
72
|
+
// make the directory if it doesn't exist (no-op if exists)
|
|
73
|
+
_fs.default.mkdirSync(_path.default.dirname(this.outputFile), {
|
|
74
|
+
recursive: true
|
|
75
|
+
});
|
|
77
76
|
_fs.default.writeFileSync(this.outputFile, JSON.stringify(this.events, null, 2));
|
|
78
77
|
this.consoleLogStream.write(_chalk.default.blueBright(`\nProfiler output written to ${_chalk.default.underline(this.outputFile)}, open it with chrome://tracing or edge://tracing\n`));
|
|
79
78
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/ChromeTraceEventsReporter.ts"],"sourcesContent":["import chalk from \"chalk\";\nimport fs from \"fs\";\nimport path from \"path\";\nimport type { Reporter } from \"@lage-run/logger\";\nimport type { SchedulerRunSummary, TargetRun } from \"@lage-run/scheduler-types\";\nimport type { Writable } from \"stream\";\n\ninterface TraceEventsObject {\n traceEvents: CompleteEvent[];\n displayTimeUnit: \"ms\" | \"ns\";\n}\n\ninterface CompleteEvent {\n name: string;\n cat: string; // status#task\n ph: \"X\";\n ts: number; // in microseconds\n pid: number;\n tid: number;\n dur: number;\n args?: Record<string, any>;\n}\n\nexport interface ChromeTraceEventsReporterOptions {\n outputFile?: string;\n concurrency: number;\n categorize?: (targetRun?: TargetRun) => string;\n}\n\nfunction hrTimeToMicroseconds(hr: [number, number]) {\n return hr[0] * 1e6 + hr[1] * 1e-3;\n}\n\nfunction getTimeBasedFilename(prefix: string) {\n const now = new Date(); // 2011-10-05T14:48:00.000Z\n const datetime = now.toISOString().split(\".\")[0]; // 2011-10-05T14:48:00\n const datetimeNormalized = datetime.replace(/-|:/g, \"\"); // 20111005T144800\n return `${prefix ? prefix + \"-\" : \"\"}${datetimeNormalized}.json`;\n}\n\nexport class ChromeTraceEventsReporter implements Reporter {\n private consoleLogStream: Writable;\n\n private events: TraceEventsObject = {\n traceEvents: [],\n displayTimeUnit: \"ms\",\n };\n private outputFile: string;\n\n constructor(\n private options: ChromeTraceEventsReporterOptions & {\n /** stream for testing */\n consoleLogStream?: Writable;\n }\n ) {\n this.outputFile = options.outputFile ?? getTimeBasedFilename(\"profile\");\n this.consoleLogStream = options.consoleLogStream ?? process.stdout;\n }\n\n public log(): void {\n // pass\n }\n\n public summarize(schedulerRunSummary: SchedulerRunSummary): void {\n const { targetRuns, startTime } = schedulerRunSummary;\n\n // categorize events\n const { categorize } = this.options;\n\n for (const targetRun of targetRuns.values()) {\n // Skip hidden targets because those should be hidden by reporters.\n // Hiding as well skipped targets to avoid polluting the profile.\n if (targetRun.target.hidden || targetRun.status === \"skipped\") {\n continue;\n }\n\n const event = {\n name: targetRun.target.id,\n cat: `${targetRun.status}#${targetRun.target.task}`,\n ph: \"X\",\n ts: hrTimeToMicroseconds(targetRun.startTime) - hrTimeToMicroseconds(startTime), // in microseconds\n dur: hrTimeToMicroseconds(targetRun.duration ?? [0, 1000]), // in microseconds\n pid: 1,\n tid: targetRun.threadId,\n }
|
|
1
|
+
{"version":3,"sources":["../src/ChromeTraceEventsReporter.ts"],"sourcesContent":["import chalk from \"chalk\";\nimport fs from \"fs\";\nimport path from \"path\";\nimport type { Reporter } from \"@lage-run/logger\";\nimport type { SchedulerRunSummary, TargetRun } from \"@lage-run/scheduler-types\";\nimport type { Writable } from \"stream\";\n\ninterface TraceEventsObject {\n traceEvents: CompleteEvent[];\n displayTimeUnit: \"ms\" | \"ns\";\n}\n\ninterface CompleteEvent {\n name: string;\n cat: string; // status#task\n ph: \"X\";\n ts: number; // in microseconds\n pid: number;\n tid: number;\n dur: number;\n args?: Record<string, any>;\n}\n\nexport interface ChromeTraceEventsReporterOptions {\n outputFile?: string;\n concurrency: number;\n categorize?: (targetRun?: TargetRun) => string;\n}\n\nfunction hrTimeToMicroseconds(hr: [number, number]) {\n return hr[0] * 1e6 + hr[1] * 1e-3;\n}\n\nfunction getTimeBasedFilename(prefix: string) {\n const now = new Date(); // 2011-10-05T14:48:00.000Z\n const datetime = now.toISOString().split(\".\")[0]; // 2011-10-05T14:48:00\n const datetimeNormalized = datetime.replace(/-|:/g, \"\"); // 20111005T144800\n return `${prefix ? prefix + \"-\" : \"\"}${datetimeNormalized}.json`;\n}\n\n/**\n * Reporter that generates a Chrome dev tools profile file.\n */\nexport class ChromeTraceEventsReporter implements Reporter {\n private consoleLogStream: Writable;\n\n private events: TraceEventsObject = {\n traceEvents: [],\n displayTimeUnit: \"ms\",\n };\n private outputFile: string;\n\n constructor(\n private options: ChromeTraceEventsReporterOptions & {\n /** stream for testing */\n consoleLogStream?: Writable;\n }\n ) {\n this.outputFile = options.outputFile ?? getTimeBasedFilename(\"profile\");\n this.consoleLogStream = options.consoleLogStream ?? process.stdout;\n }\n\n public log(): void {\n // pass\n }\n\n public summarize(schedulerRunSummary: SchedulerRunSummary): void {\n const { targetRuns, startTime } = schedulerRunSummary;\n\n // categorize events\n const { categorize } = this.options;\n\n for (const targetRun of targetRuns.values()) {\n // Skip hidden targets because those should be hidden by reporters.\n // Hiding as well skipped targets to avoid polluting the profile.\n if (targetRun.target.hidden || targetRun.status === \"skipped\") {\n continue;\n }\n\n const event: CompleteEvent = {\n name: targetRun.target.id,\n cat: `${targetRun.status}#${targetRun.target.task}`,\n ph: \"X\",\n ts: hrTimeToMicroseconds(targetRun.startTime) - hrTimeToMicroseconds(startTime), // in microseconds\n dur: hrTimeToMicroseconds(targetRun.duration ?? [0, 1000]), // in microseconds\n pid: 1,\n tid: targetRun.threadId,\n };\n\n if (categorize) {\n event.cat += `,${categorize(targetRun)}`;\n }\n\n this.events.traceEvents.push(event);\n }\n\n // make the directory if it doesn't exist (no-op if exists)\n fs.mkdirSync(path.dirname(this.outputFile), { recursive: true });\n\n fs.writeFileSync(this.outputFile, JSON.stringify(this.events, null, 2));\n\n this.consoleLogStream.write(\n chalk.blueBright(\n `\\nProfiler output written to ${chalk.underline(this.outputFile)}, open it with chrome://tracing or edge://tracing\\n`\n )\n );\n }\n}\n"],"names":["ChromeTraceEventsReporter","hrTimeToMicroseconds","hr","getTimeBasedFilename","prefix","now","Date","datetime","toISOString","split","datetimeNormalized","replace","log","summarize","schedulerRunSummary","targetRuns","startTime","categorize","options","targetRun","values","target","hidden","status","event","name","id","cat","task","ph","ts","dur","duration","pid","tid","threadId","events","traceEvents","push","fs","mkdirSync","path","dirname","outputFile","recursive","writeFileSync","JSON","stringify","consoleLogStream","write","chalk","blueBright","underline","displayTimeUnit","process","stdout"],"mappings":";;;;+BA2CaA;;;eAAAA;;;8DA3CK;2DACH;6DACE;;;;;;;;;;;;;;;;;;;AA2BjB,SAASC,qBAAqBC,EAAoB;IAChD,OAAOA,EAAE,CAAC,EAAE,GAAG,MAAMA,EAAE,CAAC,EAAE,GAAG;AAC/B;AAEA,SAASC,qBAAqBC,MAAc;IAC1C,MAAMC,MAAM,IAAIC,QAAQ,2BAA2B;IACnD,MAAMC,WAAWF,IAAIG,WAAW,GAAGC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,sBAAsB;IACxE,MAAMC,qBAAqBH,SAASI,OAAO,CAAC,QAAQ,KAAK,kBAAkB;IAC3E,OAAO,GAAGP,SAASA,SAAS,MAAM,KAAKM,mBAAmB,KAAK,CAAC;AAClE;AAKO,MAAMV;IAmBJY,MAAY;IACjB,OAAO;IACT;IAEOC,UAAUC,mBAAwC,EAAQ;QAC/D,MAAM,EAAEC,UAAU,EAAEC,SAAS,EAAE,GAAGF;QAElC,oBAAoB;QACpB,MAAM,EAAEG,UAAU,EAAE,GAAG,IAAI,CAACC,OAAO;QAEnC,KAAK,MAAMC,aAAaJ,WAAWK,MAAM,GAAI;YAC3C,mEAAmE;YACnE,iEAAiE;YACjE,IAAID,UAAUE,MAAM,CAACC,MAAM,IAAIH,UAAUI,MAAM,KAAK,WAAW;gBAC7D;YACF;YAEA,MAAMC,QAAuB;gBAC3BC,MAAMN,UAAUE,MAAM,CAACK,EAAE;gBACzBC,KAAK,GAAGR,UAAUI,MAAM,CAAC,CAAC,EAAEJ,UAAUE,MAAM,CAACO,IAAI,EAAE;gBACnDC,IAAI;gBACJC,IAAI7B,qBAAqBkB,UAAUH,SAAS,IAAIf,qBAAqBe;gBACrEe,KAAK9B,qBAAqBkB,UAAUa,QAAQ,IAAI;oBAAC;oBAAG;iBAAK;gBACzDC,KAAK;gBACLC,KAAKf,UAAUgB,QAAQ;YACzB;YAEA,IAAIlB,YAAY;gBACdO,MAAMG,GAAG,IAAI,CAAC,CAAC,EAAEV,WAAWE,YAAY;YAC1C;YAEA,IAAI,CAACiB,MAAM,CAACC,WAAW,CAACC,IAAI,CAACd;QAC/B;QAEA,2DAA2D;QAC3De,WAAE,CAACC,SAAS,CAACC,aAAI,CAACC,OAAO,CAAC,IAAI,CAACC,UAAU,GAAG;YAAEC,WAAW;QAAK;QAE9DL,WAAE,CAACM,aAAa,CAAC,IAAI,CAACF,UAAU,EAAEG,KAAKC,SAAS,CAAC,IAAI,CAACX,MAAM,EAAE,MAAM;QAEpE,IAAI,CAACY,gBAAgB,CAACC,KAAK,CACzBC,cAAK,CAACC,UAAU,CACd,CAAC,6BAA6B,EAAED,cAAK,CAACE,SAAS,CAAC,IAAI,CAACT,UAAU,EAAE,mDAAmD,CAAC;IAG3H;IAtDA,YACE,AAAQzB,OAGP,CACD;;QAbF,uBAAQ8B,oBAAR,KAAA;QAEA,uBAAQZ,UAAR,KAAA;QAIA,uBAAQO,cAAR,KAAA;aAGUzB,UAAAA;aAPFkB,SAA4B;YAClCC,aAAa,EAAE;YACfgB,iBAAiB;QACnB;QASE,IAAI,CAACV,UAAU,GAAGzB,QAAQyB,UAAU,IAAIxC,qBAAqB;QAC7D,IAAI,CAAC6C,gBAAgB,GAAG9B,QAAQ8B,gBAAgB,IAAIM,QAAQC,MAAM;IACpE;AA+CF"}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type { TargetRun } from "@lage-run/scheduler-types";
|
|
2
2
|
import { GroupedReporter } from "./GroupedReporter.js";
|
|
3
|
+
/**
|
|
4
|
+
* Reporter that formats logs for GitHub Actions, optionally with grouping.
|
|
5
|
+
*/
|
|
3
6
|
export declare class GithubActionsReporter extends GroupedReporter {
|
|
4
7
|
protected formatGroupStart(packageName: string, task: string, status: string, duration?: [number, number]): string;
|
|
5
8
|
protected formatGroupEnd(): string;
|
|
@@ -8,11 +8,11 @@ Object.defineProperty(exports, "GithubActionsReporter", {
|
|
|
8
8
|
return GithubActionsReporter;
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
|
-
const
|
|
11
|
+
const _formatDuration = require("./formatDuration.js");
|
|
12
12
|
const _GroupedReporter = require("./GroupedReporter.js");
|
|
13
13
|
class GithubActionsReporter extends _GroupedReporter.GroupedReporter {
|
|
14
14
|
formatGroupStart(packageName, task, status, duration) {
|
|
15
|
-
return `::group::${packageName} ${task} ${status}${duration ? `, took ${(0,
|
|
15
|
+
return `::group::${packageName} ${task} ${status}${duration ? `, took ${(0, _formatDuration.formatHrtime)(duration)}` : ""}\n`;
|
|
16
16
|
}
|
|
17
17
|
formatGroupEnd() {
|
|
18
18
|
return `::endgroup::\n`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/GithubActionsReporter.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"sources":["../src/GithubActionsReporter.ts"],"sourcesContent":["import { formatHrtime } from \"./formatDuration.js\";\nimport type { TargetRun } from \"@lage-run/scheduler-types\";\nimport { GroupedReporter } from \"./GroupedReporter.js\";\n\n/**\n * Reporter that formats logs for GitHub Actions, optionally with grouping.\n */\nexport class GithubActionsReporter extends GroupedReporter {\n protected formatGroupStart(packageName: string, task: string, status: string, duration?: [number, number]): string {\n return `::group::${packageName} ${task} ${status}${duration ? `, took ${formatHrtime(duration)}` : \"\"}\\n`;\n }\n\n protected formatGroupEnd(): string {\n return `::endgroup::\\n`;\n }\n\n protected writeSummaryHeader(): void {\n this.logStream.write(`::group::Summary\\n`);\n }\n\n protected writeSummaryFooter(): void {\n this.logStream.write(`::endgroup::\\n`);\n }\n\n protected writeFailures(failed: string[], targetRuns: Map<string, TargetRun<unknown>>): void {\n for (const targetId of failed) {\n const target = targetRuns.get(targetId)?.target;\n\n if (target) {\n const { packageName, task } = target;\n const taskLogs = this.logEntries.get(targetId);\n\n this.logStream.write(`::error title=${packageName} ${task}::Build failed\\n`);\n\n if (taskLogs) {\n for (const entry of taskLogs) {\n if (entry.msg.trim() !== \"\") {\n this.logStream.write(`::error::${entry.msg}\\n`);\n }\n }\n }\n }\n }\n }\n}\n"],"names":["GithubActionsReporter","GroupedReporter","formatGroupStart","packageName","task","status","duration","formatHrtime","formatGroupEnd","writeSummaryHeader","logStream","write","writeSummaryFooter","writeFailures","failed","targetRuns","targetId","target","get","taskLogs","logEntries","entry","msg","trim"],"mappings":";;;;+BAOaA;;;eAAAA;;;gCAPgB;iCAEG;AAKzB,MAAMA,8BAA8BC,gCAAe;IAC9CC,iBAAiBC,WAAmB,EAAEC,IAAY,EAAEC,MAAc,EAAEC,QAA2B,EAAU;QACjH,OAAO,CAAC,SAAS,EAAEH,YAAY,CAAC,EAAEC,KAAK,CAAC,EAAEC,SAASC,WAAW,CAAC,OAAO,EAAEC,IAAAA,4BAAY,EAACD,WAAW,GAAG,GAAG,EAAE,CAAC;IAC3G;IAEUE,iBAAyB;QACjC,OAAO,CAAC,cAAc,CAAC;IACzB;IAEUC,qBAA2B;QACnC,IAAI,CAACC,SAAS,CAACC,KAAK,CAAC,CAAC,kBAAkB,CAAC;IAC3C;IAEUC,qBAA2B;QACnC,IAAI,CAACF,SAAS,CAACC,KAAK,CAAC,CAAC,cAAc,CAAC;IACvC;IAEUE,cAAcC,MAAgB,EAAEC,UAA2C,EAAQ;QAC3F,KAAK,MAAMC,YAAYF,OAAQ;YAC7B,MAAMG,SAASF,WAAWG,GAAG,CAACF,WAAWC;YAEzC,IAAIA,QAAQ;gBACV,MAAM,EAAEd,WAAW,EAAEC,IAAI,EAAE,GAAGa;gBAC9B,MAAME,WAAW,IAAI,CAACC,UAAU,CAACF,GAAG,CAACF;gBAErC,IAAI,CAACN,SAAS,CAACC,KAAK,CAAC,CAAC,cAAc,EAAER,YAAY,CAAC,EAAEC,KAAK,gBAAgB,CAAC;gBAE3E,IAAIe,UAAU;oBACZ,KAAK,MAAME,SAASF,SAAU;wBAC5B,IAAIE,MAAMC,GAAG,CAACC,IAAI,OAAO,IAAI;4BAC3B,IAAI,CAACb,SAAS,CAACC,KAAK,CAAC,CAAC,SAAS,EAAEU,MAAMC,GAAG,CAAC,EAAE,CAAC;wBAChD;oBACF;gBACF;YACF;QACF;IACF;AACF"}
|
package/lib/GroupedReporter.d.ts
CHANGED
|
@@ -16,19 +16,16 @@ export declare const colors: {
|
|
|
16
16
|
error: chalk.Chalk;
|
|
17
17
|
warn: chalk.Chalk;
|
|
18
18
|
};
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
50: string;
|
|
24
|
-
40: string;
|
|
25
|
-
};
|
|
26
|
-
export declare function getTaskLogPrefix(pkg: string, task: string): string;
|
|
27
|
-
export declare function format(level: LogLevel, prefix: string, message: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Abstract reporter which optionally groups log entries by target.
|
|
21
|
+
* If grouping is enabled, it only flushes a target's log entries when it completes.
|
|
22
|
+
*/
|
|
28
23
|
export declare abstract class GroupedReporter implements Reporter {
|
|
29
24
|
protected options: {
|
|
30
25
|
logLevel?: LogLevel;
|
|
31
26
|
grouped?: boolean;
|
|
27
|
+
/** Whether to capture and report main process memory usage on target completion */
|
|
28
|
+
logMemory?: boolean;
|
|
32
29
|
/** stream for testing */
|
|
33
30
|
logStream?: Writable;
|
|
34
31
|
};
|
|
@@ -38,10 +35,13 @@ export declare abstract class GroupedReporter implements Reporter {
|
|
|
38
35
|
constructor(options: {
|
|
39
36
|
logLevel?: LogLevel;
|
|
40
37
|
grouped?: boolean;
|
|
38
|
+
/** Whether to capture and report main process memory usage on target completion */
|
|
39
|
+
logMemory?: boolean;
|
|
41
40
|
/** stream for testing */
|
|
42
41
|
logStream?: Writable;
|
|
43
42
|
});
|
|
44
43
|
log(entry: LogEntry<any>): boolean | void;
|
|
44
|
+
/** Print the entry for a target */
|
|
45
45
|
protected logTargetEntry(entry: LogEntry<TargetLogData>): boolean | void;
|
|
46
46
|
private logTargetEntryByGroup;
|
|
47
47
|
summarize(schedulerRunSummary: SchedulerRunSummary): void;
|
package/lib/GroupedReporter.js
CHANGED
|
@@ -14,22 +14,15 @@ _export(exports, {
|
|
|
14
14
|
},
|
|
15
15
|
get colors () {
|
|
16
16
|
return colors;
|
|
17
|
-
},
|
|
18
|
-
get format () {
|
|
19
|
-
return format;
|
|
20
|
-
},
|
|
21
|
-
get getTaskLogPrefix () {
|
|
22
|
-
return getTaskLogPrefix;
|
|
23
|
-
},
|
|
24
|
-
get logLevelLabel () {
|
|
25
|
-
return logLevelLabel;
|
|
26
17
|
}
|
|
27
18
|
});
|
|
28
|
-
const
|
|
19
|
+
const _formatDuration = require("./formatDuration.js");
|
|
29
20
|
const _isTargetStatusLogEntry = require("./isTargetStatusLogEntry.js");
|
|
30
21
|
const _logger = require("@lage-run/logger");
|
|
31
22
|
const _chalk = /*#__PURE__*/ _interop_require_default(require("chalk"));
|
|
32
23
|
const _slowestTargetRuns = require("./slowestTargetRuns.js");
|
|
24
|
+
const _formatHelpers = require("./formatHelpers.js");
|
|
25
|
+
const _LogReporter = require("./LogReporter.js");
|
|
33
26
|
function _define_property(obj, key, value) {
|
|
34
27
|
if (key in obj) {
|
|
35
28
|
Object.defineProperty(obj, key, {
|
|
@@ -70,18 +63,6 @@ const logLevelLabel = {
|
|
|
70
63
|
function getTaskLogPrefix(pkg, task) {
|
|
71
64
|
return `${colors.pkg(pkg)} ${colors.task(task)}`;
|
|
72
65
|
}
|
|
73
|
-
function normalize(prefixOrMessage, message) {
|
|
74
|
-
if (typeof message === "string") {
|
|
75
|
-
return {
|
|
76
|
-
prefix: prefixOrMessage,
|
|
77
|
-
message
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
return {
|
|
81
|
-
prefix: "",
|
|
82
|
-
message: prefixOrMessage
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
66
|
function format(level, prefix, message) {
|
|
86
67
|
return `${logLevelLabel[level]}: ${prefix} ${message}\n`;
|
|
87
68
|
}
|
|
@@ -103,35 +84,41 @@ class GroupedReporter {
|
|
|
103
84
|
return this.logTargetEntry(entry);
|
|
104
85
|
}
|
|
105
86
|
}
|
|
106
|
-
logTargetEntry(entry) {
|
|
87
|
+
/** Print the entry for a target */ logTargetEntry(entry) {
|
|
107
88
|
const colorFn = colors[entry.level];
|
|
108
89
|
const data = entry.data;
|
|
109
|
-
if (
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
const normalizedArgs = this.options.grouped ? normalize(entry.msg) : normalize(getTaskLogPrefix(packageName ?? "<root>", task), entry.msg);
|
|
113
|
-
const pkgTask = this.options.grouped ? `${_chalk.default.magenta(packageName)} ${_chalk.default.cyan(task)}` : "";
|
|
114
|
-
switch(data.status){
|
|
115
|
-
case "running":
|
|
116
|
-
return this.logStream.write(format(entry.level, normalizedArgs.prefix, colorFn(`${colors.ok("➔")} start ${pkgTask}`)));
|
|
117
|
-
case "success":
|
|
118
|
-
return this.logStream.write(format(entry.level, normalizedArgs.prefix, colorFn(`${colors.ok("✓")} done ${pkgTask} - ${(0, _formathrtime.formatDuration)((0, _formathrtime.hrToSeconds)(duration))}`)));
|
|
119
|
-
case "failed":
|
|
120
|
-
return this.logStream.write(format(entry.level, normalizedArgs.prefix, colorFn(`${colors.error("✖")} fail ${pkgTask}`)));
|
|
121
|
-
case "skipped":
|
|
122
|
-
return this.logStream.write(format(entry.level, normalizedArgs.prefix, colorFn(`${colors.ok("»")} skip ${pkgTask} - ${hash}`)));
|
|
123
|
-
case "aborted":
|
|
124
|
-
return this.logStream.write(format(entry.level, normalizedArgs.prefix, colorFn(`${colors.warn("-")} aborted ${pkgTask}`)));
|
|
125
|
-
case "queued":
|
|
126
|
-
return this.logStream.write(format(entry.level, normalizedArgs.prefix, colorFn(`${colors.warn("…")} queued ${pkgTask}`)));
|
|
90
|
+
if (!data?.target) {
|
|
91
|
+
if (entry.msg.trim()) {
|
|
92
|
+
this.logStream.write(format(entry.level, "", entry.msg));
|
|
127
93
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
return this.logStream.write(format(entry.level, ""
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const { target } = data;
|
|
97
|
+
const { packageName, task } = target;
|
|
98
|
+
const prefix = this.options.grouped ? "" : getTaskLogPrefix(packageName ?? "<root>", task);
|
|
99
|
+
if (!(0, _isTargetStatusLogEntry.isTargetStatusLogEntry)(data)) {
|
|
100
|
+
return this.logStream.write(format(entry.level, prefix, colorFn("| " + entry.msg)));
|
|
101
|
+
}
|
|
102
|
+
const { hash, duration, memoryUsage, status } = data;
|
|
103
|
+
const mem = (0, _formatHelpers.formatMemoryUsage)(memoryUsage, this.options.logMemory);
|
|
104
|
+
const pkgTask = this.options.grouped ? `${_chalk.default.magenta(packageName)} ${_chalk.default.cyan(task)}` : "";
|
|
105
|
+
switch(status){
|
|
106
|
+
case "running":
|
|
107
|
+
return this.logStream.write(format(entry.level, prefix, colorFn(`${colors.ok("➔")} start ${pkgTask}`)));
|
|
108
|
+
case "success":
|
|
109
|
+
return this.logStream.write(format(entry.level, prefix, colorFn(`${colors.ok("✓")} done ${pkgTask} - ${(0, _formatDuration.formatHrtime)(duration)}${mem}`)));
|
|
110
|
+
case "failed":
|
|
111
|
+
return this.logStream.write(format(entry.level, prefix, colorFn(`${colors.error("✖")} fail ${pkgTask}${mem}`)));
|
|
112
|
+
case "skipped":
|
|
113
|
+
return this.logStream.write(format(entry.level, prefix, colorFn(`${colors.ok("»")} skip ${pkgTask} - ${hash}${mem}`)));
|
|
114
|
+
case "aborted":
|
|
115
|
+
return this.logStream.write(format(entry.level, prefix, colorFn(`${colors.warn("-")} aborted ${pkgTask}`)));
|
|
116
|
+
case "queued":
|
|
117
|
+
return this.logStream.write(format(entry.level, prefix, colorFn(`${colors.warn("…")} queued ${pkgTask}`)));
|
|
118
|
+
case "pending":
|
|
119
|
+
return;
|
|
120
|
+
default:
|
|
121
|
+
throw new Error(`Internal error: unhandled target status "${status}"`);
|
|
135
122
|
}
|
|
136
123
|
}
|
|
137
124
|
logTargetEntryByGroup(entry) {
|
|
@@ -153,36 +140,28 @@ class GroupedReporter {
|
|
|
153
140
|
}
|
|
154
141
|
}
|
|
155
142
|
summarize(schedulerRunSummary) {
|
|
156
|
-
const { targetRuns, targetRunByStatus
|
|
143
|
+
const { targetRuns, targetRunByStatus } = schedulerRunSummary;
|
|
157
144
|
const { failed, aborted, skipped, success, pending } = targetRunByStatus;
|
|
158
|
-
const statusColorFn = {
|
|
159
|
-
success: _chalk.default.greenBright,
|
|
160
|
-
failed: _chalk.default.redBright,
|
|
161
|
-
skipped: _chalk.default.gray,
|
|
162
|
-
running: _chalk.default.yellow,
|
|
163
|
-
pending: _chalk.default.gray,
|
|
164
|
-
aborted: _chalk.default.red,
|
|
165
|
-
queued: _chalk.default.magenta
|
|
166
|
-
};
|
|
167
145
|
this.writeSummaryHeader();
|
|
168
146
|
if (targetRuns.size > 0) {
|
|
169
147
|
const slowestTargets = (0, _slowestTargetRuns.slowestTargetRuns)([
|
|
170
148
|
...targetRuns.values()
|
|
171
149
|
]);
|
|
172
150
|
for (const wrappedTarget of slowestTargets){
|
|
173
|
-
const
|
|
174
|
-
const
|
|
175
|
-
this.logStream.write(format(_logger.LogLevel.info, getTaskLogPrefix(target.packageName || "[GLOBAL]", target.task), colorFn(`${
|
|
151
|
+
const { target, status, duration } = wrappedTarget;
|
|
152
|
+
const colorFn = _LogReporter.statusColorFn[status] ?? _chalk.default.white;
|
|
153
|
+
this.logStream.write(format(_logger.LogLevel.info, getTaskLogPrefix(target.packageName || "[GLOBAL]", target.task), colorFn(`${status}${duration ? `, took ${(0, _formatDuration.formatHrtime)(duration)}` : ""}`)));
|
|
176
154
|
}
|
|
177
155
|
this.logStream.write(`[Tasks Count] success: ${success.length}, skipped: ${skipped.length}, pending: ${pending.length}, aborted: ${aborted.length}\n`);
|
|
178
156
|
} else {
|
|
179
157
|
this.logStream.write("Nothing has been run.\n");
|
|
180
158
|
}
|
|
181
159
|
this.writeSummaryFooter();
|
|
182
|
-
if (failed
|
|
160
|
+
if (failed.length > 0) {
|
|
183
161
|
this.writeFailures(failed, targetRuns);
|
|
184
162
|
}
|
|
185
|
-
|
|
163
|
+
const formattedDuration = (0, _formatDuration.formatHrtime)(schedulerRunSummary.duration);
|
|
164
|
+
this.logStream.write(format(_logger.LogLevel.info, "", `Took a total of ${formattedDuration} to complete`));
|
|
186
165
|
}
|
|
187
166
|
constructor(options){
|
|
188
167
|
_define_property(this, "options", void 0);
|