1e6b0e5684
使用专用 BuildKit builder 持久复用 Cargo 与 npm 下载缓存,并支持从可信镜像导入 按当前依赖物化镜像下载快照,配置独立缓存回收策略 补齐 AGC vendor 本地依赖清单并缩小构建上下文 增加缓存维护阶段、耗时和失败日志路径 补充下载缓存与构建上下文测试,同步部署说明和共享记忆
84 lines
3.1 KiB
JavaScript
84 lines
3.1 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import { spawnSync } from 'node:child_process';
|
|
import { existsSync } from 'node:fs';
|
|
import fs from 'node:fs/promises';
|
|
import { createRequire } from 'node:module';
|
|
import os from 'node:os';
|
|
import path from 'node:path';
|
|
import test from 'node:test';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const npmRoot = [
|
|
path.resolve(path.dirname(process.execPath), 'node_modules/npm'),
|
|
path.resolve(path.dirname(process.execPath), '../lib/node_modules/npm'),
|
|
...(process.env.npm_execpath
|
|
? [path.resolve(path.dirname(process.env.npm_execpath), '..')]
|
|
: []),
|
|
].find((root) => existsSync(path.join(root, 'node_modules/cacache')));
|
|
assert.ok(npmRoot, 'tests require the cacache bundled with npm');
|
|
const cacache = createRequire(path.join(npmRoot, 'package.json'))('cacache');
|
|
const script = fileURLToPath(
|
|
new URL('./export-ci-npm-download-cache.mjs', import.meta.url),
|
|
);
|
|
|
|
async function fixture(t) {
|
|
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'ci-npm-snapshot-'));
|
|
t.after(() => fs.rm(root, { recursive: true, force: true }));
|
|
const source = path.join(root, 'source');
|
|
const destination = path.join(root, 'destination');
|
|
const lock = path.join(root, 'package-lock.json');
|
|
const key =
|
|
'make-fetch-happen:request-cache:https://registry.npmjs.org/example/-/example-1.0.0.tgz';
|
|
const metadata = {
|
|
url: key.slice('make-fetch-happen:request-cache:'.length),
|
|
};
|
|
const integrity = String(
|
|
await cacache.put(source, key, 'current-package', { metadata }),
|
|
);
|
|
await cacache.put(source, 'old-package', 'unused-old-version');
|
|
await fs.writeFile(
|
|
lock,
|
|
JSON.stringify({ packages: { 'node_modules/example': { integrity } } }),
|
|
);
|
|
const run = () =>
|
|
spawnSync(process.execPath, [script, npmRoot, lock, source, destination], {
|
|
encoding: 'utf8',
|
|
});
|
|
return { source, destination, key, metadata, integrity, run };
|
|
}
|
|
|
|
test('exports only current lock content, preserving npm request metadata for offline use', async (t) => {
|
|
const f = await fixture(t);
|
|
const result = f.run();
|
|
assert.equal(result.status, 0, result.stderr);
|
|
assert.deepEqual(Object.keys(await cacache.ls(f.destination)), [f.key]);
|
|
const output = await cacache.get(f.destination, f.key);
|
|
assert.equal(output.data.toString(), 'current-package');
|
|
assert.deepEqual(output.metadata, f.metadata);
|
|
// 输出是独立快照;移走持久缓存仍可使用,不依赖挂载、链接或旧 builder。
|
|
await fs.rm(f.source, { recursive: true });
|
|
assert.equal(
|
|
(await cacache.get(f.destination, f.key)).data.toString(),
|
|
'current-package',
|
|
);
|
|
});
|
|
|
|
test('rejects a corrupted cached package instead of publishing it', async (t) => {
|
|
const f = await fixture(t);
|
|
const digest = Buffer.from(f.integrity.split('-')[1], 'base64').toString(
|
|
'hex',
|
|
);
|
|
const contentPath = path.join(
|
|
f.source,
|
|
'content-v2',
|
|
'sha512',
|
|
digest.slice(0, 2),
|
|
digest.slice(2, 4),
|
|
digest.slice(4),
|
|
);
|
|
await fs.writeFile(contentPath, 'corrupted-package');
|
|
const result = f.run();
|
|
assert.notEqual(result.status, 0);
|
|
assert.match(result.stderr, /EINTEGRITY|EBADSIZE/);
|
|
});
|