@vzn/vx-history 0.0.650 → 0.0.651
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 +2 -0
- package/package.json +2 -2
- package/src/history-server.ts +2 -1
- package/src/index.ts +22 -6
package/README.md
CHANGED
|
@@ -47,6 +47,8 @@ for its tasks' numbers, by task definition, in the refs the run reads,
|
|
|
47
47
|
as a remote cache does: its branch's, the branch it merges into, then
|
|
48
48
|
the default branch's (`baseBranch`, else git's or the CI's). A run
|
|
49
49
|
that reads no ref (a detached HEAD with no default branch) asks nothing.
|
|
50
|
+
A ref over the 512 characters a server takes is said and not read;
|
|
51
|
+
the run reads the others.
|
|
50
52
|
The run starts on its local history and re-ranks the tasks not yet
|
|
51
53
|
started when they land; it never waits for them. At its end it sends the
|
|
52
54
|
timings of the tasks it ran, once: under DTE that is the orchestrator,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vzn/vx-history",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.651",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "History-based scheduling for vx — a `schedule` plugin that orders ready tasks by their expected remaining critical path, learned from the local run history.",
|
|
6
6
|
"keywords": [
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"access": "public"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
|
-
"@vzn/vx": "^0.0.
|
|
40
|
+
"@vzn/vx": "^0.0.651"
|
|
41
41
|
},
|
|
42
42
|
"repository": {
|
|
43
43
|
"type": "git",
|
package/src/history-server.ts
CHANGED
|
@@ -181,7 +181,8 @@ export class HistoryServer {
|
|
|
181
181
|
u.searchParams.set('audience', new URL(this.url).origin)
|
|
182
182
|
const res = await this.askGithub(u, signal)
|
|
183
183
|
if (!res.ok) throw new Error(`GitHub's OIDC endpoint: ${(await refusal(res)).message}`)
|
|
184
|
-
|
|
184
|
+
// quiet: a body that is not JSON holds no token, said below
|
|
185
|
+
const jwt = ((await res.json().catch(() => null)) as { value?: unknown } | null)?.value
|
|
185
186
|
if (typeof jwt !== 'string' || jwt === '') throw new Error("GitHub's OIDC endpoint: no token")
|
|
186
187
|
return { jwt, exp: expiryOf(jwt) }
|
|
187
188
|
})()
|
package/src/index.ts
CHANGED
|
@@ -109,6 +109,9 @@ export interface VxHistoryOptions {
|
|
|
109
109
|
// hint needs less and reads a 2.5× smaller slice of the run history.
|
|
110
110
|
const DEFAULT_WINDOW = 20
|
|
111
111
|
|
|
112
|
+
/** The longest ref a history server takes in a query (its PROTOCOL.md). */
|
|
113
|
+
const REF_MAX = 512
|
|
114
|
+
|
|
112
115
|
// Each option is read in ONE place that a run's hooks and `vx history`
|
|
113
116
|
// share: two copies of each let either drift unseen (item 805).
|
|
114
117
|
const windowOf = (options: VxHistoryOptions): number =>
|
|
@@ -277,6 +280,11 @@ function namedOf(issuer: unknown, repository: unknown): Named {
|
|
|
277
280
|
return { issuer: issuer.replace(/\/$/, ''), repository: repository.toLowerCase() }
|
|
278
281
|
}
|
|
279
282
|
|
|
283
|
+
/** `url` as a refusal may print it: a `user:pass@` would reach the CI log. */
|
|
284
|
+
function shown(url: string): string {
|
|
285
|
+
return url.replace(/^([a-z][a-z0-9+.-]*:\/\/)[^/?#]*@/i, '$1***@')
|
|
286
|
+
}
|
|
287
|
+
|
|
280
288
|
/**
|
|
281
289
|
* https, or http to this machine: every request carries the CI token, and
|
|
282
290
|
* http:// to another host sent it in clear.
|
|
@@ -299,12 +307,12 @@ function serverUrlOf(
|
|
|
299
307
|
const from = option === undefined ? 'VX_HISTORY_URL' : 'url'
|
|
300
308
|
if (!secure(url))
|
|
301
309
|
throw new UserError(
|
|
302
|
-
`vxHistory(): ${from} must be https (http only to 127.0.0.1, ::1 or localhost), got ${url}`,
|
|
310
|
+
`vxHistory(): ${from} must be https (http only to 127.0.0.1, ::1 or localhost), got ${shown(url)}`,
|
|
303
311
|
)
|
|
304
312
|
// Each route is the server's /v1/…: one that names /v1 asked /v1/v1/…, and every answer was a 404.
|
|
305
313
|
if (url.endsWith('/v1'))
|
|
306
314
|
throw new UserError(
|
|
307
|
-
`vxHistory(): ${from} is the server's base, without /v1: ${url.slice(0, -3)}`,
|
|
315
|
+
`vxHistory(): ${from} is the server's base, without /v1: ${shown(url.slice(0, -3))}`,
|
|
308
316
|
)
|
|
309
317
|
return url
|
|
310
318
|
}
|
|
@@ -440,14 +448,22 @@ export function vxHistory(options: VxHistoryOptions = {}): VxPlugin {
|
|
|
440
448
|
// branch it merges into, the default branch (`baseBranch`). `main`
|
|
441
449
|
// was assumed, so a `master` or `baseBranch: 'trunk'` repository
|
|
442
450
|
// read no trunk's numbers; a run with none asks nothing.
|
|
443
|
-
|
|
451
|
+
// A ref the server cannot name was a 400 for the whole query, and
|
|
452
|
+
// the run read no ref's numbers, its base branch's too.
|
|
453
|
+
const refs = [...new Set(ctx.refs)].filter((ref) => {
|
|
454
|
+
if (ref.length <= REF_MAX) return true
|
|
455
|
+
ctx.warn(
|
|
456
|
+
`[vx] vx-history: ${ref} is ${ref.length} characters, over the ${REF_MAX} a history server takes: the run does not read it`,
|
|
457
|
+
)
|
|
458
|
+
return false
|
|
459
|
+
})
|
|
444
460
|
if (remote !== undefined && refs.length > 0) {
|
|
445
461
|
const server = remote
|
|
446
462
|
let late = false
|
|
447
463
|
stopImport = () => (late = true)
|
|
448
464
|
const weights = (async () => {
|
|
449
465
|
const hashes = [...new Set(ids.flatMap((id) => defs.get(id) ?? []))]
|
|
450
|
-
const got = await server.query(
|
|
466
|
+
const got = await server.query(refs, hashes)
|
|
451
467
|
const timings = new Map<string, number>()
|
|
452
468
|
const needs = new Map<string, TaskResources>()
|
|
453
469
|
for (const id of ids) {
|
|
@@ -800,7 +816,7 @@ async function historyCmd(
|
|
|
800
816
|
// A plugin verb owns its help; completions offer `--help` for every verb.
|
|
801
817
|
if (a === '--help' || a === '-h') {
|
|
802
818
|
ui.say('info', 'Usage: vx history [--format pretty|json]', 'out')
|
|
803
|
-
|
|
819
|
+
ui.print('out', ui.gap())
|
|
804
820
|
ui.say(
|
|
805
821
|
'info',
|
|
806
822
|
'What vx-history learned per task (p50, peak RSS, CPU parallelism) and the reservation it packs.',
|
|
@@ -876,7 +892,7 @@ async function historyCmd(
|
|
|
876
892
|
}
|
|
877
893
|
})
|
|
878
894
|
if (format === 'json') {
|
|
879
|
-
|
|
895
|
+
ui.data('out', `${JSON.stringify({ window, budgets, tasks: rows })}\n`)
|
|
880
896
|
return 0
|
|
881
897
|
}
|
|
882
898
|
// The table's module loads with the verb, off every run's path.
|