@lodestar/spec-test-util 1.43.0-dev.b7d69444c9 → 1.43.0-dev.bc569affb9
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/downloadNightlyTests.d.ts +7 -0
- package/lib/downloadNightlyTests.d.ts.map +1 -0
- package/lib/downloadNightlyTests.js +67 -0
- package/lib/downloadNightlyTests.js.map +1 -0
- package/lib/downloadTests.d.ts +3 -1
- package/lib/downloadTests.d.ts.map +1 -1
- package/lib/downloadTests.js +5 -4
- package/lib/downloadTests.js.map +1 -1
- package/package.json +9 -4
- package/src/downloadNightlyTests.ts +89 -0
- package/src/downloadTests.ts +14 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"downloadNightlyTests.d.ts","sourceRoot":"","sources":["../src/downloadNightlyTests.ts"],"names":[],"mappings":"AA0CA,wBAAsB,oBAAoB,CACxC,IAAI,EAAE;IAAC,gBAAgB,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAC,EAC/F,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,EAC1B,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC,CA0Cf"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { fetch } from "@lodestar/utils";
|
|
2
|
+
import { downloadGenericSpecTests } from "./downloadTests.js";
|
|
3
|
+
async function ghApiFetch(endpoint, token) {
|
|
4
|
+
const res = await fetch(`https://api.github.com${endpoint}`, {
|
|
5
|
+
headers: { Authorization: `token ${token}`, Accept: "application/vnd.github+json" },
|
|
6
|
+
signal: AbortSignal.timeout(30_000),
|
|
7
|
+
});
|
|
8
|
+
if (!res.ok) {
|
|
9
|
+
throw new Error(res.status === 401 ? "GITHUB_TOKEN is invalid or expired" : `GitHub API ${res.status} (${endpoint})`);
|
|
10
|
+
}
|
|
11
|
+
return res.json();
|
|
12
|
+
}
|
|
13
|
+
async function resolveNightlyRunId(repo, token, date, branch) {
|
|
14
|
+
const params = new URLSearchParams({ status: "success", per_page: "1" });
|
|
15
|
+
if (branch)
|
|
16
|
+
params.append("branch", branch);
|
|
17
|
+
// If neither branch nor date narrow the query, restrict to scheduled runs so
|
|
18
|
+
// a PR's successful run on consensus-specs can't outrank the latest master
|
|
19
|
+
// nightly. When a date is given, allow manual re-runs on that day too.
|
|
20
|
+
else if (!date)
|
|
21
|
+
params.append("event", "schedule");
|
|
22
|
+
if (date)
|
|
23
|
+
params.append("created", date);
|
|
24
|
+
const { workflow_runs } = await ghApiFetch(`/repos/${repo}/actions/workflows/tests.yml/runs?${params}`, token);
|
|
25
|
+
const runId = workflow_runs[0]?.id;
|
|
26
|
+
if (!runId) {
|
|
27
|
+
throw new Error(`No successful run found${date ? ` on ${date}` : ""} for ${repo}${branch ? ` (${branch})` : ""}`);
|
|
28
|
+
}
|
|
29
|
+
return runId;
|
|
30
|
+
}
|
|
31
|
+
export async function downloadNightlyTests(opts, log, date) {
|
|
32
|
+
const token = process.env.GITHUB_TOKEN;
|
|
33
|
+
if (!token)
|
|
34
|
+
throw new Error("GITHUB_TOKEN is required for nightly downloads");
|
|
35
|
+
const resolvedDate = date === "latest" || !date ? undefined : date;
|
|
36
|
+
if (resolvedDate && !/^\d{4}-\d{2}-\d{2}$/.test(resolvedDate)) {
|
|
37
|
+
throw new Error(`Invalid date: "${date}". Expected "latest" or YYYY-MM-DD`);
|
|
38
|
+
}
|
|
39
|
+
const repo = new URL(opts.specTestsRepoUrl).pathname.slice(1).replace(/\/$/, "");
|
|
40
|
+
const runId = await resolveNightlyRunId(repo, token, resolvedDate, opts.branch);
|
|
41
|
+
log(`Resolved nightly${resolvedDate ? ` ${resolvedDate}` : ""} to run ${runId}`);
|
|
42
|
+
const { artifacts } = await ghApiFetch(`/repos/${repo}/actions/runs/${runId}/artifacts`, token);
|
|
43
|
+
const urlByTest = {};
|
|
44
|
+
const available = [];
|
|
45
|
+
for (const test of opts.testsToDownload) {
|
|
46
|
+
const artifact = artifacts.find((a) => a.name === `${test}.tar.gz` && !a.expired);
|
|
47
|
+
if (artifact) {
|
|
48
|
+
urlByTest[test] = artifact.archive_download_url;
|
|
49
|
+
available.push(test);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
log(`Skipping ${test} (not found in run ${runId})`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (available.length === 0)
|
|
56
|
+
throw new Error(`No matching artifacts found in run ${runId}`);
|
|
57
|
+
const authInit = { headers: { Authorization: `token ${token}`, Accept: "application/vnd.github+json" } };
|
|
58
|
+
await downloadGenericSpecTests({
|
|
59
|
+
specVersion: `nightly-${runId}`,
|
|
60
|
+
specTestsRepoUrl: opts.specTestsRepoUrl,
|
|
61
|
+
outputDir: opts.outputDir,
|
|
62
|
+
testsToDownload: available,
|
|
63
|
+
testUrls: urlByTest,
|
|
64
|
+
fetchInit: authInit,
|
|
65
|
+
}, log);
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=downloadNightlyTests.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"downloadNightlyTests.js","sourceRoot":"","sources":["../src/downloadNightlyTests.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,EAAC,MAAM,iBAAiB,CAAC;AACtC,OAAO,EAAC,wBAAwB,EAAC,MAAM,oBAAoB,CAAC;AAK5D,KAAK,UAAU,UAAU,CAAI,QAAgB,EAAE,KAAa,EAAc;IACxE,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,yBAAyB,QAAQ,EAAE,EAAE;QAC3D,OAAO,EAAE,EAAC,aAAa,EAAE,SAAS,KAAK,EAAE,EAAE,MAAM,EAAE,6BAA6B,EAAC;QACjF,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC;KACpC,CAAC,CAAC;IAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,GAAG,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,oCAAoC,CAAC,CAAC,CAAC,cAAc,GAAG,CAAC,MAAM,KAAK,QAAQ,GAAG,CACrG,CAAC;IACJ,CAAC;IAED,OAAO,GAAG,CAAC,IAAI,EAAgB,CAAC;AAAA,CACjC;AAED,KAAK,UAAU,mBAAmB,CAAC,IAAY,EAAE,KAAa,EAAE,IAAa,EAAE,MAAe,EAAmB;IAC/G,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,EAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,EAAC,CAAC,CAAC;IACvE,IAAI,MAAM;QAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC5C,6EAA6E;IAC7E,2EAA2E;IAC3E,uEAAuE;SAClE,IAAI,CAAC,IAAI;QAAE,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IACnD,IAAI,IAAI;QAAE,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAEzC,MAAM,EAAC,aAAa,EAAC,GAAG,MAAM,UAAU,CACtC,UAAU,IAAI,qCAAqC,MAAM,EAAE,EAC3D,KAAK,CACN,CAAC;IAEF,MAAM,KAAK,GAAG,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IACnC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,0BAA0B,IAAI,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACpH,CAAC;IACD,OAAO,KAAK,CAAC;AAAA,CACd;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,IAA+F,EAC/F,GAA0B,EAC1B,IAAa,EACE;IACf,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;IACvC,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IAE9E,MAAM,YAAY,GAAG,IAAI,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;IACnE,IAAI,YAAY,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;QAC9D,MAAM,IAAI,KAAK,CAAC,kBAAkB,IAAI,oCAAoC,CAAC,CAAC;IAC9E,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACjF,MAAM,KAAK,GAAG,MAAM,mBAAmB,CAAC,IAAI,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAChF,GAAG,CAAC,mBAAmB,YAAY,CAAC,CAAC,CAAC,IAAI,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,KAAK,EAAE,CAAC,CAAC;IAEjF,MAAM,EAAC,SAAS,EAAC,GAAG,MAAM,UAAU,CAAwB,UAAU,IAAI,iBAAiB,KAAK,YAAY,EAAE,KAAK,CAAC,CAAC;IAErH,MAAM,SAAS,GAA2B,EAAE,CAAC;IAC7C,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;QACxC,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,GAAG,IAAI,SAAS,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QAClF,IAAI,QAAQ,EAAE,CAAC;YACb,SAAS,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,oBAAoB,CAAC;YAChD,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvB,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,YAAY,IAAI,sBAAsB,KAAK,GAAG,CAAC,CAAC;QACtD,CAAC;IACH,CAAC;IAED,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,sCAAsC,KAAK,EAAE,CAAC,CAAC;IAE3F,MAAM,QAAQ,GAAgB,EAAC,OAAO,EAAE,EAAC,aAAa,EAAE,SAAS,KAAK,EAAE,EAAE,MAAM,EAAE,6BAA6B,EAAC,EAAC,CAAC;IAElH,MAAM,wBAAwB,CAC5B;QACE,WAAW,EAAE,WAAW,KAAK,EAAE;QAC/B,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;QACvC,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,eAAe,EAAE,SAAS;QAC1B,QAAQ,EAAE,SAAS;QACnB,SAAS,EAAE,QAAQ;KACpB,EACD,GAAG,CACJ,CAAC;AAAA,CACH"}
|
package/lib/downloadTests.d.ts
CHANGED
|
@@ -12,6 +12,8 @@ export interface DownloadGenericTestsOptions<TestNames extends string> {
|
|
|
12
12
|
outputDir: string;
|
|
13
13
|
specTestsRepoUrl: string;
|
|
14
14
|
testsToDownload: TestNames[];
|
|
15
|
+
testUrls?: Record<string, string>;
|
|
16
|
+
fetchInit?: RequestInit;
|
|
15
17
|
}
|
|
16
18
|
/**
|
|
17
19
|
* Download spec tests
|
|
@@ -21,5 +23,5 @@ export declare function downloadTests(opts: DownloadTestsOptions, log?: (msg: st
|
|
|
21
23
|
* Generic Github release downloader.
|
|
22
24
|
* Used by spec tests and SlashingProtectionInterchangeTest
|
|
23
25
|
*/
|
|
24
|
-
export declare function downloadGenericSpecTests<TestNames extends string>({ specVersion, specTestsRepoUrl, outputDir, testsToDownload }: DownloadGenericTestsOptions<TestNames>, log?: (msg: string) => void): Promise<void>;
|
|
26
|
+
export declare function downloadGenericSpecTests<TestNames extends string>({ specVersion, specTestsRepoUrl, outputDir, testsToDownload, testUrls, fetchInit }: DownloadGenericTestsOptions<TestNames>, log?: (msg: string) => void): Promise<void>;
|
|
25
27
|
//# sourceMappingURL=downloadTests.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"downloadTests.d.ts","sourceRoot":"","sources":["../src/downloadTests.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,uBAAuB,gDAAgD,CAAC;AAIrF,MAAM,MAAM,oBAAoB,GAAG;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,gBAAgB,EAAE,MAAM,CAAC;IACzB,yFAAyF;IACzF,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B,CAAC;AAEF,MAAM,WAAW,2BAA2B,CAAC,SAAS,SAAS,MAAM;IACnE,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,SAAS,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"downloadTests.d.ts","sourceRoot":"","sources":["../src/downloadTests.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,uBAAuB,gDAAgD,CAAC;AAIrF,MAAM,MAAM,oBAAoB,GAAG;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,gBAAgB,EAAE,MAAM,CAAC;IACzB,yFAAyF;IACzF,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B,CAAC;AAEF,MAAM,WAAW,2BAA2B,CAAC,SAAS,SAAS,MAAM;IACnE,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,SAAS,EAAE,CAAC;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,SAAS,CAAC,EAAE,WAAW,CAAC;CACzB;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,oBAAoB,EAAE,GAAG,GAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAEpH;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,CAAC,SAAS,SAAS,MAAM,EACrE,EACE,WAAW,EACX,gBAAgB,EAChB,SAAS,EACT,eAAe,EACf,QAAQ,EACR,SAAS,EACV,EAAE,2BAA2B,CAAC,SAAS,CAAC,EACzC,GAAG,GAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAe,GACpC,OAAO,CAAC,IAAI,CAAC,CAiEf"}
|
package/lib/downloadTests.js
CHANGED
|
@@ -17,7 +17,7 @@ export async function downloadTests(opts, log = logEmpty) {
|
|
|
17
17
|
* Generic Github release downloader.
|
|
18
18
|
* Used by spec tests and SlashingProtectionInterchangeTest
|
|
19
19
|
*/
|
|
20
|
-
export async function downloadGenericSpecTests({ specVersion, specTestsRepoUrl, outputDir, testsToDownload }, log = logEmpty) {
|
|
20
|
+
export async function downloadGenericSpecTests({ specVersion, specTestsRepoUrl, outputDir, testsToDownload, testUrls, fetchInit, }, log = logEmpty) {
|
|
21
21
|
log(`outputDir = ${outputDir}`);
|
|
22
22
|
// Use version.txt as a flag to prevent re-downloading the tests
|
|
23
23
|
const versionFile = path.join(outputDir, "version.txt");
|
|
@@ -32,10 +32,11 @@ export async function downloadGenericSpecTests({ specVersion, specTestsRepoUrl,
|
|
|
32
32
|
}
|
|
33
33
|
fs.mkdirSync(outputDir, { recursive: true });
|
|
34
34
|
await Promise.all(testsToDownload.map(async (test) => {
|
|
35
|
-
const
|
|
35
|
+
const defaultUrl = `${specTestsRepoUrl ?? defaultSpecTestsRepoUrl}/releases/download/${specVersion}/${test}.tar.gz`;
|
|
36
36
|
const tarball = path.join(outputDir, `${test}.tar.gz`);
|
|
37
37
|
await retry(async () => {
|
|
38
|
-
const
|
|
38
|
+
const url = testUrls?.[test] ?? defaultUrl;
|
|
39
|
+
const res = await fetch(url, { signal: AbortSignal.timeout(30 * 60 * 1000), ...fetchInit });
|
|
39
40
|
if (!res.ok) {
|
|
40
41
|
throw new Error(`Failed to download file from ${url}: ${res.status} ${res.statusText}`);
|
|
41
42
|
}
|
|
@@ -56,7 +57,7 @@ export async function downloadGenericSpecTests({ specVersion, specTestsRepoUrl,
|
|
|
56
57
|
}, {
|
|
57
58
|
retries: 3,
|
|
58
59
|
onRetry: (e, attempt) => {
|
|
59
|
-
log(`Download attempt ${attempt} for ${
|
|
60
|
+
log(`Download attempt ${attempt} for ${test} failed: ${e.message}`);
|
|
60
61
|
},
|
|
61
62
|
});
|
|
62
63
|
// download tar
|
package/lib/downloadTests.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"downloadTests.js","sourceRoot":"","sources":["../src/downloadTests.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAC,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AAE9C,OAAO,EAAC,SAAS,EAAC,MAAM,WAAW,CAAC;AACpC,OAAO,EAAC,MAAM,EAAC,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAC,KAAK,EAAE,KAAK,EAAC,MAAM,iBAAiB,CAAC;AAE7C,MAAM,CAAC,MAAM,uBAAuB,GAAG,6CAA6C,CAAC;AAErF,MAAM,QAAQ,GAAG,GAAS,EAAE,CAAC,EAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"downloadTests.js","sourceRoot":"","sources":["../src/downloadTests.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAC,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AAE9C,OAAO,EAAC,SAAS,EAAC,MAAM,WAAW,CAAC;AACpC,OAAO,EAAC,MAAM,EAAC,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAC,KAAK,EAAE,KAAK,EAAC,MAAM,iBAAiB,CAAC;AAE7C,MAAM,CAAC,MAAM,uBAAuB,GAAG,6CAA6C,CAAC;AAErF,MAAM,QAAQ,GAAG,GAAS,EAAE,CAAC,EAAC,CAAC,CAAC;AAoBhC;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAA0B,EAAE,GAAG,GAA0B,QAAQ,EAAiB;IACpH,MAAM,wBAAwB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AAAA,CAC3C;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,EACE,WAAW,EACX,gBAAgB,EAChB,SAAS,EACT,eAAe,EACf,QAAQ,EACR,SAAS,GAC8B,EACzC,GAAG,GAA0B,QAAQ,EACtB;IACf,GAAG,CAAC,eAAe,SAAS,EAAE,CAAC,CAAC;IAEhC,gEAAgE;IAChE,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;IACxD,MAAM,eAAe,GAAG,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IAElG,IAAI,eAAe,KAAK,WAAW,EAAE,CAAC;QACpC,OAAO,GAAG,CAAC,WAAW,WAAW,qBAAqB,CAAC,CAAC;IAC1D,CAAC;IACD,GAAG,CAAC,2BAA2B,WAAW,EAAE,CAAC,CAAC;IAE9C,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7B,GAAG,CAAC,6BAA6B,eAAe,OAAO,SAAS,EAAE,CAAC,CAAC;QACpE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACzB,CAAC;IAED,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAC,SAAS,EAAE,IAAI,EAAC,CAAC,CAAC;IAE3C,MAAM,OAAO,CAAC,GAAG,CACf,eAAe,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC;QAClC,MAAM,UAAU,GAAG,GAAG,gBAAgB,IAAI,uBAAuB,sBAAsB,WAAW,IAAI,IAAI,SAAS,CAAC;QACpH,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,IAAI,SAAS,CAAC,CAAC;QAEvD,MAAM,KAAK,CACT,KAAK,IAAI,EAAE,CAAC;YACV,MAAM,GAAG,GAAG,QAAQ,EAAE,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC;YAC3C,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,EAAE,GAAG,SAAS,EAAC,CAAC,CAAC;YAE1F,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,MAAM,IAAI,KAAK,CAAC,gCAAgC,GAAG,KAAK,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC;YAC1F,CAAC;YAED,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;gBACd,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;YAC3C,CAAC;YAED,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;YACpD,GAAG,CAAC,eAAe,GAAG,MAAM,SAAS,QAAQ,CAAC,CAAC;YAE/C,wCAAwC;YACxC,MAAM,QAAQ,CAAC,GAAG,CAAC,IAAqC,EAAE,EAAE,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC;YACzF,GAAG,CAAC,cAAc,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC;YAE9D,oCAAoC;YACpC,MAAM,SAAS,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,eAAe,EAAE,iBAAiB,CAAC,EAAE;gBACvG,SAAS,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,EAAE,OAAO;aACvC,CAAC,CAAC;YACH,GAAG,CAAC,aAAa,OAAO,OAAO,SAAS,EAAE,CAAC,CAAC;YAE5C,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAAA,CACxB,EACD;YACE,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC;gBACvB,GAAG,CAAC,oBAAoB,OAAO,QAAQ,IAAI,YAAY,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;YAAA,CACrE;SACF,CACF,CAAC;QAEF,eAAe;IAFb,CAGH,CAAC,CACH,CAAC;IAEF,EAAE,CAAC,aAAa,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;AAAA,CAC5C"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lodestar/spec-test-util",
|
|
3
|
-
"version": "1.43.0-dev.
|
|
3
|
+
"version": "1.43.0-dev.bc569affb9",
|
|
4
4
|
"description": "Spec test suite generator from yaml test files",
|
|
5
5
|
"author": "ChainSafe Systems",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -19,6 +19,11 @@
|
|
|
19
19
|
"bun": "./src/downloadTests.ts",
|
|
20
20
|
"types": "./lib/downloadTests.d.ts",
|
|
21
21
|
"import": "./lib/downloadTests.js"
|
|
22
|
+
},
|
|
23
|
+
"./downloadNightlyTests": {
|
|
24
|
+
"bun": "./src/downloadNightlyTests.ts",
|
|
25
|
+
"types": "./lib/downloadNightlyTests.d.ts",
|
|
26
|
+
"import": "./lib/downloadNightlyTests.js"
|
|
22
27
|
}
|
|
23
28
|
},
|
|
24
29
|
"files": [
|
|
@@ -54,15 +59,15 @@
|
|
|
54
59
|
"blockchain"
|
|
55
60
|
],
|
|
56
61
|
"dependencies": {
|
|
57
|
-
"@lodestar/utils": "^1.43.0-dev.
|
|
62
|
+
"@lodestar/utils": "^1.43.0-dev.bc569affb9",
|
|
58
63
|
"rimraf": "^4.4.1",
|
|
59
64
|
"snappyjs": "^0.7.0",
|
|
60
65
|
"vitest": "catalog:"
|
|
61
66
|
},
|
|
62
67
|
"peerDependencies": {
|
|
63
68
|
"@chainsafe/ssz": "^1.4.0",
|
|
64
|
-
"@lodestar/types": "^1.43.0-dev.
|
|
69
|
+
"@lodestar/types": "^1.43.0-dev.bc569affb9",
|
|
65
70
|
"vitest": "catalog:"
|
|
66
71
|
},
|
|
67
|
-
"gitHead": "
|
|
72
|
+
"gitHead": "e8c887fd0ffa2587b0627ee7ce4d4d1465b4154a"
|
|
68
73
|
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import {fetch} from "@lodestar/utils";
|
|
2
|
+
import {downloadGenericSpecTests} from "./downloadTests.js";
|
|
3
|
+
|
|
4
|
+
type WorkflowRunsResponse = {workflow_runs: {id: number}[]};
|
|
5
|
+
type ArtifactsListResponse = {artifacts: {archive_download_url: string; expired: boolean; name: string}[]};
|
|
6
|
+
|
|
7
|
+
async function ghApiFetch<T>(endpoint: string, token: string): Promise<T> {
|
|
8
|
+
const res = await fetch(`https://api.github.com${endpoint}`, {
|
|
9
|
+
headers: {Authorization: `token ${token}`, Accept: "application/vnd.github+json"},
|
|
10
|
+
signal: AbortSignal.timeout(30_000),
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
if (!res.ok) {
|
|
14
|
+
throw new Error(
|
|
15
|
+
res.status === 401 ? "GITHUB_TOKEN is invalid or expired" : `GitHub API ${res.status} (${endpoint})`
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return res.json() as Promise<T>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async function resolveNightlyRunId(repo: string, token: string, date?: string, branch?: string): Promise<number> {
|
|
23
|
+
const params = new URLSearchParams({status: "success", per_page: "1"});
|
|
24
|
+
if (branch) params.append("branch", branch);
|
|
25
|
+
// If neither branch nor date narrow the query, restrict to scheduled runs so
|
|
26
|
+
// a PR's successful run on consensus-specs can't outrank the latest master
|
|
27
|
+
// nightly. When a date is given, allow manual re-runs on that day too.
|
|
28
|
+
else if (!date) params.append("event", "schedule");
|
|
29
|
+
if (date) params.append("created", date);
|
|
30
|
+
|
|
31
|
+
const {workflow_runs} = await ghApiFetch<WorkflowRunsResponse>(
|
|
32
|
+
`/repos/${repo}/actions/workflows/tests.yml/runs?${params}`,
|
|
33
|
+
token
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const runId = workflow_runs[0]?.id;
|
|
37
|
+
if (!runId) {
|
|
38
|
+
throw new Error(`No successful run found${date ? ` on ${date}` : ""} for ${repo}${branch ? ` (${branch})` : ""}`);
|
|
39
|
+
}
|
|
40
|
+
return runId;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export async function downloadNightlyTests(
|
|
44
|
+
opts: {specTestsRepoUrl: string; outputDir: string; testsToDownload: string[]; branch?: string},
|
|
45
|
+
log: (msg: string) => void,
|
|
46
|
+
date?: string
|
|
47
|
+
): Promise<void> {
|
|
48
|
+
const token = process.env.GITHUB_TOKEN;
|
|
49
|
+
if (!token) throw new Error("GITHUB_TOKEN is required for nightly downloads");
|
|
50
|
+
|
|
51
|
+
const resolvedDate = date === "latest" || !date ? undefined : date;
|
|
52
|
+
if (resolvedDate && !/^\d{4}-\d{2}-\d{2}$/.test(resolvedDate)) {
|
|
53
|
+
throw new Error(`Invalid date: "${date}". Expected "latest" or YYYY-MM-DD`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const repo = new URL(opts.specTestsRepoUrl).pathname.slice(1).replace(/\/$/, "");
|
|
57
|
+
const runId = await resolveNightlyRunId(repo, token, resolvedDate, opts.branch);
|
|
58
|
+
log(`Resolved nightly${resolvedDate ? ` ${resolvedDate}` : ""} to run ${runId}`);
|
|
59
|
+
|
|
60
|
+
const {artifacts} = await ghApiFetch<ArtifactsListResponse>(`/repos/${repo}/actions/runs/${runId}/artifacts`, token);
|
|
61
|
+
|
|
62
|
+
const urlByTest: Record<string, string> = {};
|
|
63
|
+
const available: string[] = [];
|
|
64
|
+
for (const test of opts.testsToDownload) {
|
|
65
|
+
const artifact = artifacts.find((a) => a.name === `${test}.tar.gz` && !a.expired);
|
|
66
|
+
if (artifact) {
|
|
67
|
+
urlByTest[test] = artifact.archive_download_url;
|
|
68
|
+
available.push(test);
|
|
69
|
+
} else {
|
|
70
|
+
log(`Skipping ${test} (not found in run ${runId})`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (available.length === 0) throw new Error(`No matching artifacts found in run ${runId}`);
|
|
75
|
+
|
|
76
|
+
const authInit: RequestInit = {headers: {Authorization: `token ${token}`, Accept: "application/vnd.github+json"}};
|
|
77
|
+
|
|
78
|
+
await downloadGenericSpecTests(
|
|
79
|
+
{
|
|
80
|
+
specVersion: `nightly-${runId}`,
|
|
81
|
+
specTestsRepoUrl: opts.specTestsRepoUrl,
|
|
82
|
+
outputDir: opts.outputDir,
|
|
83
|
+
testsToDownload: available,
|
|
84
|
+
testUrls: urlByTest,
|
|
85
|
+
fetchInit: authInit,
|
|
86
|
+
},
|
|
87
|
+
log
|
|
88
|
+
);
|
|
89
|
+
}
|
package/src/downloadTests.ts
CHANGED
|
@@ -25,6 +25,8 @@ export interface DownloadGenericTestsOptions<TestNames extends string> {
|
|
|
25
25
|
outputDir: string;
|
|
26
26
|
specTestsRepoUrl: string;
|
|
27
27
|
testsToDownload: TestNames[];
|
|
28
|
+
testUrls?: Record<string, string>;
|
|
29
|
+
fetchInit?: RequestInit;
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
/**
|
|
@@ -39,7 +41,14 @@ export async function downloadTests(opts: DownloadTestsOptions, log: (msg: strin
|
|
|
39
41
|
* Used by spec tests and SlashingProtectionInterchangeTest
|
|
40
42
|
*/
|
|
41
43
|
export async function downloadGenericSpecTests<TestNames extends string>(
|
|
42
|
-
{
|
|
44
|
+
{
|
|
45
|
+
specVersion,
|
|
46
|
+
specTestsRepoUrl,
|
|
47
|
+
outputDir,
|
|
48
|
+
testsToDownload,
|
|
49
|
+
testUrls,
|
|
50
|
+
fetchInit,
|
|
51
|
+
}: DownloadGenericTestsOptions<TestNames>,
|
|
43
52
|
log: (msg: string) => void = logEmpty
|
|
44
53
|
): Promise<void> {
|
|
45
54
|
log(`outputDir = ${outputDir}`);
|
|
@@ -62,12 +71,13 @@ export async function downloadGenericSpecTests<TestNames extends string>(
|
|
|
62
71
|
|
|
63
72
|
await Promise.all(
|
|
64
73
|
testsToDownload.map(async (test) => {
|
|
65
|
-
const
|
|
74
|
+
const defaultUrl = `${specTestsRepoUrl ?? defaultSpecTestsRepoUrl}/releases/download/${specVersion}/${test}.tar.gz`;
|
|
66
75
|
const tarball = path.join(outputDir, `${test}.tar.gz`);
|
|
67
76
|
|
|
68
77
|
await retry(
|
|
69
78
|
async () => {
|
|
70
|
-
const
|
|
79
|
+
const url = testUrls?.[test] ?? defaultUrl;
|
|
80
|
+
const res = await fetch(url, {signal: AbortSignal.timeout(30 * 60 * 1000), ...fetchInit});
|
|
71
81
|
|
|
72
82
|
if (!res.ok) {
|
|
73
83
|
throw new Error(`Failed to download file from ${url}: ${res.status} ${res.statusText}`);
|
|
@@ -95,7 +105,7 @@ export async function downloadGenericSpecTests<TestNames extends string>(
|
|
|
95
105
|
{
|
|
96
106
|
retries: 3,
|
|
97
107
|
onRetry: (e, attempt) => {
|
|
98
|
-
log(`Download attempt ${attempt} for ${
|
|
108
|
+
log(`Download attempt ${attempt} for ${test} failed: ${e.message}`);
|
|
99
109
|
},
|
|
100
110
|
}
|
|
101
111
|
);
|