@vzn/vx-ci 0.0.650 → 0.0.652
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/README.md +8 -3
- package/package.json +2 -2
- package/src/gitlab.ts +20 -3
- package/src/summary.ts +33 -0
package/README.md
CHANGED
|
@@ -25,7 +25,8 @@ That's the whole setup. On a GitHub Actions runner (`GITHUB_STEP_SUMMARY`
|
|
|
25
25
|
set) every `vx run` appends a summary block, on its own line after
|
|
26
26
|
anything already written in the step: verdict headline, stats
|
|
27
27
|
(tasks / executed / cache hits / duration, and the ideal time an executor says
|
|
28
|
-
the run could have taken, as `@vzn/vx-dte` replays it),
|
|
28
|
+
the run could have taken, as `@vzn/vx-dte` replays it), the workers
|
|
29
|
+
that would have run it best (`@vzn/vx-dte`'s "Workers to declare"), failures called out above the
|
|
29
30
|
per-task table (rows by status, failures first, then the longest first) with their exit code, the signal an exit above 128
|
|
30
31
|
stands for (`exit 137 (128 + SIGKILL)`, as the run's own frame and
|
|
31
32
|
`vx last` say it), a timeout as `timed out, exit 143`, a persistent task
|
|
@@ -111,8 +112,12 @@ variables, as `github()` does on Actions. The default branch
|
|
|
111
112
|
subgroup's project is `group/sub/app:feat-x`, the scope a laptop on
|
|
112
113
|
`feat-x` derives. A merge request pipeline names its source branch
|
|
113
114
|
(`CI_MERGE_REQUEST_SOURCE_BRANCH_NAME`) in the project it lives in (a
|
|
114
|
-
fork's `CI_MERGE_REQUEST_SOURCE_PROJECT_PATH`) and
|
|
115
|
-
(`CI_MERGE_REQUEST_DIFF_BASE_SHA`)
|
|
115
|
+
fork's `CI_MERGE_REQUEST_SOURCE_PROJECT_PATH`) and the base of a bare
|
|
116
|
+
`--affected`: its diff base (`CI_MERGE_REQUEST_DIFF_BASE_SHA`); in a
|
|
117
|
+
merged results pipeline the target head it merged onto
|
|
118
|
+
(`CI_MERGE_REQUEST_TARGET_BRANCH_SHA`), so changes the target took
|
|
119
|
+
since are not run again; in a merge train the car ahead (`HEAD^1`),
|
|
120
|
+
whose own pipeline runs its changes.
|
|
116
121
|
A merge train's pipeline (`CI_MERGE_REQUEST_EVENT_TYPE=merge_train`)
|
|
117
122
|
builds what lands on the target, so it is trusted: no scope. As on
|
|
118
123
|
Actions, the scope keys only plugin entries. A remote reads the tag, else
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vzn/vx-ci",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.652",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "GitHub Actions and GitLab CI integration for vx — a job summary on Actions and the branch cache scope on both.",
|
|
6
6
|
"keywords": [
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"access": "public"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
|
-
"@vzn/vx": "^0.0.
|
|
36
|
+
"@vzn/vx": "^0.0.652"
|
|
37
37
|
},
|
|
38
38
|
"repository": {
|
|
39
39
|
"type": "git",
|
package/src/gitlab.ts
CHANGED
|
@@ -10,7 +10,8 @@ export interface GitlabPluginOptions {
|
|
|
10
10
|
* Name the run's cache scope and base commit from GitLab's predefined
|
|
11
11
|
* variables: none on the default branch or a merge train, else
|
|
12
12
|
* `<project path>:<branch>`; a merge request is compared with its diff
|
|
13
|
-
* base
|
|
13
|
+
* base, a merged results pipeline with the target head, a train car
|
|
14
|
+
* with the car ahead. The scope keys plugin entries only. `VX_CACHE_SCOPE` beats it.
|
|
14
15
|
* Default: on; `false` opts out.
|
|
15
16
|
*/
|
|
16
17
|
cacheScope?: boolean
|
|
@@ -41,7 +42,7 @@ export function gitlab(options: GitlabPluginOptions = {}): VxPlugin | undefined
|
|
|
41
42
|
/**
|
|
42
43
|
* What a GitLab CI job knows of its branch. A merge request pipeline names
|
|
43
44
|
* its source branch in the project it lives in (a fork's own,
|
|
44
|
-
* `CI_MERGE_REQUEST_SOURCE_PROJECT_PATH`) and its
|
|
45
|
+
* `CI_MERGE_REQUEST_SOURCE_PROJECT_PATH`) and its base (`baseOf`); a merge
|
|
45
46
|
* train's pipeline builds what lands on the target, so it is trusted; a
|
|
46
47
|
* branch or tag pipeline names its ref, none on the default branch.
|
|
47
48
|
* `refs`, what a remote reads (2026-10-25): a merge train's only its
|
|
@@ -80,8 +81,24 @@ function gitlabBranch(
|
|
|
80
81
|
return refs.length === 0 ? facts : { ...facts, refs }
|
|
81
82
|
}
|
|
82
83
|
|
|
84
|
+
/**
|
|
85
|
+
* The commit a bare `--affected` compares with. A merged results pipeline
|
|
86
|
+
* runs the merge onto the target's head, so it is compared with that head:
|
|
87
|
+
* the diff base took in every change the target got since the branch
|
|
88
|
+
* forked. A train's car is merged onto the car ahead (its first parent,
|
|
89
|
+
* GitLab's `first_parent_ref`), whose pipeline runs that car's changes.
|
|
90
|
+
* Any other merge request pipeline runs its source branch: the diff base.
|
|
91
|
+
*/
|
|
92
|
+
function baseOf(value: (key: string) => string | undefined): string | undefined {
|
|
93
|
+
const event = value('CI_MERGE_REQUEST_EVENT_TYPE')
|
|
94
|
+
if (event === 'merge_train') return 'HEAD^1'
|
|
95
|
+
const diffBase = value('CI_MERGE_REQUEST_DIFF_BASE_SHA')
|
|
96
|
+
if (event === 'merged_result') return value('CI_MERGE_REQUEST_TARGET_BRANCH_SHA') ?? diffBase
|
|
97
|
+
return diffBase
|
|
98
|
+
}
|
|
99
|
+
|
|
83
100
|
function scopeOf(value: (key: string) => string | undefined): BranchFacts {
|
|
84
|
-
const base = value
|
|
101
|
+
const base = baseOf(value)
|
|
85
102
|
const withBase = (facts: BranchFacts): BranchFacts =>
|
|
86
103
|
base === undefined ? facts : { ...facts, base }
|
|
87
104
|
if (value('CI_MERGE_REQUEST_EVENT_TYPE') === 'merge_train') return withBase({ trusted: true })
|
package/src/summary.ts
CHANGED
|
@@ -198,6 +198,9 @@ export function renderJobSummary(summary: RunSummaryRecord, title = 'vx run'): s
|
|
|
198
198
|
if (summary.machines !== undefined && summary.machines.length > 0) {
|
|
199
199
|
lines.push(...renderWorkers(summary.machines, summary.tasks), '')
|
|
200
200
|
}
|
|
201
|
+
if (summary.advice !== undefined && summary.advice.length > 0) {
|
|
202
|
+
lines.push(...renderAdvice(summary.advice), '')
|
|
203
|
+
}
|
|
201
204
|
|
|
202
205
|
const header = ['Task', 'Status', 'Duration']
|
|
203
206
|
lines.push(`| ${header.join(' | ')} |`)
|
|
@@ -237,6 +240,36 @@ const tasksCell = (ok: number, failed: number): string =>
|
|
|
237
240
|
|
|
238
241
|
const pct = (x: number): string => `${Math.round(x * 100)}%`
|
|
239
242
|
|
|
243
|
+
/** What each `WorkerAdvice` played. */
|
|
244
|
+
const ADVICE = {
|
|
245
|
+
declared: 'The fewest of the declared sizes',
|
|
246
|
+
more: "Past the sizes' max",
|
|
247
|
+
any: 'Any cores, least core time',
|
|
248
|
+
} as const
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* The workers that would have run it best (2026-11-05: "So I can add more
|
|
252
|
+
* or change their specs"): played again from what each task took.
|
|
253
|
+
*/
|
|
254
|
+
function renderAdvice(advice: NonNullable<RunSummaryRecord['advice']>): string[] {
|
|
255
|
+
const lines = [
|
|
256
|
+
'### Workers to declare',
|
|
257
|
+
'',
|
|
258
|
+
'| Played on | Workers | Ends at |',
|
|
259
|
+
'| --- | --- | --- |',
|
|
260
|
+
]
|
|
261
|
+
for (const a of advice)
|
|
262
|
+
lines.push(
|
|
263
|
+
`| ${ADVICE[a.of]} | ${a.workers
|
|
264
|
+
.map(
|
|
265
|
+
(w) =>
|
|
266
|
+
`${w.count} × ${w.size === undefined ? '' : `${escapeMarkdownCell(escapeInline(w.size))} `}(${w.cores} cores, ${gb(w.memoryBytes)} GB${w.platform === undefined ? '' : `, ${escapeMarkdownCell(escapeInline(w.platform))}`})`,
|
|
267
|
+
)
|
|
268
|
+
.join(' + ')} | ${fmtMs(a.endMs)} |`,
|
|
269
|
+
)
|
|
270
|
+
return lines
|
|
271
|
+
}
|
|
272
|
+
|
|
240
273
|
/**
|
|
241
274
|
* The workers an executor ran the run on (vx-dte's): the cores its tasks
|
|
242
275
|
* booked beside the cores they used, each averaged over the time the
|