feat: add restart command for managed deployments and enhance logging functionality

This commit is contained in:
2026-08-09 14:43:33 +07:00 Unverified
parent 58c26b735a
commit a0abaf05b9
8 changed files with 337 additions and 93 deletions
+42 -8
View File
@@ -1,6 +1,6 @@
import { basename, isAbsolute, relative, resolve } from "node:path";
import { mkdtemp, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import { hostname, tmpdir } from "node:os";
import type { Writable } from "node:stream";
import type { ComposeSpecification, Service } from "../schema/docker.d";
import { IMAGE_REGISTRY } from "../const";
@@ -57,7 +57,7 @@ function resolveBuildPlan(
service: Service,
cwd: string,
repoRoot: string,
remoteRepo: string,
buildRoot: string,
): BuildPlan | undefined {
if (!service.build) return;
@@ -93,13 +93,17 @@ function resolveBuildPlan(
return {
name,
image: `${IMAGE_REGISTRY}/kuber/${project}-${name}:latest`,
context: `${remoteRepo}/${contextRelative === "" ? "." : contextRelative}`,
dockerfile: dockerfileRelative ? `${remoteRepo}/${dockerfileRelative}` : undefined,
context: `${buildRoot}/${contextRelative === "" ? "." : contextRelative}`,
dockerfile: dockerfileRelative ? `${buildRoot}/${dockerfileRelative}` : undefined,
target: typeof build === "string" ? undefined : build.target,
buildArgs: resolveBuildArgs(service),
};
}
function isOnRemoteBuilder(): boolean {
return hostname() === REMOTE_BUILDER.split("@").at(-1);
}
async function pumpStream(
stream: ReadableStream<Uint8Array> | null | undefined,
onLine: (line: string) => void | Promise<void>,
@@ -299,6 +303,30 @@ async function buildRemote(plan: BuildPlan, reporter?: BuildReporter) {
await runWithOutput(ssh(`set -euo pipefail; ${command}`), reporter);
}
async function buildLocal(plan: BuildPlan, reporter?: BuildReporter) {
await reporter?.progress?.(`Building ${plan.name}`);
const command = Bun.spawn(
[
"docker",
"build",
"--push",
"--progress=plain",
"-t",
plan.image,
...(plan.dockerfile ? ["-f", plan.dockerfile] : []),
...(plan.target ? ["--target", plan.target] : []),
...plan.buildArgs.flatMap((arg) => ["--build-arg", arg]),
plan.context,
],
{
stdout: "pipe",
stderr: "pipe",
},
);
await runWithOutput(command, reporter);
}
export async function buildServices(
project: string,
compose: ComposeSpecification,
@@ -306,15 +334,21 @@ export async function buildServices(
reporter?: BuildReporter,
): Promise<number> {
const repoRoot = await getRepoRoot(cwd);
const remoteRepo = `${REMOTE_BUILD_ROOT}/${basename(repoRoot)}`;
const plans = getBuildPlans(project, compose, cwd, repoRoot, remoteRepo);
const localBuilder = isOnRemoteBuilder();
const buildRoot = localBuilder
? repoRoot
: `${REMOTE_BUILD_ROOT}/${basename(repoRoot)}`;
const plans = getBuildPlans(project, compose, cwd, repoRoot, buildRoot);
if (plans.length === 0) return 0;
await syncRemoteRepo(repoRoot, remoteRepo, reporter);
if (!localBuilder) {
await syncRemoteRepo(repoRoot, buildRoot, reporter);
}
for (const plan of plans) {
await buildRemote(plan, reporter);
if (localBuilder) await buildLocal(plan, reporter);
else await buildRemote(plan, reporter);
}
return plans.length;