Configure runtime lane download stack

This commit is contained in:
Codex Agent
2026-06-08 15:39:17 +08:00
parent e63e2afbe4
commit f4b6c12488
4 changed files with 166 additions and 5 deletions
+51 -1
View File
@@ -108,7 +108,7 @@ export async function createG14CiPlan(options = {}) {
...buildSystemMatches
].filter((item) => !isTestOnlyPath(item) && !isDocsOnlyPath(item)));
const catalogRecord = catalogByServiceId.get(model.serviceId) ?? null;
const environmentInputHash = envReuse ? await hashGitPaths(repoRoot, targetRef, envInputPaths, {
const environmentInputHash = envReuse ? await hashEnvReuseInputs(repoRoot, targetRef, envInputPaths, envReuseRecipe.publicRecipe, {
skipPath: (filePath) => isTestOnlyPath(filePath) || isDocsOnlyPath(filePath),
semanticPackageJson: true
}) : null;
@@ -339,6 +339,7 @@ function envReuseRecipeForLaneConfig(laneConfig, lane = "v02") {
...additionalEnvPaths
]);
const hwpodAliases = normalizeHwpodAliases(configured.hwpodAliases);
const downloadStack = normalizeDownloadStack(configured.downloadStack, lane);
if (osPackages.length === 0) throw new Error(`deploy.lanes.${lane}.envRecipe.osPackages is required`);
if (additionalEnvPaths.length === 0) throw new Error(`deploy.lanes.${lane}.envRecipe.additionalEnvPaths is required`);
if (hwpodAliases.length === 0) throw new Error(`deploy.lanes.${lane}.envRecipe.hwpodAliases is required`);
@@ -349,6 +350,7 @@ function envReuseRecipeForLaneConfig(laneConfig, lane = "v02") {
runtimeNodeModulesPath,
additionalEnvPaths,
launcherInputPaths,
downloadStack,
hwpodAliases,
publicRecipe: {
osPackages,
@@ -356,11 +358,52 @@ function envReuseRecipeForLaneConfig(laneConfig, lane = "v02") {
launcherPath,
runtimeNodeModulesPath,
additionalEnvPaths,
downloadStack,
hwpodAliases
}
};
}
function normalizeDownloadStack(value, lane) {
const configured = value && typeof value === "object" ? value : null;
if (!configured) throw new Error(`deploy.lanes.${lane}.envRecipe.downloadStack is required`);
const httpProxy = normalizeOptionalHttpUrl(configured.httpProxy, `deploy.lanes.${lane}.envRecipe.downloadStack.httpProxy`);
const httpsProxy = normalizeOptionalHttpUrl(configured.httpsProxy, `deploy.lanes.${lane}.envRecipe.downloadStack.httpsProxy`);
const npmRegistry = normalizeOptionalHttpUrl(configured.npmRegistry, `deploy.lanes.${lane}.envRecipe.downloadStack.npmRegistry`);
const npmFetchTimeoutMs = Number(configured.npmFetchTimeoutMs);
const bunPackages = configured.bunPackages && typeof configured.bunPackages === "object" ? configured.bunPackages : null;
const x64 = normalizePackageName(bunPackages?.x64);
const arm64 = normalizePackageName(bunPackages?.arm64);
if (!npmRegistry) throw new Error(`deploy.lanes.${lane}.envRecipe.downloadStack.npmRegistry is required`);
if (!Number.isInteger(npmFetchTimeoutMs) || npmFetchTimeoutMs <= 0) {
throw new Error(`deploy.lanes.${lane}.envRecipe.downloadStack.npmFetchTimeoutMs must be a positive integer`);
}
if (!x64 || !arm64) throw new Error(`deploy.lanes.${lane}.envRecipe.downloadStack.bunPackages.x64/arm64 are required`);
return {
httpProxy,
httpsProxy,
noProxy: normalizeStringList(configured.noProxy, []),
npmRegistry,
npmFetchTimeoutMs,
bunPackages: { x64, arm64 }
};
}
function normalizeOptionalHttpUrl(value, label) {
const text = normalizeDeclarationString(value);
if (!text) return null;
try {
const url = new URL(text);
if (url.protocol === "http:" || url.protocol === "https:") return text;
} catch {}
throw new Error(`${label} must be an http(s) URL`);
}
function normalizePackageName(value) {
const text = normalizeDeclarationString(value);
return text && !text.includes(" ") ? text : null;
}
function normalizeStringList(value, fallback) {
const list = Array.isArray(value) ? value : fallback;
return list.map((item) => String(item ?? "").trim()).filter(Boolean);
@@ -532,6 +575,13 @@ export async function hashGitPaths(repoRoot, targetRef, paths, options = {}) {
return stableHash({ entries: lines });
}
async function hashEnvReuseInputs(repoRoot, targetRef, paths, recipe, options = {}) {
return stableHash({
gitPaths: await hashGitPaths(repoRoot, targetRef, paths, options),
envRecipe: recipe
});
}
export async function lastCommitForPaths(repoRoot, targetRef, paths) {
const normalizedPaths = uniqueSorted(paths.map(normalizeRepoPath).filter(Boolean));
if (normalizedPaths.length === 0) return null;