@vzn/vx 0.0.18 → 0.0.22
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/LICENSE +1 -1
- package/README.md +107 -70
- package/package.json +10 -20
- package/src/bin.ts +64 -5
- package/src/cache/archive.ts +279 -28
- package/src/cache/cache.ts +952 -1584
- package/src/cache/chained-cache.ts +14 -10
- package/src/cache/config-evals.ts +112 -0
- package/src/cache/file-hashes.ts +290 -0
- package/src/cache/git-inputs.ts +966 -0
- package/src/cache/index.ts +23 -7
- package/src/cache/inputs.ts +553 -739
- package/src/cache/key-fold.ts +232 -0
- package/src/cache/layer.ts +674 -0
- package/src/cache/layered-cache.ts +211 -49
- package/src/cache/output-index.ts +323 -0
- package/src/cache/policy.ts +84 -0
- package/src/cache/run-history.ts +152 -0
- package/src/cache/zstd.ts +183 -0
- package/src/cli/cache.ts +88 -30
- package/src/cli/completions.ts +104 -0
- package/src/cli/core-alias.ts +25 -0
- package/src/cli/format.ts +4 -15
- package/src/cli/help.ts +76 -38
- package/src/cli/index.ts +82 -17
- package/src/cli/info.ts +162 -91
- package/src/cli/init.ts +87 -0
- package/src/cli/last.ts +130 -23
- package/src/cli/lock.ts +36 -18
- package/src/cli/plan-format.ts +18 -7
- package/src/cli/plugin-commands.ts +34 -12
- package/src/cli/run.ts +138 -313
- package/src/cli/select.ts +342 -0
- package/src/cli/show.ts +151 -71
- package/src/cli/upgrade.ts +136 -15
- package/src/cli/watch.ts +1175 -116
- package/src/cli/why.ts +51 -29
- package/src/cli/workspace-config.ts +138 -0
- package/src/config.ts +183 -126
- package/src/exec/env.ts +11 -0
- package/src/exec/executor.ts +62 -31
- package/src/exec/index.ts +16 -2
- package/src/exec/kill-tree.ts +281 -0
- package/src/exec/local-executor.ts +41 -0
- package/src/exec/runner.ts +361 -77
- package/src/exec/sandbox-binds.ts +211 -0
- package/src/exec/sandbox-paths.ts +70 -0
- package/src/exec/sandbox-runtime.ts +1152 -415
- package/src/exec/sandbox-violations.ts +293 -0
- package/src/graph/dependency-spec.ts +14 -14
- package/src/graph/index.ts +6 -4
- package/src/graph/priorities.ts +130 -0
- package/src/graph/scheduler.ts +332 -329
- package/src/graph/task-graph.ts +552 -188
- package/src/index.ts +111 -102
- package/src/orchestrator/admission.ts +161 -0
- package/src/orchestrator/colors.ts +8 -3
- package/src/orchestrator/deferred-outputs.ts +25 -7
- package/src/orchestrator/doctor.ts +363 -0
- package/src/orchestrator/events.ts +111 -8
- package/src/orchestrator/excluded-keys.ts +155 -0
- package/src/orchestrator/execute-task.ts +450 -565
- package/src/orchestrator/failure-mode.ts +169 -28
- package/src/orchestrator/failure-recap.ts +121 -0
- package/src/orchestrator/fingerprint-watch.ts +89 -0
- package/src/orchestrator/framed-output.ts +121 -49
- package/src/orchestrator/history.ts +123 -104
- package/src/orchestrator/hit-restore.ts +285 -0
- package/src/orchestrator/index.ts +42 -5
- package/src/orchestrator/keyed-projects.ts +89 -0
- package/src/orchestrator/local-shortcircuit.ts +83 -23
- package/src/orchestrator/lockfile-claim.ts +401 -0
- package/src/orchestrator/logger.ts +128 -41
- package/src/orchestrator/metrics.ts +201 -72
- package/src/orchestrator/miss-save.ts +232 -0
- package/src/orchestrator/options.ts +63 -34
- package/src/orchestrator/persistent.ts +99 -0
- package/src/orchestrator/placement.ts +212 -0
- package/src/orchestrator/plan.ts +24 -11
- package/src/orchestrator/plugin-host.ts +200 -49
- package/src/orchestrator/plugin.ts +190 -14
- package/src/orchestrator/prepare.ts +168 -137
- package/src/orchestrator/projects.ts +270 -0
- package/src/orchestrator/remote-prefetch.ts +22 -2
- package/src/orchestrator/run-artifacts.ts +34 -3
- package/src/orchestrator/run-context.ts +20 -5
- package/src/orchestrator/run-lock.ts +349 -0
- package/src/orchestrator/run-records.ts +132 -0
- package/src/orchestrator/run-report.ts +6 -4
- package/src/orchestrator/run.ts +467 -611
- package/src/orchestrator/sandbox-request.ts +569 -0
- package/src/orchestrator/save-lane.ts +44 -0
- package/src/orchestrator/shell-verdict.ts +117 -0
- package/src/orchestrator/signals.ts +167 -0
- package/src/orchestrator/stable-keys.ts +259 -10
- package/src/orchestrator/status-line.ts +35 -2
- package/src/orchestrator/summary.ts +115 -25
- package/src/orchestrator/task-hash.ts +103 -21
- package/src/orchestrator/task-log-buffer.ts +15 -18
- package/src/orchestrator/telemetry-host.ts +27 -8
- package/src/orchestrator/telemetry.ts +71 -44
- package/src/orchestrator/upstream.ts +91 -45
- package/src/util/bun-version.ts +43 -0
- package/src/util/cgroup.ts +160 -0
- package/src/util/edit-distance.ts +49 -0
- package/src/util/errors.ts +86 -0
- package/src/util/hash.ts +10 -1
- package/src/util/index.ts +42 -5
- package/src/util/paths.ts +168 -5
- package/src/util/procfs.ts +20 -0
- package/src/util/settle.ts +23 -2
- package/src/util/size.ts +33 -0
- package/src/util/task-id.ts +20 -0
- package/src/util/timing.ts +11 -1
- package/src/util/verbs.ts +39 -0
- package/src/util/which.ts +48 -0
- package/src/workspace/affected.ts +368 -60
- package/src/workspace/config-cache.ts +271 -32
- package/src/workspace/config-eval.ts +60 -16
- package/src/workspace/config-imports.ts +131 -9
- package/src/workspace/config-schema.ts +1033 -0
- package/src/workspace/filter.ts +69 -17
- package/src/workspace/fingerprint.ts +59 -7
- package/src/workspace/index.ts +37 -3
- package/src/workspace/json-data.ts +90 -0
- package/src/workspace/load-reads.ts +32 -0
- package/src/workspace/lockfile.ts +41 -14
- package/src/workspace/migrate-scripts.ts +187 -0
- package/src/workspace/migration.ts +353 -0
- package/src/workspace/package-graph.ts +239 -31
- package/src/workspace/project-loader.ts +295 -815
- package/src/workspace/workspace.ts +266 -31
- package/plugins/local-cache/index.ts +0 -2
- package/plugins/local-executor/index.ts +0 -2
- package/plugins/schedule-history/index.ts +0 -2
- package/src/cache/cas-backend.ts +0 -115
- package/src/cache/digest.ts +0 -32
- package/src/cli/migrate-emit.ts +0 -21
- package/src/cli/migrate-nx.ts +0 -473
- package/src/cli/migrate-scripts.ts +0 -127
- package/src/cli/migrate-turbo.ts +0 -401
- package/src/cli/migrate.ts +0 -305
- package/src/cli/prune.ts +0 -291
- package/src/orchestrator/missing-plugin.ts +0 -9
- package/src/orchestrator/resources.ts +0 -45
- package/src/orchestrator/verify.ts +0 -174
- package/src/plugins/local-cache/index.ts +0 -11
- package/src/plugins/local-executor/index.ts +0 -45
- package/src/plugins/schedule-history/index.ts +0 -109
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { TaskNode, TaskOutcome } from '../graph/index.js'
|
|
2
2
|
import { detectColors, type ColorSupport } from './colors.js'
|
|
3
3
|
import {
|
|
4
|
+
formatFailureRecap,
|
|
4
5
|
formatFrameClose,
|
|
5
6
|
formatFrameOpen,
|
|
6
7
|
formatPersistentTailBlock,
|
|
@@ -8,7 +9,15 @@ import {
|
|
|
8
9
|
formatTaskExecutedLine,
|
|
9
10
|
formatTaskHitLine,
|
|
10
11
|
formatTaskSkippedLine,
|
|
12
|
+
type RecapEntry,
|
|
11
13
|
} from './framed-output.js'
|
|
14
|
+
import {
|
|
15
|
+
appendRecapRing,
|
|
16
|
+
createRecapRing,
|
|
17
|
+
RECAP_TASKS,
|
|
18
|
+
recapTail,
|
|
19
|
+
type RecapRing,
|
|
20
|
+
} from './failure-recap.js'
|
|
12
21
|
import {
|
|
13
22
|
createOutputWriter,
|
|
14
23
|
formatFailureLine,
|
|
@@ -20,6 +29,7 @@ import { formatDuration, formatSummarySection, type RunContext } from './summary
|
|
|
20
29
|
import { isGroupTask } from '../graph/index.js'
|
|
21
30
|
import { appendTail, createTail, resetTail, tailText, type Tail } from '../util/index.js'
|
|
22
31
|
import { isCacheHit } from './telemetry.js'
|
|
32
|
+
import { failedLabel, outcomeWord } from './events.js'
|
|
23
33
|
|
|
24
34
|
export interface Logger {
|
|
25
35
|
/** Header / footer / status text. Written verbatim, one trailing \n added. */
|
|
@@ -52,6 +62,21 @@ export interface Logger {
|
|
|
52
62
|
runEnd?(): void
|
|
53
63
|
}
|
|
54
64
|
|
|
65
|
+
/** The logger `run()` builds when none is passed, and the one that owns the recap. */
|
|
66
|
+
export interface DefaultLogger extends Logger {
|
|
67
|
+
/**
|
|
68
|
+
* The run's last block: each failed task's last lines (item 706). Empty
|
|
69
|
+
* when nothing failed, and in the modes that promise no task output.
|
|
70
|
+
*/
|
|
71
|
+
failureRecap(): string[]
|
|
72
|
+
/**
|
|
73
|
+
* Hand over any output still coalesced, and write straight through from
|
|
74
|
+
* now on. `runEnd` does it; the run's own `finally` does it again for a
|
|
75
|
+
* throw that never reached `runEnd`.
|
|
76
|
+
*/
|
|
77
|
+
settle(): void
|
|
78
|
+
}
|
|
79
|
+
|
|
55
80
|
/**
|
|
56
81
|
* The default logger's per-task output policy. Resolved once per run
|
|
57
82
|
* from (in priority order) the explicit `--output-logs` override, a
|
|
@@ -124,19 +149,8 @@ function ghaFence(body: string, token: string): string {
|
|
|
124
149
|
return `::stop-commands::${token}\n${body}::${token}::\n`
|
|
125
150
|
}
|
|
126
151
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
switch (o.status) {
|
|
130
|
-
case 'success':
|
|
131
|
-
return 'success'
|
|
132
|
-
case 'cache-hit':
|
|
133
|
-
return o.restored === false ? 'up-to-date' : 'restored-local'
|
|
134
|
-
case 'cache-hit-remote':
|
|
135
|
-
return o.restored === false ? 'up-to-date' : 'restored-remote'
|
|
136
|
-
default:
|
|
137
|
-
return o.status
|
|
138
|
-
}
|
|
139
|
-
}
|
|
152
|
+
const cacheWordOf = (n: TaskNode): 'miss' | 'no-cache' =>
|
|
153
|
+
n.config.cache === undefined ? 'no-cache' : 'miss'
|
|
140
154
|
|
|
141
155
|
export function resolveOutputView(
|
|
142
156
|
options: {
|
|
@@ -162,8 +176,8 @@ export function defaultLogger(
|
|
|
162
176
|
colors: ColorSupport = detectColors(),
|
|
163
177
|
view: OutputView = { mode: 'full' },
|
|
164
178
|
out: StatusStream = process.stdout,
|
|
165
|
-
opts: { forceFloorMs?: number } = {},
|
|
166
|
-
):
|
|
179
|
+
opts: { forceFloorMs?: number; coalesce?: boolean } = {},
|
|
180
|
+
): DefaultLogger {
|
|
167
181
|
// Per-task buffers, split by stream. Splitting lets the framed-output
|
|
168
182
|
// renderer put stdout under `├─ stdout` and stderr under `├─ stderr`.
|
|
169
183
|
// The price: chunks that interleaved at runtime get re-ordered (all
|
|
@@ -182,8 +196,6 @@ export function defaultLogger(
|
|
|
182
196
|
// a one-liner or streamed output since the last block does.
|
|
183
197
|
let lineEmitted = false
|
|
184
198
|
let streamedSinceBlock = false
|
|
185
|
-
// Ids whose output went straight to the terminal (focused mode).
|
|
186
|
-
const streamed = new Set<string>()
|
|
187
199
|
// True while the live stream sits mid-line (chunk without trailing
|
|
188
200
|
// newline) — the frame close must not glue onto partial output.
|
|
189
201
|
let streamMidLine = false
|
|
@@ -227,6 +239,7 @@ export function defaultLogger(
|
|
|
227
239
|
const writer = createOutputWriter(out, {
|
|
228
240
|
enabled: view.ci !== true,
|
|
229
241
|
...(opts.forceFloorMs !== undefined ? { forceFloorMs: opts.forceFloorMs } : {}),
|
|
242
|
+
...(opts.coalesce === true ? { coalesce: true } : {}),
|
|
230
243
|
})
|
|
231
244
|
|
|
232
245
|
// Status-display state, driven by the optional lifecycle hooks.
|
|
@@ -257,6 +270,8 @@ export function defaultLogger(
|
|
|
257
270
|
let slots: (WorkerSlot | null)[] = []
|
|
258
271
|
const slotQueue: WorkerSlot[] = []
|
|
259
272
|
let succeeded = 0
|
|
273
|
+
// Executed with no `cache` block: never a miss, counted apart.
|
|
274
|
+
let noCache = 0
|
|
260
275
|
let upToDate = 0
|
|
261
276
|
let restoredLocal = 0
|
|
262
277
|
let restoredRemote = 0
|
|
@@ -267,11 +282,12 @@ export function defaultLogger(
|
|
|
267
282
|
let spreadMin = Infinity
|
|
268
283
|
let spreadSum = 0
|
|
269
284
|
let spreadCount = 0
|
|
270
|
-
//
|
|
271
|
-
//
|
|
272
|
-
//
|
|
273
|
-
//
|
|
274
|
-
//
|
|
285
|
+
// The pinned zone above the worker rows: persistent tasks pin at
|
|
286
|
+
// ready (their outcome lands while the child keeps running) and live
|
|
287
|
+
// until runEnd kills the region. A failure is not pinned: it is a
|
|
288
|
+
// permanent ◼ row the moment it happens, and its full frame is
|
|
289
|
+
// deferred to runEnd (owner: '✗ line, continue, all full frames at
|
|
290
|
+
// the end'). 'full'/CI keeps frames inline.
|
|
275
291
|
const deferredFailures: string[] = []
|
|
276
292
|
const pinnedPersistent: string[] = []
|
|
277
293
|
let flushedFailures = false
|
|
@@ -297,6 +313,13 @@ export function defaultLogger(
|
|
|
297
313
|
{ node: TaskNode; outcome?: TaskOutcome; out: Tail; err: Tail }
|
|
298
314
|
>()
|
|
299
315
|
let flushedPersistent = false
|
|
316
|
+
// The recap's material, decided at each failure so nothing is held for a
|
|
317
|
+
// task that passed. A buffered task's tail is read off the buffers the
|
|
318
|
+
// frame drains; a live-streamed one keeps no buffer, so a bounded ring
|
|
319
|
+
// follows it from its frame-open until its outcome.
|
|
320
|
+
const recapEntries: RecapEntry[] = []
|
|
321
|
+
const recapMore: string[] = []
|
|
322
|
+
const liveRings = new Map<string, RecapRing>()
|
|
300
323
|
|
|
301
324
|
const refresh = (force: boolean): void => {
|
|
302
325
|
if (statusDead) return
|
|
@@ -311,7 +334,8 @@ export function defaultLogger(
|
|
|
311
334
|
upToDate,
|
|
312
335
|
restoredLocal,
|
|
313
336
|
restoredRemote,
|
|
314
|
-
miss: succeeded + failed,
|
|
337
|
+
miss: succeeded + failed - noCache,
|
|
338
|
+
noCache,
|
|
315
339
|
left: total - done,
|
|
316
340
|
spread:
|
|
317
341
|
spreadCount > 0
|
|
@@ -381,6 +405,23 @@ export function defaultLogger(
|
|
|
381
405
|
view.mode === 'focused' && isPrimary(node) && !isGroupTask(node) && requestedCount <= 1
|
|
382
406
|
|
|
383
407
|
return {
|
|
408
|
+
settle() {
|
|
409
|
+
writer.settle()
|
|
410
|
+
},
|
|
411
|
+
failureRecap() {
|
|
412
|
+
if (recapEntries.length === 0) return []
|
|
413
|
+
// Fenced like a frame: a tail is the task's own text, and a line of it
|
|
414
|
+
// must not become a workflow command. Never inside a group, so it reads
|
|
415
|
+
// with every group collapsed.
|
|
416
|
+
const fence =
|
|
417
|
+
view.gha === true
|
|
418
|
+
? (lines: string[]) =>
|
|
419
|
+
ghaFence(`${lines.join('\n')}\n`, ghaToken)
|
|
420
|
+
.slice(0, -1)
|
|
421
|
+
.split('\n')
|
|
422
|
+
: undefined
|
|
423
|
+
return formatFailureRecap(recapEntries, recapMore, colors, fence)
|
|
424
|
+
},
|
|
384
425
|
status(line) {
|
|
385
426
|
writer.write(`${line}\n`)
|
|
386
427
|
},
|
|
@@ -413,6 +454,7 @@ export function defaultLogger(
|
|
|
413
454
|
// Open the live frame: full task info even when the command
|
|
414
455
|
// streams nothing (or the hit replays nothing).
|
|
415
456
|
emitLine(formatFrameOpen(node, colors))
|
|
457
|
+
liveRings.set(node.id, createRecapRing())
|
|
416
458
|
return
|
|
417
459
|
}
|
|
418
460
|
// Bound a persistent task's output from its FIRST chunk. Waiting for
|
|
@@ -461,21 +503,25 @@ export function defaultLogger(
|
|
|
461
503
|
}
|
|
462
504
|
}
|
|
463
505
|
// Failures end the log: every deferred frame replays here, right
|
|
464
|
-
// above the summary — the
|
|
465
|
-
//
|
|
506
|
+
// above the summary — the ◼ rows marked them in the stream,
|
|
507
|
+
// the full diagnostics read last where eyes land.
|
|
466
508
|
// Guarded for repeat runEnd calls.
|
|
467
509
|
if (!flushedFailures && deferredFailures.length > 0) {
|
|
468
510
|
flushedFailures = true
|
|
469
511
|
for (const block of deferredFailures) emitBlock(block)
|
|
470
512
|
}
|
|
513
|
+
// The summary and the CLI's own lines follow on the stream directly:
|
|
514
|
+
// nothing may still be held, and nothing after this is.
|
|
515
|
+
writer.settle()
|
|
471
516
|
},
|
|
472
517
|
taskStdout(node, chunk) {
|
|
473
518
|
if (discardsOutput) return
|
|
474
519
|
if (streamsLive(node)) {
|
|
475
|
-
streamed.add(node.id)
|
|
476
520
|
streamedSinceBlock = true
|
|
477
521
|
if (chunk.length > 0) streamMidLine = !chunk.endsWith('\n')
|
|
478
522
|
writer.write(chunk)
|
|
523
|
+
const ring = liveRings.get(node.id)
|
|
524
|
+
if (ring !== undefined) appendRecapRing(ring, chunk)
|
|
479
525
|
return
|
|
480
526
|
}
|
|
481
527
|
const tail = persistentTails.get(node.id)
|
|
@@ -488,10 +534,11 @@ export function defaultLogger(
|
|
|
488
534
|
taskStderr(node, chunk) {
|
|
489
535
|
if (discardsOutput) return
|
|
490
536
|
if (streamsLive(node)) {
|
|
491
|
-
streamed.add(node.id)
|
|
492
537
|
streamedSinceBlock = true
|
|
493
538
|
if (chunk.length > 0) streamMidLine = !chunk.endsWith('\n')
|
|
494
539
|
writer.write(chunk)
|
|
540
|
+
const ring = liveRings.get(node.id)
|
|
541
|
+
if (ring !== undefined) appendRecapRing(ring, chunk)
|
|
495
542
|
return
|
|
496
543
|
}
|
|
497
544
|
const tail = persistentTails.get(node.id)
|
|
@@ -516,6 +563,28 @@ export function defaultLogger(
|
|
|
516
563
|
// The pre-ready window closed either way: a failed task is over, and
|
|
517
564
|
// a ready one starts a fresh post-ready tail below.
|
|
518
565
|
persistentTails.delete(node.id)
|
|
566
|
+
const liveRing = liveRings.get(node.id)
|
|
567
|
+
liveRings.delete(node.id)
|
|
568
|
+
if (outcome.status === 'failed' && !discardsOutput) {
|
|
569
|
+
if (recapEntries.length === RECAP_TASKS) recapMore.push(node.id)
|
|
570
|
+
else {
|
|
571
|
+
let ring = liveRing
|
|
572
|
+
if (ring === undefined) {
|
|
573
|
+
ring = createRecapRing()
|
|
574
|
+
appendRecapRing(ring, stdout)
|
|
575
|
+
if (stdout.length > 0 && stderr.length > 0 && !stdout.endsWith('\n')) {
|
|
576
|
+
appendRecapRing(ring, '\n')
|
|
577
|
+
}
|
|
578
|
+
appendRecapRing(ring, stderr)
|
|
579
|
+
}
|
|
580
|
+
recapEntries.push({
|
|
581
|
+
node,
|
|
582
|
+
outcome,
|
|
583
|
+
tail: recapTail(ring),
|
|
584
|
+
droppedChars: (preReady?.out.dropped ?? 0) + (preReady?.err.dropped ?? 0),
|
|
585
|
+
})
|
|
586
|
+
}
|
|
587
|
+
}
|
|
519
588
|
// An aborted task (child killed by a shutdown signal) reverts
|
|
520
589
|
// to pending: free its worker slot, but never count or render it
|
|
521
590
|
// — the run is tearing down and it has no honest outcome.
|
|
@@ -527,6 +596,22 @@ export function defaultLogger(
|
|
|
527
596
|
if (qi >= 0) slotQueue.splice(qi, 1)
|
|
528
597
|
}
|
|
529
598
|
refresh(true)
|
|
599
|
+
// What it printed while it stopped (a trap's cleanup) still reaches
|
|
600
|
+
// the terminal where a frame would have: a task that traps Ctrl-C
|
|
601
|
+
// and exits 0 is aborted since item 962, and its frame was dropped
|
|
602
|
+
// with the count.
|
|
603
|
+
const framed = view.mode === 'full' || (view.mode === 'focused' && isPrimary(node))
|
|
604
|
+
if (framed && !isGroupTask(node)) {
|
|
605
|
+
if (streamsLive(node)) {
|
|
606
|
+
if (streamMidLine) {
|
|
607
|
+
writer.write('\n')
|
|
608
|
+
streamMidLine = false
|
|
609
|
+
}
|
|
610
|
+
emitFrameClose(formatFrameClose(node, outcome, colors))
|
|
611
|
+
} else if (stdout.length > 0 || stderr.length > 0) {
|
|
612
|
+
emitBlock(formatTaskBlock(node, outcome, { stdout, stderr, ...dropped }, colors, true))
|
|
613
|
+
}
|
|
614
|
+
}
|
|
530
615
|
return
|
|
531
616
|
}
|
|
532
617
|
// Group tasks (no exec) do no work — no surface prints them.
|
|
@@ -534,6 +619,7 @@ export function defaultLogger(
|
|
|
534
619
|
done++
|
|
535
620
|
if (outcome.status === 'failed') {
|
|
536
621
|
failed++
|
|
622
|
+
if (node.config.cache === undefined) noCache++
|
|
537
623
|
} else if (node.config.exec?.persistent !== undefined && outcome.status === 'success') {
|
|
538
624
|
// A persistent task's outcome arrives at READY; the child
|
|
539
625
|
// keeps running until the orchestrator SIGTERMs it at run
|
|
@@ -557,6 +643,7 @@ export function defaultLogger(
|
|
|
557
643
|
switch (outcome.status) {
|
|
558
644
|
case 'success':
|
|
559
645
|
succeeded++
|
|
646
|
+
if (node.config.cache === undefined) noCache++
|
|
560
647
|
break
|
|
561
648
|
case 'cache-hit':
|
|
562
649
|
if (outcome.restored === false) upToDate++
|
|
@@ -593,7 +680,7 @@ export function defaultLogger(
|
|
|
593
680
|
}
|
|
594
681
|
case 'errors-only':
|
|
595
682
|
if (outcome.status !== 'failed') return
|
|
596
|
-
emitLine(formatFailureLine(node.id, outcome.durationMs, colors))
|
|
683
|
+
emitLine(formatFailureLine(node.id, outcome.durationMs, colors, cacheWordOf(node)))
|
|
597
684
|
deferredFailures.push(
|
|
598
685
|
formatTaskBlock(node, outcome, { stdout, stderr, ...dropped }, colors),
|
|
599
686
|
)
|
|
@@ -604,8 +691,8 @@ export function defaultLogger(
|
|
|
604
691
|
// their replay buffers are deliberately dropped; the counts
|
|
605
692
|
// surface in the end-of-run summary.
|
|
606
693
|
if (outcome.status === 'failed') {
|
|
607
|
-
//
|
|
608
|
-
emitLine(formatFailureLine(node.id, outcome.durationMs, colors))
|
|
694
|
+
// ◼ row now; the full frame replays at runEnd.
|
|
695
|
+
emitLine(formatFailureLine(node.id, outcome.durationMs, colors, cacheWordOf(node)))
|
|
609
696
|
deferredFailures.push(
|
|
610
697
|
formatTaskBlock(node, outcome, { stdout, stderr, ...dropped }, colors),
|
|
611
698
|
)
|
|
@@ -615,11 +702,11 @@ export function defaultLogger(
|
|
|
615
702
|
return
|
|
616
703
|
case 'focused':
|
|
617
704
|
if (isPrimary(node)) {
|
|
618
|
-
// Skipped tasks never started (upstream
|
|
619
|
-
// frame-open fired — and a skip has no output,
|
|
620
|
-
// one-liner carries everything a frame would.
|
|
705
|
+
// Skipped tasks never started (blocked upstream, or the run
|
|
706
|
+
// stopped), so no frame-open fired — and a skip has no output,
|
|
707
|
+
// so a one-liner carries everything a frame would.
|
|
621
708
|
if (outcome.status === 'skipped') {
|
|
622
|
-
emitLine(formatTaskSkippedLine(node, colors))
|
|
709
|
+
emitLine(formatTaskSkippedLine(node, colors, outcome.blockedBy))
|
|
623
710
|
return
|
|
624
711
|
}
|
|
625
712
|
if (streamsLive(node)) {
|
|
@@ -640,7 +727,7 @@ export function defaultLogger(
|
|
|
640
727
|
// to runEnd like everywhere else; everything else emits
|
|
641
728
|
// ONE atomic block from the buffered output.
|
|
642
729
|
if (outcome.status === 'failed') {
|
|
643
|
-
emitLine(formatFailureLine(node.id, outcome.durationMs, colors))
|
|
730
|
+
emitLine(formatFailureLine(node.id, outcome.durationMs, colors, cacheWordOf(node)))
|
|
644
731
|
deferredFailures.push(
|
|
645
732
|
formatTaskBlock(node, outcome, { stdout, stderr, ...dropped }, colors),
|
|
646
733
|
)
|
|
@@ -652,9 +739,9 @@ export function defaultLogger(
|
|
|
652
739
|
return
|
|
653
740
|
}
|
|
654
741
|
// Dependency-pulled nodes: silent on success; failures get
|
|
655
|
-
// the
|
|
742
|
+
// the ◼ row now and their frame replayed at runEnd.
|
|
656
743
|
if (outcome.status === 'failed') {
|
|
657
|
-
emitLine(formatFailureLine(node.id, outcome.durationMs, colors))
|
|
744
|
+
emitLine(formatFailureLine(node.id, outcome.durationMs, colors, cacheWordOf(node)))
|
|
658
745
|
deferredFailures.push(
|
|
659
746
|
formatTaskBlock(node, outcome, { stdout, stderr, ...dropped }, colors),
|
|
660
747
|
)
|
|
@@ -672,7 +759,7 @@ export function defaultLogger(
|
|
|
672
759
|
return
|
|
673
760
|
}
|
|
674
761
|
if (outcome.status === 'skipped') {
|
|
675
|
-
emitLine(formatTaskSkippedLine(node, colors))
|
|
762
|
+
emitLine(formatTaskSkippedLine(node, colors, outcome.blockedBy))
|
|
676
763
|
return
|
|
677
764
|
}
|
|
678
765
|
const block = formatTaskBlock(node, outcome, { stdout, stderr, ...dropped }, colors)
|
|
@@ -685,10 +772,10 @@ export function defaultLogger(
|
|
|
685
772
|
// Failed tasks stay pre-expanded in the Actions viewer:
|
|
686
773
|
// an ::error annotation instead of a collapsed group.
|
|
687
774
|
if (outcome.status === 'failed') {
|
|
688
|
-
// The message is ours (a literal
|
|
689
|
-
// carries user input.
|
|
775
|
+
// The message is ours (a literal, an integer and a signal
|
|
776
|
+
// name); only the title carries user input.
|
|
690
777
|
emitBlock(
|
|
691
|
-
`::error title=${ghaProperty(node.id)}
|
|
778
|
+
`::error title=${ghaProperty(node.id)}::${failedLabel(outcome.exitCode, outcome.timedOut, outcome.sandboxViolations, outcome.notReady)}\n${body}`,
|
|
692
779
|
)
|
|
693
780
|
} else {
|
|
694
781
|
emitBlock(
|