feat: share go env reuse artifact

This commit is contained in:
UniDesk Codex
2026-07-07 02:00:31 +08:00
parent d5919977b5
commit f0f7e937d8
3 changed files with 209 additions and 2 deletions
+157 -1
View File
@@ -1145,6 +1145,79 @@ test("v03 planner reads env reuse declarations and catalog from v03 lane config"
}
});
test("v03 planner builds one shared Go env artifact for compatible Go services", async () => {
const repo = await createFixtureRepo({ catalog: false });
await addGoEnvReuseFixture(repo);
await writeFile(path.join(repo, "go.mod"), "module github.com/pikasTech/HWLAB\n\ngo 1.22\n\nrequire example.com/direct v0.0.2\n");
await git(repo, ["add", "go.mod"]);
await git(repo, ["commit", "-m", "change go env dependency"]);
const plan = await createCiPlan({
repoRoot: repo,
lane: "v03",
baseRef: "HEAD~1",
targetRef: "HEAD",
artifactCatalogPath: "deploy/nonexistent-artifact-catalog.json",
services: ["hwlab-user-billing", "hwlab-workbench-runtime"]
});
const group = plan.envArtifactGroups.find((item) => item.id === "hwlab-go-runtime-env");
assert.equal(group.buildRequired, true);
assert.deepEqual(group.buildServices, ["hwlab-user-billing"]);
assert.deepEqual(group.consumerServices, ["hwlab-workbench-runtime"]);
assert.deepEqual(plan.buildServices, ["hwlab-user-billing"]);
const userBilling = plan.services.find((service) => service.serviceId === "hwlab-user-billing");
const workbenchRuntime = plan.services.find((service) => service.serviceId === "hwlab-workbench-runtime");
assert.equal(userBilling.envArtifactCacheRef, "127.0.0.1:5000/hwlab/cache/hwlab-go-runtime-env");
assert.equal(workbenchRuntime.envArtifactCacheRef, "127.0.0.1:5000/hwlab/cache/hwlab-go-runtime-env");
assert.equal(userBilling.environmentImage, `127.0.0.1:5000/hwlab/hwlab-go-runtime-env:env-${userBilling.environmentInputHash.slice(0, 12)}`);
assert.equal(workbenchRuntime.environmentImage, userBilling.environmentImage);
assert.equal(workbenchRuntime.sharedEnvBuildSkipped, true);
assert.equal(workbenchRuntime.buildRequired, false);
});
test("v03 planner ignores Go launcher comment-only changes for env identity", async () => {
const repo = await createFixtureRepo({ catalog: false });
await addGoEnvReuseFixture(repo);
const initialSha = (await git(repo, ["rev-parse", "HEAD"])).stdout.trim();
const initialPlan = await createCiPlan({
repoRoot: repo,
lane: "v03",
baseRef: "HEAD",
targetRef: initialSha,
artifactCatalogPath: "deploy/nonexistent-artifact-catalog.json",
services: ["hwlab-user-billing", "hwlab-workbench-runtime"]
});
await writeFile(path.join(repo, "deploy/artifact-catalog.v03.json"), JSON.stringify(createCatalogFixture("ready", catalogOptionsFromPlan(initialPlan, {
sourceCommitId: initialSha,
serviceIds: ["hwlab-user-billing", "hwlab-workbench-runtime"]
})), null, 2));
await git(repo, ["add", "deploy/artifact-catalog.v03.json"]);
await git(repo, ["commit", "-m", "seed go env reuse catalog"]);
await writeFile(path.join(repo, "deploy/runtime/launcher/hwlab-go-env-reuse-launcher.mjs"), "// changed explanatory comment\nexport const goEnvLauncher = true;\n");
await git(repo, ["add", "deploy/runtime/launcher/hwlab-go-env-reuse-launcher.mjs"]);
await git(repo, ["commit", "-m", "change go launcher comment only"]);
const plan = await createCiPlan({
repoRoot: repo,
lane: "v03",
baseRef: "HEAD~1",
targetRef: "HEAD",
artifactCatalogPath: "deploy/artifact-catalog.v03.json",
services: ["hwlab-user-billing", "hwlab-workbench-runtime"]
});
assert.deepEqual(plan.affectedServices, []);
assert.deepEqual(plan.buildServices, []);
assert.equal(plan.imageBuildRequired, false);
for (const service of plan.services) {
assert.equal(service.runtimeReuseDecision.envIdentityHit, true, service.serviceId);
assert.equal(service.environmentInputChanged, false, service.serviceId);
assert.equal(service.buildRequired, false, service.serviceId);
}
});
async function createFixtureRepo(options = {}) {
const serviceIds = options.serviceIds ?? ["hwlab-cloud-api", "hwlab-cloud-web"];
const laneServiceIds = options.laneServiceIds ?? V02_RUNTIME_SERVICE_IDS;
@@ -1255,6 +1328,84 @@ function planV02CoreServices(repo, options) {
});
}
async function addGoEnvReuseFixture(repo) {
await mkdir(path.join(repo, "cmd/hwlab-user-billing"), { recursive: true });
await mkdir(path.join(repo, "cmd/hwlab-workbench-runtime"), { recursive: true });
await mkdir(path.join(repo, "internal/userbilling"), { recursive: true });
await mkdir(path.join(repo, "internal/workbenchruntime"), { recursive: true });
await mkdir(path.join(repo, "gitops"), { recursive: true });
await writeFile(path.join(repo, "go.mod"), "module github.com/pikasTech/HWLAB\n\ngo 1.22\n\nrequire example.com/direct v0.0.1\n");
await writeFile(path.join(repo, "go.sum"), "example.com/direct v0.0.1 h1:fixture\n");
await writeFile(path.join(repo, "cmd/hwlab-user-billing/main.go"), "package main\n\nfunc main() {}\n");
await writeFile(path.join(repo, "cmd/hwlab-workbench-runtime/main.go"), "package main\n\nfunc main() {}\n");
await writeFile(path.join(repo, "internal/userbilling/billing.go"), "package userbilling\n");
await writeFile(path.join(repo, "internal/workbenchruntime/runtime.go"), "package workbenchruntime\n");
await writeFile(path.join(repo, "deploy/runtime/boot/hwlab-user-billing.sh"), "#!/bin/sh\nexec /app/hwlab-user-billing\n");
await writeFile(path.join(repo, "deploy/runtime/boot/hwlab-workbench-runtime.sh"), "#!/bin/sh\nexec /app/hwlab-workbench-runtime\n");
await writeFile(path.join(repo, "deploy/runtime/launcher/hwlab-go-env-reuse-launcher.mjs"), "// initial explanatory comment\nexport const goEnvLauncher = true;\n");
const deployPath = path.join(repo, "deploy/deploy.yaml");
const deploy = await readStructuredFile(repo, deployPath);
deploy.lanes.v03.envReuseServices = uniquePreserveOrder([
...deploy.lanes.v03.envReuseServices,
"hwlab-user-billing",
"hwlab-workbench-runtime"
]);
deploy.lanes.v03.bootScripts["hwlab-user-billing"] = "deploy/runtime/boot/hwlab-user-billing.sh";
deploy.lanes.v03.bootScripts["hwlab-workbench-runtime"] = "deploy/runtime/boot/hwlab-workbench-runtime.sh";
deploy.lanes.v03.serviceDeclarations["hwlab-user-billing"] = {
runtimeKind: "go-service",
entrypoint: "cmd/hwlab-user-billing/main.go",
artifactKind: "go-service",
healthPath: "/health/live",
healthPort: 7101,
componentPaths: ["cmd/hwlab-user-billing/", "internal/userbilling/"],
env: {},
observable: true
};
deploy.lanes.v03.serviceDeclarations["hwlab-workbench-runtime"] = {
runtimeKind: "go-service",
entrypoint: "cmd/hwlab-workbench-runtime/main.go",
artifactKind: "go-service",
healthPath: "/health/live",
healthPort: 7102,
componentPaths: ["cmd/hwlab-workbench-runtime/", "internal/workbenchruntime/"],
env: {},
observable: true
};
await writeStructuredFile(repo, deployPath, deploy);
await writeStructuredFile(repo, "gitops/reuse.ymal", {
apiVersion: "unidesk.pikapython.com/v1alpha1",
kind: "RuntimeReuseConfig",
metadata: { name: "hwlab-v03-reuse", ownerRepository: "pikasTech/HWLAB" },
spec: {
envArtifactGroups: {
"hwlab-go-runtime-env": {
enabled: true,
mode: "env-reuse-git-mirror-checkout",
buildService: "hwlab-user-billing",
imageRepository: "hwlab-go-runtime-env",
cacheRepository: "cache/hwlab-go-runtime-env",
services: ["hwlab-user-billing", "hwlab-workbench-runtime"]
}
},
services: Object.fromEntries(["hwlab-user-billing", "hwlab-workbench-runtime"].map((serviceId) => [serviceId, {
runtimeReuse: {
enabled: true,
codeIdentity: { paths: [serviceId === "hwlab-user-billing" ? "cmd/hwlab-user-billing" : "cmd/hwlab-workbench-runtime"] },
envIdentity: { paths: ["go.mod", "go.sum", "deploy/runtime/launcher/hwlab-go-env-reuse-launcher.mjs"] }
},
envReuse: {
enabled: true,
mode: "env-reuse-git-mirror-checkout",
envIdentityFiles: ["go.mod", "go.sum", "deploy/runtime/launcher/hwlab-go-env-reuse-launcher.mjs"]
}
}]))
}
});
await git(repo, ["add", "."]);
await git(repo, ["commit", "-m", "add go env reuse fixture"]);
}
function createDeployFixture({ serviceIds = V02_RUNTIME_SERVICE_IDS } = {}) {
const v02 = {
sourceRepo: "git@github.com:pikasTech/HWLAB.git",
@@ -1380,6 +1531,11 @@ function createDeployFixture({ serviceIds = V02_RUNTIME_SERVICE_IDS } = {}) {
function createCatalogFixture(mode, options = {}) {
const digest = mode === "ready" ? `sha256:${"1".repeat(64)}` : "not_published";
const envReuseCatalogServiceIds = new Set([
...V02_RUNTIME_SERVICE_IDS,
...Object.keys(options.environmentInputHashes ?? {}),
...Object.keys(options.codeInputHashes ?? {})
]);
const serviceIds = options.serviceIds ?? uniquePreserveOrder([
"hwlab-cloud-api",
"hwlab-cloud-web",
@@ -1398,7 +1554,7 @@ function createCatalogFixture(mode, options = {}) {
...((options.componentInputHashes?.[serviceId] || (serviceId === "hwlab-cloud-api" && options.cloudApiComponentInputHash)) ? {
componentInputHash: options.cloudApiComponentInputHash ?? options.componentInputHashes?.[serviceId]
} : {}),
...(V02_RUNTIME_SERVICE_IDS.includes(serviceId) ? {
...(envReuseCatalogServiceIds.has(serviceId) ? {
runtimeMode: "env-reuse-git-mirror-checkout",
envReuse: true,
environmentImage: `127.0.0.1:5000/hwlab/${serviceId}-env:env-abc1234`,