From 0dd3341d02853845637a6f33646d5fd94a4af282 Mon Sep 17 00:00:00 2001 From: Ittai Zeidman Date: Mon, 2 Nov 2026 18:34:23 +0200 Subject: [PATCH 1/2] fix(functions): print server warnings from function deploys Since apper #35392 the server no longer creates new automations declared in function.jsonc and reports that in the deploy response's `warnings`. The CLI parsed the response as `{ status }`, so the warning (and the private data source warnings) were dropped and deploy just printed "deployed". Keep `warnings` in DeploySingleFunctionResponseSchema, carry it on the deploy result, and print it from formatDeployResult, which now also handles actor warnings for both `deploy` and `actors deploy`. --- docs/commands.md | 3 ++ .../cli/src/cli/commands/actors/deploy.ts | 3 -- .../commands/functions/formatDeployResult.ts | 6 ++++ .../cli/src/cli/commands/project/deploy.ts | 3 -- .../cli/src/core/resources/function/deploy.ts | 2 ++ .../cli/src/core/resources/function/schema.ts | 2 ++ packages/cli/tests/cli/deploy.spec.ts | 20 +++++++++++ .../cli/tests/cli/functions_deploy.spec.ts | 35 +++++++++++++++++++ .../cli/tests/cli/testkit/TestAPIServer.ts | 1 + 9 files changed, 69 insertions(+), 6 deletions(-) diff --git a/docs/commands.md b/docs/commands.md index c6516a577..834b1b917 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -12,6 +12,9 @@ JSON error envelope. Successful results use `RunCommandResult.stdout`; progress and server warnings use the context logger. Deployment reads project resources; deletion only needs the selected app context. +Function and actor deploy responses carry non-fatal server `warnings`. Keep them +in the response schema; `formatDeployResult` prints them under each result line. + ## Branch targeting Discover names with `base44 branches list --app-id --json`. diff --git a/packages/cli/src/cli/commands/actors/deploy.ts b/packages/cli/src/cli/commands/actors/deploy.ts index d3c45df2b..021629797 100644 --- a/packages/cli/src/cli/commands/actors/deploy.ts +++ b/packages/cli/src/cli/commands/actors/deploy.ts @@ -45,9 +45,6 @@ async function deployActorsAction( onResult: (result) => { completed++; formatDeployResult(result, log); - if (result.status !== "error") - for (const warning of result.warnings) - log.warn(`${result.name}: ${warning}`); }, }); const summary = { diff --git a/packages/cli/src/cli/commands/functions/formatDeployResult.ts b/packages/cli/src/cli/commands/functions/formatDeployResult.ts index 39406a203..6fc7bec62 100644 --- a/packages/cli/src/cli/commands/functions/formatDeployResult.ts +++ b/packages/cli/src/cli/commands/functions/formatDeployResult.ts @@ -20,5 +20,11 @@ export function formatDeployResult( log.success(`${label} unchanged`); } else { log.error(`${label} error: ${result.error}`); + return; + } + // Some server warnings already name the function; don't repeat it. + for (const warning of result.warnings ?? []) { + const prefix = `${result.name}: `; + log.warn(warning.startsWith(prefix) ? warning : `${prefix}${warning}`); } } diff --git a/packages/cli/src/cli/commands/project/deploy.ts b/packages/cli/src/cli/commands/project/deploy.ts index c3d0c7a4b..5b21541ba 100644 --- a/packages/cli/src/cli/commands/project/deploy.ts +++ b/packages/cli/src/cli/commands/project/deploy.ts @@ -152,9 +152,6 @@ export async function deployAction( onActorResult: (result) => { actorCompleted++; formatDeployResult(result, log); - if (result.status !== "error") - for (const warning of result.warnings) - log.warn(`${result.name}: ${warning}`); }, }); diff --git a/packages/cli/src/core/resources/function/deploy.ts b/packages/cli/src/core/resources/function/deploy.ts index c0e3f66bf..f8a566e34 100644 --- a/packages/cli/src/core/resources/function/deploy.ts +++ b/packages/cli/src/core/resources/function/deploy.ts @@ -30,6 +30,7 @@ export interface SingleFunctionDeployResult { status: "deployed" | "unchanged" | "error"; error?: string | null; durationMs?: number; + warnings?: string[]; } async function deployOne( @@ -47,6 +48,7 @@ async function deployOne( name: functionWithCode.name, status: response.status, durationMs: Date.now() - start, + warnings: response.warnings, }; } catch (error) { return { diff --git a/packages/cli/src/core/resources/function/schema.ts b/packages/cli/src/core/resources/function/schema.ts index c5610524d..39e64bb5b 100644 --- a/packages/cli/src/core/resources/function/schema.ts +++ b/packages/cli/src/core/resources/function/schema.ts @@ -152,6 +152,8 @@ const BackendFunctionSchema = FunctionConfigSchema.extend({ export const DeploySingleFunctionResponseSchema = z.object({ status: z.enum(["deployed", "unchanged"]), + // Non-fatal notices, e.g. function.jsonc automations the server no longer creates. + warnings: z.array(z.string()).optional().default([]), }); const FunctionInfoSchema = z diff --git a/packages/cli/tests/cli/deploy.spec.ts b/packages/cli/tests/cli/deploy.spec.ts index 3369634e8..7f94c1745 100644 --- a/packages/cli/tests/cli/deploy.spec.ts +++ b/packages/cli/tests/cli/deploy.spec.ts @@ -229,6 +229,26 @@ describe("deploy command (unified)", () => { t.expectResult(result).toContain("App deployed successfully"); }); + it("prints function deploy warnings", async () => { + await t.givenLoggedInWithProject(fixture("with-functions-and-entities")); + t.api.mockEntitiesPush({ created: ["Order"], updated: [], deleted: [] }); + t.api.mockSingleFunctionDeploy({ + status: "deployed", + warnings: ["process-order: automations not created (nightly)."], + }); + t.api.mockAgentsPush({ created: [], updated: [], deleted: [] }); + t.api.mockConnectorsList({ integrations: [] }); + t.api.mockStripeStatus({ stripe_mode: null }); + + const result = await t.run("deploy", "-y"); + + t.expectResult(result).toSucceed(); + t.expectResult(result).toContain( + "process-order: automations not created (nightly).", + ); + t.expectResult(result).toContain("App deployed successfully"); + }); + it("deploys zero-config functions (path-based names) with unified deploy", async () => { await t.givenLoggedInWithProject(fixture("with-zero-config-functions")); t.api.mockEntitiesPush({ created: [], updated: [], deleted: [] }); diff --git a/packages/cli/tests/cli/functions_deploy.spec.ts b/packages/cli/tests/cli/functions_deploy.spec.ts index 573119202..4634f5627 100644 --- a/packages/cli/tests/cli/functions_deploy.spec.ts +++ b/packages/cli/tests/cli/functions_deploy.spec.ts @@ -57,6 +57,41 @@ describe("functions deploy command", () => { t.expectResult(result).toContain("1 unchanged"); }); + it("prints server warnings for a deployed function", async () => { + await t.givenLoggedInWithProject(fixture("with-functions-and-entities")); + t.api.mockSingleFunctionDeploy({ + status: "deployed", + warnings: [ + "process-order: automations not created (nightly) and none removed.", + "Private data source warehouse is unavailable.", + ], + }); + + const result = await t.run("functions", "deploy"); + + t.expectResult(result).toSucceed(); + t.expectResult(result).toContain( + "process-order: automations not created (nightly) and none removed.", + ); + t.expectResult(result).toNotContain("process-order: process-order:"); + t.expectResult(result).toContain( + "process-order: Private data source warehouse is unavailable.", + ); + }); + + it("prints server warnings for an unchanged function", async () => { + await t.givenLoggedInWithProject(fixture("with-functions-and-entities")); + t.api.mockSingleFunctionDeploy({ + status: "unchanged", + warnings: ["Automations are retired."], + }); + + const result = await t.run("functions", "deploy"); + + t.expectResult(result).toSucceed(); + t.expectResult(result).toContain("process-order: Automations are retired."); + }); + it("deploys zero-config and path-named functions successfully", async () => { await t.givenLoggedInWithProject(fixture("with-zero-config-functions")); t.api.mockSingleFunctionDeploy({ status: "deployed" }); diff --git a/packages/cli/tests/cli/testkit/TestAPIServer.ts b/packages/cli/tests/cli/testkit/TestAPIServer.ts index 0ebdba5bb..6ad596c43 100644 --- a/packages/cli/tests/cli/testkit/TestAPIServer.ts +++ b/packages/cli/tests/cli/testkit/TestAPIServer.ts @@ -113,6 +113,7 @@ interface SecretsDeleteResponse { interface SingleFunctionDeployResponse { status: "deployed" | "unchanged"; + warnings?: string[]; } interface AutomationBase { From 348632c4c0d8e195392a2c6fef590900dad8ff96 Mon Sep 17 00:00:00 2001 From: Ittai Zeidman Date: Tue, 3 Nov 2026 11:46:38 +0200 Subject: [PATCH 2/2] chore: drop inline comments --- packages/cli/src/cli/commands/functions/formatDeployResult.ts | 1 - packages/cli/src/core/resources/function/schema.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/cli/src/cli/commands/functions/formatDeployResult.ts b/packages/cli/src/cli/commands/functions/formatDeployResult.ts index 6fc7bec62..2c1d66089 100644 --- a/packages/cli/src/cli/commands/functions/formatDeployResult.ts +++ b/packages/cli/src/cli/commands/functions/formatDeployResult.ts @@ -22,7 +22,6 @@ export function formatDeployResult( log.error(`${label} error: ${result.error}`); return; } - // Some server warnings already name the function; don't repeat it. for (const warning of result.warnings ?? []) { const prefix = `${result.name}: `; log.warn(warning.startsWith(prefix) ? warning : `${prefix}${warning}`); diff --git a/packages/cli/src/core/resources/function/schema.ts b/packages/cli/src/core/resources/function/schema.ts index 39e64bb5b..5f56dc3ec 100644 --- a/packages/cli/src/core/resources/function/schema.ts +++ b/packages/cli/src/core/resources/function/schema.ts @@ -152,7 +152,6 @@ const BackendFunctionSchema = FunctionConfigSchema.extend({ export const DeploySingleFunctionResponseSchema = z.object({ status: z.enum(["deployed", "unchanged"]), - // Non-fatal notices, e.g. function.jsonc automations the server no longer creates. warnings: z.array(z.string()).optional().default([]), });