feat: improve API keys and build workflows
This commit is contained in:
+89
-20
@@ -1,5 +1,5 @@
|
||||
import { defineCommand } from "citty";
|
||||
import { Listr, type ListrTaskWrapper } from "listr2";
|
||||
import { Listr, ListrErrorTypes, type ListrTaskWrapper } from "listr2";
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { isDeepStrictEqual } from "node:util";
|
||||
import type { ComposeSpecification } from "../schema/docker.d";
|
||||
@@ -765,34 +765,103 @@ export async function runUp(
|
||||
},
|
||||
{
|
||||
title: "Build images",
|
||||
rendererOptions: { outputBar: 10, persistentOutput: true },
|
||||
rendererOptions: { bottomBar: Infinity, persistentOutput: true },
|
||||
enabled: async () =>
|
||||
build &&
|
||||
Object.values((await compose()).services ?? {}).some(
|
||||
(service) => service.build,
|
||||
),
|
||||
task: async (taskCtx, task) => {
|
||||
const result = await buildServices(
|
||||
project,
|
||||
taskCtx.compose!,
|
||||
cwd,
|
||||
{
|
||||
progress: (message) => {
|
||||
task.output = message;
|
||||
},
|
||||
stream: task.stdout(),
|
||||
},
|
||||
{
|
||||
...config,
|
||||
request,
|
||||
snapshot: taskCtx.snapshot,
|
||||
workspaceRoot: taskCtx.workspaceRoot,
|
||||
signal: task.signal,
|
||||
},
|
||||
const services = Object.entries(taskCtx.compose!.services ?? {})
|
||||
.filter(([, service]) => service.build)
|
||||
.map(([name]) => name);
|
||||
const children = new Map<
|
||||
string,
|
||||
ListrTaskWrapper<UpContext, any, any>
|
||||
>();
|
||||
const pending = new Map<string, (error?: unknown) => void>();
|
||||
const completed = new Map<string, Promise<unknown>>(
|
||||
services.map((name) => [
|
||||
name,
|
||||
new Promise((resolve) => pending.set(name, resolve)),
|
||||
]),
|
||||
);
|
||||
let result: Awaited<ReturnType<typeof buildServices>> | undefined;
|
||||
let operationFailure: Error | undefined;
|
||||
let operation: Promise<void> | undefined;
|
||||
const start = () => {
|
||||
operation ??= buildServices(
|
||||
project,
|
||||
taskCtx.compose!,
|
||||
cwd,
|
||||
{
|
||||
progress: (message) => {
|
||||
task.output = message;
|
||||
},
|
||||
service: (name) => {
|
||||
let stream: ReturnType<ListrTaskWrapper<UpContext, any, any>["stdout"]> | undefined;
|
||||
return {
|
||||
progress: (message) => {
|
||||
const child = children.get(name);
|
||||
if (child && child.output !== message) child.output = message;
|
||||
},
|
||||
get stream() {
|
||||
const child = children.get(name);
|
||||
if (child) stream ??= child.stdout();
|
||||
return stream;
|
||||
},
|
||||
};
|
||||
},
|
||||
settled: (name, error) => {
|
||||
pending.get(name)?.(error);
|
||||
pending.delete(name);
|
||||
},
|
||||
},
|
||||
{
|
||||
...config,
|
||||
request,
|
||||
snapshot: taskCtx.snapshot,
|
||||
workspaceRoot: taskCtx.workspaceRoot,
|
||||
signal: task.signal,
|
||||
},
|
||||
).then(
|
||||
(value) => {
|
||||
result = value;
|
||||
},
|
||||
(error: unknown) => {
|
||||
const failure =
|
||||
error instanceof Error ? error : new Error(String(error));
|
||||
operationFailure = failure;
|
||||
task.output = failure.stack ?? failure.message;
|
||||
task.report(failure, ListrErrorTypes.HAS_FAILED);
|
||||
for (const resolve of pending.values()) resolve(failure);
|
||||
pending.clear();
|
||||
},
|
||||
);
|
||||
return operation;
|
||||
};
|
||||
await task
|
||||
.newListr<UpContext>(
|
||||
services.map((name) => ({
|
||||
title: `Build ${name}`,
|
||||
rendererOptions: { outputBar: 10, persistentOutput: true },
|
||||
task: async (_ctx, child) => {
|
||||
children.set(name, child);
|
||||
child.output = "Build queued";
|
||||
if (children.size === services.length) start();
|
||||
const error = await completed.get(name);
|
||||
if (error) throw error;
|
||||
child.output = "done";
|
||||
},
|
||||
})),
|
||||
{ concurrent: true, exitOnError: false },
|
||||
)
|
||||
.run();
|
||||
await operation;
|
||||
if (!result) throw operationFailure ?? new Error("Build images failed");
|
||||
taskCtx.buildImages = result.images;
|
||||
await config.postBuild?.(result, await getHookContext());
|
||||
task.output = `Built ${result.built.length} image${result.built.length === 1 ? "" : "s"}`;
|
||||
task.title = `Built ${result.built.length} image${result.built.length === 1 ? "" : "s"}`;
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user