diff --git a/apps/cli/src/next/commands/functions/deploy/deploy.integration.test.ts b/apps/cli/src/next/commands/functions/deploy/deploy.integration.test.ts index edf7c3304f..60f5bfe80d 100644 --- a/apps/cli/src/next/commands/functions/deploy/deploy.integration.test.ts +++ b/apps/cli/src/next/commands/functions/deploy/deploy.integration.test.ts @@ -1549,6 +1549,44 @@ describe("functions deploy", () => { }).pipe(Effect.ensuring(cleanupTempDir(tempDir))); }); + it.live("bundles when Docker only shares the project directory", () => { + const tempDir = makeTempDir(); + const sharedOutputRoot = join(tempDir, "supabase", ".temp"); + let outputPath = ""; + const child = mockChildProcessSpawner({ + exitCode: 0, + onSpawn: (record) => { + if (record.command !== "docker" || record.args[0] !== "run") { + return; + } + outputPath = resolveDockerOutputPath(record.args); + if (!outputPath.startsWith(`${sharedOutputRoot}${sep}`)) { + return; + } + mkdirSync(dirname(outputPath), { recursive: true }); + writeFileSync(outputPath, "eszip-test-output"); + }, + }); + + return Effect.gen(function* () { + yield* Effect.promise(() => writeProjectConfig(tempDir)); + yield* Effect.promise(() => writeLocalFunction(tempDir, "hello-world")); + + const { layer } = setup(tempDir, { + rawArgs: ["functions", "deploy", "hello-world", "--use-docker"], + childLayer: child.layer, + }); + + yield* functionsDeploy({ + ...BASE_FLAGS, + functionNames: ["hello-world"], + useDocker: true, + }).pipe(Effect.provide(layer)); + + expect(outputPath.startsWith(`${sharedOutputRoot}${sep}`)).toBe(true); + }).pipe(Effect.ensuring(cleanupTempDir(tempDir))); + }); + it.live("forwards npm auth environment to the Docker bundler", () => { const tempDir = makeTempDir(); const previousRegistry = process.env["NPM_CONFIG_REGISTRY"]; diff --git a/apps/cli/src/shared/functions/deploy.ts b/apps/cli/src/shared/functions/deploy.ts index 51f0d9a9a8..6783c7a7f5 100644 --- a/apps/cli/src/shared/functions/deploy.ts +++ b/apps/cli/src/shared/functions/deploy.ts @@ -1,7 +1,6 @@ import { brotliCompressSync, constants as zlibConstants } from "node:zlib"; -import { chmod, mkdtemp, readFile, readdir, realpath, rm, stat } from "node:fs/promises"; +import { chmod, mkdir, mkdtemp, readFile, readdir, realpath, rm, stat } from "node:fs/promises"; import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path"; -import { tmpdir } from "node:os"; import { URL } from "node:url"; import { FunctionResponse, operationDefinitions, type ApiClient } from "@supabase/api/effect"; import { @@ -1334,8 +1333,10 @@ const bundleFunctionWithDocker = Effect.fnUntraced(function* ( const output = yield* Output; yield* output.raw(`Bundling Function: ${config.slug}\n`, "stderr"); + const outputRoot = resolve(functionsDir, "..", ".temp"); + yield* Effect.tryPromise(() => mkdir(outputRoot, { recursive: true })); const outputDir = yield* Effect.tryPromise(() => - mkdtemp(join(tmpdir(), `.supabase-output-${config.slug}-`)), + mkdtemp(join(outputRoot, `.supabase-output-${config.slug}-`)), ); try { yield* Effect.tryPromise(() => chmod(outputDir, 0o777));