From ea3b26b895bcf587edfb54ecde922be72c39357a Mon Sep 17 00:00:00 2001 From: Lyon <88232613+pikasTech@users.noreply.github.com> Date: Sat, 13 Jun 2026 16:22:21 +0800 Subject: [PATCH] fix: scope Go envreuse packages to Go services (#1131) --- deploy/deploy.schema.json | 5 +++++ deploy/deploy.yaml | 1 + scripts/artifact-publish.mjs | 10 +++++++++- scripts/src/ci-plan-lib.mjs | 23 +++++++++++++++++++++-- 4 files changed, 36 insertions(+), 3 deletions(-) diff --git a/deploy/deploy.schema.json b/deploy/deploy.schema.json index 8cd5292a..5658281a 100644 --- a/deploy/deploy.schema.json +++ b/deploy/deploy.schema.json @@ -406,6 +406,11 @@ "items": { "type": "string", "minLength": 1 }, "uniqueItems": true }, + "goOsPackages": { + "type": "array", + "items": { "type": "string", "minLength": 1 }, + "uniqueItems": true + }, "bunVersion": { "type": "string", "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+" }, "launcherPath": { "$ref": "#/$defs/repoPath" }, "runtimeNodeModulesPath": { "type": "string", "pattern": "^/" }, diff --git a/deploy/deploy.yaml b/deploy/deploy.yaml index cfb41e6e..be4b6e72 100644 --- a/deploy/deploy.yaml +++ b/deploy/deploy.yaml @@ -353,6 +353,7 @@ lanes: osPackages: - ca-certificates - git + goOsPackages: - golang-go bunVersion: 1.3.13 downloadStack: diff --git a/scripts/artifact-publish.mjs b/scripts/artifact-publish.mjs index 3416812a..8a3e89c7 100644 --- a/scripts/artifact-publish.mjs +++ b/scripts/artifact-publish.mjs @@ -890,8 +890,12 @@ function envReuseDockerfile(baseImage, labels = [], recipe, service = null) { const goReadiness = goCacheEnabled ? `; mkdir -p ${shellQuote(normalizedRecipe.runtimeGoModCachePath)} ${shellQuote(normalizedRecipe.runtimeGoBuildCachePath)}; command -v go >/dev/null; go version >/tmp/hwlab-env-go-version.txt` : ""; + const osPackages = uniquePreserveOrder([ + ...normalizedRecipe.osPackages, + ...(goCacheEnabled ? normalizedRecipe.goOsPackages : []) + ]); const downloadDependencyScript = `set -eu; ${npmConfigScript}; if [ -f package-lock.json ]; then npm ci --omit=dev --include=optional --ignore-scripts; else npm install --omit=dev --include=optional --ignore-scripts; fi; if command -v bun >/dev/null 2>&1; then bun_path="$(command -v bun)"; if [ "$bun_path" != "/usr/local/bin/bun" ]; then ln -sf "$bun_path" /usr/local/bin/bun; fi; fi; if [ ! -x /usr/local/bin/bun ]; then bun_pkg=""; case "$(uname -m)" in x86_64|amd64) bun_pkg="${normalizedRecipe.downloadStack.bunPackages.x64}@${normalizedRecipe.bunVersion}" ;; aarch64|arm64) bun_pkg="${normalizedRecipe.downloadStack.bunPackages.arm64}@${normalizedRecipe.bunVersion}" ;; *) echo "unsupported bun architecture: $(uname -m)" >&2; false ;; esac; npm install --no-save --omit=dev --include=optional --ignore-scripts "$bun_pkg"; bun_bin="node_modules/\${bun_pkg%@*}/bin/bun"; test -x "$bun_bin"; ln -sf "${runtimeRoot}/$bun_bin" /usr/local/bin/bun; fi`; - const osPackageScript = `set -eu; apt-get update; apt-get install -y --no-install-recommends ${normalizedRecipe.osPackages.map(shellQuote).join(" ")}; rm -rf /var/lib/apt/lists/*`; + const osPackageScript = `set -eu; apt-get update; apt-get install -y --no-install-recommends ${osPackages.map(shellQuote).join(" ")}; rm -rf /var/lib/apt/lists/*`; const aliasScript = normalizedRecipe.hwpodAliases.map((alias) => `printf '%s\\n' '#!/usr/bin/env sh' 'exec node /workspace/hwlab-boot/repo/scripts/run-bun.mjs /workspace/hwlab-boot/repo/${alias.script} \"$@\"' > /usr/local/bin/${alias.command}; chmod 755 /usr/local/bin/${alias.command}`).join("; "); const readinessScript = `set -eu; command -v node >/dev/null; command -v npm >/dev/null; command -v git >/dev/null; command -v sh >/dev/null; test -d ${shellQuote(normalizedRecipe.runtimeNodeModulesPath)}; test -x /usr/local/bin/bun; /usr/local/bin/bun --version >/tmp/hwlab-env-bun-version.txt${goReadiness}; ${aliasScript}`; return [ @@ -919,6 +923,7 @@ function normalizeEnvReuseRecipe(recipe) { assert.ok(recipe && typeof recipe === "object", "envRecipe must be provided by deploy.lanes..envRecipe"); const normalized = { osPackages: normalizeStringList(recipe.osPackages), + goOsPackages: normalizeStringList(recipe.goOsPackages), bunVersion: String(recipe.bunVersion ?? "").trim(), launcherPath: normalizeRepoPath(recipe.launcherPath), runtimeNodeModulesPath: normalizeAbsolutePath(recipe.runtimeNodeModulesPath), @@ -929,6 +934,9 @@ function normalizeEnvReuseRecipe(recipe) { hwpodAliases: normalizeHwpodAliases(recipe.hwpodAliases) }; assert.ok(normalized.osPackages.length > 0, "envRecipe.osPackages must not be empty"); + if (normalized.runtimeGoModCachePath || normalized.runtimeGoBuildCachePath) { + assert.ok(normalized.goOsPackages.length > 0, "envRecipe.goOsPackages must not be empty when Go cache paths are configured"); + } assert.match(normalized.bunVersion, /^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/u, "envRecipe.bunVersion must be a semver-like version"); assert.ok(normalized.launcherPath && !normalized.launcherPath.split("/").includes(".."), "envRecipe.launcherPath must be repo-relative"); assert.ok(normalized.runtimeNodeModulesPath, "envRecipe.runtimeNodeModulesPath must be absolute"); diff --git a/scripts/src/ci-plan-lib.mjs b/scripts/src/ci-plan-lib.mjs index 3e4e8e24..9f9abb6a 100644 --- a/scripts/src/ci-plan-lib.mjs +++ b/scripts/src/ci-plan-lib.mjs @@ -97,6 +97,7 @@ export async function createCiPlan(options = {}) { const buildSystemMatches = matchingPaths(normalizedChangedPaths, model.buildSystemPaths); const envReuse = envReuseServices.has(model.serviceId); const bootSh = envReuse ? bootShForService(deployJson, model.serviceId, lane) : null; + const serviceEnvReuseRecipe = envReuse ? envReuseRecipeForService(envReuseRecipe.publicRecipe, model) : null; const envInputPaths = envReuse ? uniqueSorted([ ...model.runtimeDeps, ...envReuseRecipe.launcherInputPaths @@ -120,7 +121,7 @@ export async function createCiPlan(options = {}) { ...buildSystemMatches ].filter((item) => !isTestOnlyPath(item) && !isDocsOnlyPath(item))); const catalogRecord = catalogByServiceId.get(model.serviceId) ?? null; - const environmentInputHash = envReuse ? await hashEnvReuseInputs(repoRoot, targetRef, envInputPaths, envReuseRecipe.publicRecipe, { + const environmentInputHash = envReuse ? await hashEnvReuseInputs(repoRoot, targetRef, envInputPaths, serviceEnvReuseRecipe, { skipPath: (filePath) => isTestOnlyPath(filePath) || isDocsOnlyPath(filePath), semanticPackageJson: true }) : null; @@ -202,7 +203,7 @@ export async function createCiPlan(options = {}) { sharedPaths: model.sharedPaths, runtimeDeps: model.runtimeDeps, buildSystemPaths: model.buildSystemPaths, - envReuseRecipe: envReuse ? envReuseRecipe.publicRecipe : null, + envReuseRecipe: serviceEnvReuseRecipe, componentCommitId, componentInputHash, catalogSourceCommitId: catalogSourceCommitId || null, @@ -363,6 +364,7 @@ function envReuseRecipeForLaneConfig(laneConfig, lane = "v02") { const configured = laneConfig?.envRecipe; if (!configured) throw new Error(`deploy.lanes.${lane}.envRecipe is required`); const osPackages = normalizeStringList(configured.osPackages, []); + const goOsPackages = normalizeStringList(configured.goOsPackages, []); const bunVersion = requireDeclarationString(configured.bunVersion, lane, "envRecipe.bunVersion"); const launcherPath = normalizeRepoPath(requireDeclarationString(configured.launcherPath, lane, "envRecipe.launcherPath")); const runtimeNodeModulesPath = normalizeAbsolutePath(configured.runtimeNodeModulesPath); @@ -378,10 +380,14 @@ function envReuseRecipeForLaneConfig(laneConfig, lane = "v02") { 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 ((runtimeGoModCachePath || runtimeGoBuildCachePath) && goOsPackages.length === 0) { + throw new Error(`deploy.lanes.${lane}.envRecipe.goOsPackages is required when Go cache paths are configured`); + } 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`); return { osPackages, + goOsPackages, bunVersion, launcherPath, runtimeNodeModulesPath, @@ -394,6 +400,7 @@ function envReuseRecipeForLaneConfig(laneConfig, lane = "v02") { hwpodAliases, publicRecipe: { osPackages, + goOsPackages, bunVersion, launcherPath, runtimeNodeModulesPath, @@ -407,6 +414,18 @@ function envReuseRecipeForLaneConfig(laneConfig, lane = "v02") { }; } +function envReuseRecipeForService(recipe, model) { + if (model?.runtimeKind === "go-service" || model?.artifactKind === "go-service") return recipe; + const { + goOsPackages: _goOsPackages, + runtimeGoModCachePath: _runtimeGoModCachePath, + runtimeGoBuildCachePath: _runtimeGoBuildCachePath, + goToolchain: _goToolchain, + ...nodeRecipe + } = recipe; + return nodeRecipe; +} + function normalizeDownloadStack(value, lane) { const configured = effectiveDownloadStackConfig(value, process.env); if (!configured) throw new Error(`deploy.lanes.${lane}.envRecipe.downloadStack is required`);