fix: respect compose project name
This commit is contained in:
@@ -143,7 +143,7 @@ export default {
|
||||
|
||||
Operational defaults:
|
||||
|
||||
- `project`: current working directory name
|
||||
- `project`: Compose top-level `name`, falling back to the current working directory name
|
||||
- `composeFile`: the first recognized Compose filename in the working directory
|
||||
- `registry`: `registry.neko-piranha.ts.net`
|
||||
- `builders.amd64`: `kuber@astral-th`
|
||||
@@ -151,6 +151,9 @@ Operational defaults:
|
||||
- `builders.remoteRoot`: `kuber-build`
|
||||
- `rolloutTimeoutMs`: `300000`
|
||||
|
||||
Project-name precedence is `.kuberrc.ts project`, Compose top-level `name`, then
|
||||
the current working directory name.
|
||||
|
||||
Configuration hooks can be synchronous or asynchronous and receive mutable
|
||||
values:
|
||||
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ import { up } from "./up";
|
||||
export const main = defineCommand({
|
||||
meta: {
|
||||
name: "kuber",
|
||||
version: "1.2.0",
|
||||
version: "1.2.1",
|
||||
description: "Docker Compose -> K8s translation layer",
|
||||
},
|
||||
args: {
|
||||
|
||||
@@ -20,6 +20,7 @@ type Hooks = Pick<
|
||||
|
||||
export type ResolvedKuberConfig = Hooks & {
|
||||
project: string;
|
||||
projectConfigured: boolean;
|
||||
composeFile?: string;
|
||||
registry: string;
|
||||
builders: {
|
||||
@@ -157,6 +158,7 @@ export async function loadConfig(
|
||||
|
||||
return {
|
||||
project: raw.project?.trim() ?? basename(cwd),
|
||||
projectConfigured: raw.project !== undefined,
|
||||
composeFile: composeFile
|
||||
? isAbsolute(composeFile)
|
||||
? composeFile
|
||||
|
||||
+22
-1
@@ -15,6 +15,14 @@ type AppContext = {
|
||||
|
||||
const appContext = new AsyncLocalStorage<AppContext>();
|
||||
|
||||
export function resolveProjectName(
|
||||
config: Pick<ResolvedKuberConfig, "project" | "projectConfigured">,
|
||||
compose: ComposeSpecification,
|
||||
): string {
|
||||
if (config.projectConfigured) return config.project;
|
||||
return compose.name?.trim() || config.project;
|
||||
}
|
||||
|
||||
export async function provideContext<T>(
|
||||
fn: () => T,
|
||||
configPath?: string,
|
||||
@@ -26,6 +34,19 @@ export async function provideContext<T>(
|
||||
? Promise.resolve(config.composeFile)
|
||||
: resolveComposeFile(cwd),
|
||||
);
|
||||
const parsedCompose = createCachedGetter("parsedCompose", async () => {
|
||||
const composeFile = await path();
|
||||
if (!composeFile) throw new Error("Compose file cannot be found");
|
||||
return readCompose(composeFile);
|
||||
});
|
||||
|
||||
if (!config.projectConfigured) {
|
||||
const composeFile = await path();
|
||||
if (composeFile) {
|
||||
config.project = resolveProjectName(config, await parsedCompose());
|
||||
}
|
||||
}
|
||||
|
||||
const getHookContext = createCachedGetter("hookContext", async () => {
|
||||
const composeFile = await path();
|
||||
if (!composeFile) throw new Error("Compose file cannot be found");
|
||||
@@ -33,7 +54,7 @@ export async function provideContext<T>(
|
||||
});
|
||||
const compose = createCachedGetter("compose", async () => {
|
||||
const context = await getHookContext();
|
||||
const value = await readCompose(context.composeFile);
|
||||
const value = await parsedCompose();
|
||||
await config.compose?.(value, context);
|
||||
return value;
|
||||
});
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@dmgnr/kuber",
|
||||
"version": "1.2.0",
|
||||
"version": "1.2.1",
|
||||
"description": "Docker Compose to Kubernetes translation layer",
|
||||
"bin": {
|
||||
"kuber": "dist/index.js"
|
||||
|
||||
+22
-1
@@ -7,7 +7,7 @@ import {
|
||||
resolveComposeArch,
|
||||
withComposeArch,
|
||||
} from "../../lib/arch";
|
||||
import { createCachedGetter, ctx } from "../../lib/context";
|
||||
import { createCachedGetter, ctx, resolveProjectName } from "../../lib/context";
|
||||
import { toEnvVars, toTable } from "../../lib/format";
|
||||
import { deepMerge, getPodContainerName, throwWhen } from "../../lib/shared";
|
||||
|
||||
@@ -131,6 +131,27 @@ describe("shared helpers", () => {
|
||||
});
|
||||
|
||||
describe("context helpers", () => {
|
||||
test("resolves project names using config, Compose, then directory precedence", () => {
|
||||
expect(
|
||||
resolveProjectName(
|
||||
{ project: "directory", projectConfigured: false },
|
||||
{ name: "compose" },
|
||||
),
|
||||
).toBe("compose");
|
||||
expect(
|
||||
resolveProjectName(
|
||||
{ project: "config", projectConfigured: true },
|
||||
{ name: "compose" },
|
||||
),
|
||||
).toBe("config");
|
||||
expect(
|
||||
resolveProjectName(
|
||||
{ project: "directory", projectConfigured: false },
|
||||
{},
|
||||
),
|
||||
).toBe("directory");
|
||||
});
|
||||
|
||||
test("rejects access outside an application context", () => {
|
||||
expect(() => ctx()).toThrow("Not in context");
|
||||
});
|
||||
|
||||
@@ -50,8 +50,12 @@ describe("Compose parsing", () => {
|
||||
test("parses and validates a minimal Compose project", async () => {
|
||||
const directory = await temporaryDirectory();
|
||||
const path = join(directory, "compose.yml");
|
||||
await writeFile(path, "services:\n app:\n image: nginx:latest\n");
|
||||
await writeFile(
|
||||
path,
|
||||
"name: compose-project\nservices:\n app:\n image: nginx:latest\n",
|
||||
);
|
||||
expect(await readCompose(path)).toMatchObject({
|
||||
name: "compose-project",
|
||||
services: { app: { image: "nginx:latest" } },
|
||||
});
|
||||
});
|
||||
|
||||
Vendored
+1
-1
@@ -35,7 +35,7 @@ export interface KuberBuildersConfig {
|
||||
}
|
||||
|
||||
export interface KuberConfig {
|
||||
/** Kubernetes namespace/project name. Defaults to the working directory name. */
|
||||
/** Kubernetes namespace/project name. Overrides the Compose name and working directory. */
|
||||
project?: string;
|
||||
/** Compose file path, resolved relative to the working directory. */
|
||||
composeFile?: string;
|
||||
|
||||
Reference in New Issue
Block a user