From feb2550facfcfa52bc720f6b8ec3ab6c38e869a5 Mon Sep 17 00:00:00 2001 From: Codex Date: Mon, 18 May 2026 01:58:24 +0000 Subject: [PATCH] fix: reuse code queue base for dev builds --- docs/reference/deploy.md | 2 +- scripts/src/deploy.ts | 34 +++++++++++++++++++++++++++++----- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/docs/reference/deploy.md b/docs/reference/deploy.md index 9a80921b..221c0f38 100644 --- a/docs/reference/deploy.md +++ b/docs/reference/deploy.md @@ -75,7 +75,7 @@ Phase 5 introduces the dev Code Queue execution manifest at `src/components/micr All dev Code Queue components must use `unidesk-dev-runtime-config` and `unidesk-dev-runtime-secrets`, connect to `postgres-dev.../unidesk_dev`, write logs and state under `/home/ubuntu/unidesk-dev-code-queue-deploy/state`, and expose HTTP on 4222 only as ClusterIP services. The scheduler uses `CODE_QUEUE_MAIN_PROVIDER_ID=D601-dev`, `CODE_QUEUE_WORKDIR=/workspace-dev`, `CODE_QUEUE_REMOTE_WORKDIR=/home/ubuntu/unidesk-dev-workspace`, disables ClaudeQQ notifications by default, and does not use the production `d601-tcp-egress-gateway` or production PostgreSQL route. -`deploy apply --env dev --service code-queue` fetches `origin/deploy/dev:deploy.json`, materializes the requested source commit on D601, copies the dev Code Queue control manifest, narrows it to Code Queue dev objects, replaces placeholders with the requested commit and `unidesk-code-queue:dev`, builds on D601, imports the image into native k3s containerd, applies only `unidesk-dev` objects and stamps the dev Deployments. This first dev execution slice proves deployability, health and dev database isolation; wiring the dev frontend stable `code-queue` route through a dev `code-queue-mgr` is a separate later phase. +`deploy apply --env dev --service code-queue` fetches `origin/deploy/dev:deploy.json`, materializes the requested source commit on D601, copies the dev Code Queue control manifest, narrows it to Code Queue dev objects, replaces placeholders with the requested commit and `unidesk-code-queue:dev`, builds on D601, imports the image into native k3s containerd, applies only `unidesk-dev` objects and stamps the dev Deployments. Because Code Queue carries the agent toolchain and browser/runtime dependencies, dev builds may reuse an existing D601 `unidesk-code-queue:d601-build-base` or `unidesk-code-queue:d601` image when the dev build-base tag is absent, and the deploy executor allows a longer Code Queue build window than lightweight services. This first dev execution slice proves deployability, health and dev database isolation; wiring the dev frontend stable `code-queue` route through a dev `code-queue-mgr` is a separate later phase. ## CLI diff --git a/scripts/src/deploy.ts b/scripts/src/deploy.ts index 984447f5..c44ece3f 100644 --- a/scripts/src/deploy.ts +++ b/scripts/src/deploy.ts @@ -923,17 +923,41 @@ while True: ].join("\n"); } -function buildCachePrelude(dockerfileVariable: string): string[] { +function buildBaseImageFallbacks(service: UniDeskMicroserviceConfig): string[] { + if (isDevK3sDeployService(service) && service.id === "code-queue") { + return [ + "unidesk-code-queue:d601-build-base", + "unidesk-code-queue:d601", + ]; + } + return []; +} + +function buildCachePrelude(dockerfileVariable: string, baseImageFallbacks: string[] = []): string[] { + const fallbackLines = baseImageFallbacks.flatMap((image) => [ + `if [ "$base_image_found" = "0" ] && docker image inspect ${shellQuote(image)} >/dev/null 2>&1; then`, + ` build_base_image=${shellQuote(image)}`, + " base_image_found=1", + "fi", + ]); return [ "cache_args=(--cache-to type=inline --build-arg BUILDKIT_INLINE_CACHE=1)", "if docker image inspect \"$image\" >/dev/null 2>&1; then cache_args+=(--cache-from \"$image\"); echo target_build_cache_from_image=$image; else echo target_build_cache_from_image=missing:$image; fi", "echo target_build_cache_to=inline", "base_args=()", "build_base_image=\"${image}-build-base\"", - `if grep -Eq '^ARG[[:space:]]+CODE_QUEUE_BASE_IMAGE([=[:space:]]|$)' "${dockerfileVariable}" 2>/dev/null; then if docker image inspect "$build_base_image" >/dev/null 2>&1; then base_args=(--build-arg "CODE_QUEUE_BASE_IMAGE=$build_base_image"); echo target_build_base_image=$build_base_image; else echo target_build_base_image=default; fi; else echo target_build_base_image=unsupported; fi`, + "base_image_found=0", + "if docker image inspect \"$build_base_image\" >/dev/null 2>&1; then base_image_found=1; fi", + ...fallbackLines, + `if grep -Eq '^ARG[[:space:]]+CODE_QUEUE_BASE_IMAGE([=[:space:]]|$)' "${dockerfileVariable}" 2>/dev/null; then if [ "$base_image_found" = "1" ]; then base_args=(--build-arg "CODE_QUEUE_BASE_IMAGE=$build_base_image"); echo target_build_base_image=$build_base_image; else echo target_build_base_image=default; fi; else echo target_build_base_image=unsupported; fi`, ]; } +function dockerBuildTimeoutMs(service: UniDeskMicroserviceConfig, options: DeployOptions): number { + const maxBuildMs = service.id === "code-queue" ? 1_800_000 : 540_000; + return Math.min(options.timeoutMs, maxBuildMs); +} + function prepareSourceScript(service: UniDeskMicroserviceConfig, desired: DeployManifestService, exportDir: string): string { if (targetIsMain(service) && isUnideskRepo(desired.repo)) { return [ @@ -1126,7 +1150,7 @@ function buildImageScript(service: UniDeskMicroserviceConfig, desired: DeployMan "if docker buildx inspect --builder default >/dev/null 2>&1; then builder_args=(--builder default); echo target_build_builder=default; else echo target_build_builder=implicit; fi", "docker buildx inspect \"${builder_args[@]}\" --bootstrap || true", "echo target_build_builder_cleanup=not-required", - ...buildCachePrelude("$dockerfile"), + ...buildCachePrelude("$dockerfile", buildBaseImageFallbacks(service)), `docker buildx build "\${builder_args[@]}" --load "\${cache_args[@]}" "\${base_args[@]}" ${[...proxyBuildArgs, ...commonArgs].map(shellQuote).join(" ")}`, "docker image inspect \"$image\" --format 'image_id={{.Id}} labels={{json .Config.Labels}}'", ].filter((line) => line.length > 0).join("\n"); @@ -1242,7 +1266,7 @@ function buildDirectImageScript(service: UniDeskMicroserviceConfig, desired: Dep "builder_args=()", "if docker buildx inspect --builder default >/dev/null 2>&1; then builder_args=(--builder default); echo target_build_builder=default; else echo target_build_builder=implicit; fi", "docker buildx inspect \"${builder_args[@]}\" --bootstrap || true", - ...buildCachePrelude("$dockerfile_abs"), + ...buildCachePrelude("$dockerfile_abs", buildBaseImageFallbacks(service)), "compose_build_args=()", "while IFS= read -r item; do [ -n \"$item\" ] && compose_build_args+=(--build-arg \"$item\"); done < \"$build_args_file\"", "target_args=()", @@ -2098,7 +2122,7 @@ async function applyOneService(config: UniDeskConfig, service: UniDeskMicroservi const buildScript = isDirectComposeDeployMode(service) ? buildDirectImageScript(service, desired, resolvedCommit) : buildImageScript(service, desired, resolvedCommit); - const build = await step(config, service, "docker-build", buildScript, targetWorkDir(service), Math.min(options.timeoutMs, 540_000), !targetIsMain(service)); + const build = await step(config, service, "docker-build", buildScript, targetWorkDir(service), dockerBuildTimeoutMs(service, options), !targetIsMain(service)); if (!pushStep(steps, build)) return { ok: false, serviceId: service.id, startedAt, finishedAt: nowIso(), resolvedCommit, before, steps }; if (service.deployment.mode === "k3sctl-managed") {