Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 7 additions & 8 deletions .oxlintrc.effect.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"!apps/cli/src/command-internal/connect-errors.*",
"!apps/cli/src/command-internal/container-cli.*",
"!apps/cli/src/command-internal/db-*.ts",
"!apps/cli/src/command-internal/db-bootstrap/**",
"!apps/cli/src/command-internal/debug-logger.*",
"!apps/cli/src/command-internal/detect-content-type.*",
"!apps/cli/src/command-internal/diff-engine.*",
Expand Down Expand Up @@ -100,20 +101,16 @@
"!apps/cli/src/command-internal/size-units.ts",
"!apps/cli/src/command-internal/sql-files-glob.*",
"!apps/cli/src/command-internal/sql-split.*",
"!apps/cli/src/command-internal/stack-api.ts",
"!apps/cli/src/command-internal/stack-backend.ts",
"!apps/cli/src/command-internal/stack-catalog-setup.ts",
"!apps/cli/src/command-internal/stack-config.ts",
"!apps/cli/src/command-internal/stack-local-database.ts",
"!apps/cli/src/command-internal/stack-shadow.ts",
"!apps/cli/src/command-internal/stack-storage.ts",
"!apps/cli/src/command-internal/stack-*",
"!apps/cli/src/command-internal/start-*",
"!apps/cli/src/command-internal/status-errors.ts",
"!apps/cli/src/command-internal/status-pretty.*",
"!apps/cli/src/command-internal/status-values.*",
"!apps/cli/src/command-internal/storage-*.ts",
"!apps/cli/src/command-internal/string-slice-flag.*",
"!apps/cli/src/command-internal/temp-paths.*",
"!apps/cli/src/command-internal/tenant-*",
"!apps/cli/src/command-internal/test-db.*",
"!apps/cli/src/command-internal/timestamp.format.*",
"!apps/cli/src/command-internal/upgrade-notice.*",
"!apps/cli/src/command-internal/upgrade-suggest.*",
Expand All @@ -122,6 +119,8 @@
"!apps/cli/src/command-internal/viper-env.*",
"!apps/cli/src/command-internal/workdir-project.*",
"!apps/cli/src/command-internal/workdir-search.ts",
"!apps/cli/src/command-internal/workdir-validation.ts"
"!apps/cli/src/command-internal/workdir-validation.ts",
"apps/cli/src/command-internal/db-bootstrap/local-db-running.integration.test.ts",
"apps/cli/src/command-internal/db-bootstrap/local-db-running.ts"
]
}
66 changes: 27 additions & 39 deletions apps/cli/src/command-internal/db-bootstrap/container-lifecycle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,15 +245,13 @@ export function ensureNetwork(
);
if (exitCode !== 0 && !isNetworkAlreadyExistsError(stderr)) {
const message = stderr.trim();
return yield* Effect.fail(
new NetworkCreateError({
message:
message.length > 0
? `failed to create docker network: ${message}`
: "failed to create docker network",
reason: containerCliReason(message),
}),
);
return yield* new NetworkCreateError({
message:
message.length > 0
? `failed to create docker network: ${message}`
: "failed to create docker network",
reason: containerCliReason(message),
});
}
}),
);
Expand Down Expand Up @@ -316,15 +314,11 @@ export function ensureVolume(
);
if (exitCode !== 0 && !isVolumeAlreadyExistsError(stderr)) {
const message = stderr.trim();
return yield* Effect.fail(
new VolumeCreateError({
message:
message.length > 0
? `failed to create volume: ${message}`
: "failed to create volume",
reason: containerCliReason(message),
}),
);
return yield* new VolumeCreateError({
message:
message.length > 0 ? `failed to create volume: ${message}` : "failed to create volume",
reason: containerCliReason(message),
});
}
}),
);
Expand Down Expand Up @@ -483,15 +477,13 @@ function dockerCreateContainer(
);
if (exitCode !== 0) {
const message = stderr.trim();
return yield* Effect.fail(
new ContainerCreateError({
message:
message.length > 0
? `failed to create docker container: ${message}`
: "failed to create docker container",
reason: containerCliReason(message),
}),
);
return yield* new ContainerCreateError({
message:
message.length > 0
? `failed to create docker container: ${message}`
: "failed to create docker container",
reason: containerCliReason(message),
});
}
return stdout.trim();
}),
Expand Down Expand Up @@ -537,20 +529,16 @@ function dockerStartContainer(
}`;
const hostPort = parsePortBindError(trimmed);
if (hostPort === undefined) {
return yield* Effect.fail(
new ContainerStartError({
message: base,
reason: containerCliReason(trimmed),
}),
);
return yield* new ContainerStartError({
message: base,
reason: containerCliReason(trimmed),
});
}
const serviceLabel = spec.networkAliases?.[0] ?? spec.containerName;
return yield* Effect.fail(
new ContainerStartError({
message: `${base}${portConflictSuggestion(hostPort, serviceLabel)}`,
reason: "port_conflict",
}),
);
return yield* new ContainerStartError({
message: `${base}${portConflictSuggestion(hostPort, serviceLabel)}`,
reason: "port_conflict",
});
}
}),
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import { mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";

import { describe, expect, it } from "@effect/vitest";
import { Deferred, Effect, PlatformError, Sink, Stream } from "effect";
import { ChildProcess, ChildProcessSpawner } from "effect/process";
import { afterEach, beforeEach } from "vitest";

import {
ContainerCreateError,
Expand All @@ -22,17 +17,10 @@ import {
createContainer,
volumeExists,
} from "./container-lifecycle.ts";
import { useTempWorkdir } from "../../../tests/helpers/command-mocks.ts";
import type { StartContainerSpec } from "./docker-create-args.ts";

let workdir: string;

beforeEach(() => {
workdir = mkdtempSync(join(tmpdir(), "supabase-start-container-lifecycle-"));
});

afterEach(() => {
rmSync(workdir, { recursive: true, force: true });
});
const workdir = useTempWorkdir("supabase-start-container-lifecycle-");

/** Per-call handler, for multi-step orchestration (volume create -> container create -> start). */
function mockSpawner(
Expand Down Expand Up @@ -142,7 +130,7 @@ describe("createContainer", () => {
return createContainer(mock.spawner, baseSpec, {
projectId: "proj",
isBitbucketPipeline: false,
workdir,
workdir: workdir.current,
extraHosts: [],
}).pipe(
Effect.map((containerId) => {
Expand Down Expand Up @@ -185,12 +173,12 @@ describe("createContainer", () => {
return createContainer(mock.spawner, baseSpec, {
projectId: "proj",
isBitbucketPipeline: false,
workdir,
workdir: workdir.current,
extraHosts: [],
}).pipe(
Effect.map(() => {
const create = mock.spawned.find((args) => args[0] === "create");
expect(create).toContain(`com.supabase.cli.workdir=${workdir}`);
expect(create).toContain(`com.supabase.cli.workdir=${workdir.current}`);
}),
);
},
Expand All @@ -207,7 +195,7 @@ describe("createContainer", () => {
return createContainer(mock.spawner, spec, {
projectId: "proj",
isBitbucketPipeline: false,
workdir,
workdir: workdir.current,
extraHosts: [],
}).pipe(
Effect.map(() => {
Expand All @@ -233,7 +221,7 @@ describe("createContainer", () => {
return createContainer(mock.spawner, spec, {
projectId: "proj",
isBitbucketPipeline: false,
workdir,
workdir: workdir.current,
extraHosts: [],
}).pipe(
Effect.map(() => {
Expand All @@ -252,7 +240,7 @@ describe("createContainer", () => {
return createContainer(mock.spawner, baseSpec, {
projectId: "proj",
isBitbucketPipeline: true,
workdir,
workdir: workdir.current,
extraHosts: [],
}).pipe(
Effect.map(() => {
Expand All @@ -275,7 +263,7 @@ describe("createContainer", () => {
return createContainer(mock.spawner, baseSpec, {
projectId: "proj",
isBitbucketPipeline: false,
workdir,
workdir: workdir.current,
extraHosts: [],
}).pipe(
Effect.flip,
Expand All @@ -296,7 +284,7 @@ describe("createContainer", () => {
return createContainer(mock.spawner, spec, {
projectId: "proj",
isBitbucketPipeline: false,
workdir,
workdir: workdir.current,
extraHosts: [],
}).pipe(
Effect.flip,
Expand All @@ -318,7 +306,7 @@ describe("createContainer", () => {
return createContainer(mock.spawner, spec, {
projectId: "proj",
isBitbucketPipeline: false,
workdir,
workdir: workdir.current,
extraHosts: [],
}).pipe(
Effect.flip,
Expand Down Expand Up @@ -349,7 +337,7 @@ describe("createContainer", () => {
return createContainer(mock.spawner, spec, {
projectId: "proj",
isBitbucketPipeline: false,
workdir,
workdir: workdir.current,
extraHosts: [],
}).pipe(
Effect.flip,
Expand Down Expand Up @@ -391,7 +379,7 @@ describe("createContainer secretFiles", () => {
const containerId = yield* createContainer(mock.spawner, spec, {
projectId: "proj",
isBitbucketPipeline: false,
workdir,
workdir: workdir.current,
extraHosts: [],
});

Expand Down Expand Up @@ -459,7 +447,7 @@ describe("createContainer secretFiles", () => {
return createContainer(mock.spawner, spec, {
projectId: "proj",
isBitbucketPipeline: false,
workdir,
workdir: workdir.current,
extraHosts: [],
}).pipe(
Effect.flip,
Expand Down Expand Up @@ -493,7 +481,7 @@ describe("createContainer secretFiles", () => {
return createContainer(mock.spawner, spec, {
projectId: "proj",
isBitbucketPipeline: false,
workdir,
workdir: workdir.current,
extraHosts: [],
}).pipe(
Effect.flip,
Expand Down Expand Up @@ -523,7 +511,7 @@ describe("createContainer secretFiles", () => {
return createContainer(mock.spawner, spec, {
projectId: "proj",
isBitbucketPipeline: false,
workdir,
workdir: workdir.current,
extraHosts: [],
}).pipe(
Effect.flip,
Expand Down Expand Up @@ -585,11 +573,7 @@ describe("ensureNetwork", () => {
stderr:
"Error response from daemon: network with name supabase_network_proj already exists\n",
}));
return ensureNetwork(mock.spawner, "supabase_network_proj", {}).pipe(
Effect.map(() => {
// Just needs to not fail — no return value to assert on.
}),
);
return ensureNetwork(mock.spawner, "supabase_network_proj", {});
});

it.live("fails with NetworkCreateError on any other failure", () => {
Expand Down Expand Up @@ -649,23 +633,15 @@ describe("ensureVolume", () => {
exitCode: 125,
stderr: "Error: volume with name supabase_db_proj already exists: volume already exists\n",
}));
return ensureVolume(mock.spawner, "supabase_db_proj", {}).pipe(
Effect.map(() => {
// Just needs to not fail — no return value to assert on.
}),
);
return ensureVolume(mock.spawner, "supabase_db_proj", {});
});

it.live("treats an already-exists rejection without the trailing sentinel as success", () => {
const mock = mockSpawner(() => ({
exitCode: 125,
stderr: "volume with name supabase_db_proj already exists\n",
}));
return ensureVolume(mock.spawner, "supabase_db_proj", {}).pipe(
Effect.map(() => {
// Just needs to not fail — no return value to assert on.
}),
);
return ensureVolume(mock.spawner, "supabase_db_proj", {});
});

it.live("fails with VolumeCreateError on any other failure", () => {
Expand Down Expand Up @@ -852,7 +828,7 @@ describe("createContainer with an empty containerName (the shadow database)", ()
return createContainer(mock.spawner, spec, {
projectId: "proj",
isBitbucketPipeline: false,
workdir,
workdir: workdir.current,
extraHosts: [],
}).pipe(
Effect.map((containerId) => {
Expand Down
Loading
Loading