Skip to content

Commit 7af789b

Browse files
authored
fix(deployments): external build token generation issue (#3070)
Fixes an issue introduced in #3024. The behavior for local builds in older CLI versions relies on `externalBuildData` to be defined to distinguish from the self-hosting local build path, even though it doesn't actually use the token.
1 parent 72ce6a8 commit 7af789b

File tree

5 files changed

+61
-29
lines changed

5 files changed

+61
-29
lines changed

.changeset/tricky-suits-design.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@trigger.dev/sdk": patch
3+
"trigger.dev": patch
4+
"@trigger.dev/core": patch
5+
---
6+
7+
Fixed a minor issue in the deployment command on distinguishing between local builds for the cloud vs local builds for self-hosting setups.

apps/webapp/app/v3/services/deployment.server.ts

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,9 @@ export class DeploymentService extends BaseService {
110110
const createRemoteBuildIfNeeded = deployment.buildServerMetadata?.isNativeBuild
111111
? okAsync(undefined)
112112
: fromPromise(createRemoteImageBuild(authenticatedEnv.project), (error) => ({
113-
type: "failed_to_create_remote_build" as const,
114-
cause: error,
115-
}));
113+
type: "failed_to_create_remote_build" as const,
114+
cause: error,
115+
}));
116116

117117
const existingBuildServerMetadata = deployment.buildServerMetadata as
118118
| BuildServerMetadata
@@ -134,7 +134,7 @@ export class DeploymentService extends BaseService {
134134
},
135135
}
136136
: {}),
137-
externalBuildData,
137+
...(externalBuildData ? { externalBuildData } : {}),
138138
status: "BUILDING",
139139
installedAt: new Date(),
140140
},
@@ -496,14 +496,16 @@ export class DeploymentService extends BaseService {
496496
type: "other" as const,
497497
cause: error,
498498
})
499-
).andThen((deployment) => {
500-
if (!deployment) {
501-
return errAsync({ type: "deployment_not_found" as const });
502-
}
503-
return okAsync(deployment);
504-
}).map((deployment) => ({
505-
...deployment,
506-
buildServerMetadata: BuildServerMetadata.safeParse(deployment.buildServerMetadata).data,
507-
}));
499+
)
500+
.andThen((deployment) => {
501+
if (!deployment) {
502+
return errAsync({ type: "deployment_not_found" as const });
503+
}
504+
return okAsync(deployment);
505+
})
506+
.map((deployment) => ({
507+
...deployment,
508+
buildServerMetadata: BuildServerMetadata.safeParse(deployment.buildServerMetadata).data,
509+
}));
508510
}
509511
}

apps/webapp/app/v3/services/initializeDeployment.server.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
import { BuildServerMetadata, type InitializeDeploymentRequestBody } from "@trigger.dev/core/v3";
1+
import {
2+
BuildServerMetadata,
3+
type InitializeDeploymentRequestBody,
4+
type ExternalBuildData,
5+
} from "@trigger.dev/core/v3";
26
import { customAlphabet } from "nanoid";
37
import { env } from "~/env.server";
48
import { type AuthenticatedEnvironment } from "~/services/apiAuth.server";
@@ -89,12 +93,18 @@ export class InitializeDeploymentService extends BaseService {
8993
);
9094
}
9195

92-
// For the `PENDING` initial status, defer the creation of the Depot build until the deployment is started.
93-
// This helps avoid Depot token expiration issues.
94-
const externalBuildData =
95-
payload.initialStatus === "PENDING" || payload.isNativeBuild
96-
? undefined
97-
: await createRemoteImageBuild(environment.project);
96+
// For the `PENDING` initial status, defer the creation of the Depot build until the deployment is started to avoid token expiration issues.
97+
// For local and native builds we don't need to generate the Depot tokens. We still need to create an empty object sadly due to a bug in older CLI versions.
98+
const generateExternalBuildToken =
99+
payload.initialStatus === "PENDING" || payload.isNativeBuild || payload.isLocalBuild;
100+
101+
const externalBuildData = generateExternalBuildToken
102+
? ({
103+
projectId: "-",
104+
buildToken: "-",
105+
buildId: "-",
106+
} satisfies ExternalBuildData)
107+
: await createRemoteImageBuild(environment.project);
98108

99109
const triggeredBy = payload.userId
100110
? await this._prisma.user.findFirst({

packages/cli-v3/src/commands/deploy.ts

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -197,11 +197,18 @@ export function configureDeployCommand(program: Command) {
197197
)
198198
// Local build options
199199
.addOption(
200-
new CommandOption("--force-local-build", "Deprecated alias for --local-build").implies({
201-
localBuild: true,
202-
})
200+
new CommandOption("--force-local-build", "Deprecated alias for --local-build")
201+
.implies({
202+
localBuild: true,
203+
})
204+
.conflicts("nativeBuildServer")
205+
.hideHelp()
206+
)
207+
.addOption(
208+
new CommandOption("--local-build", "Build the deployment image locally").conflicts(
209+
"nativeBuildServer"
210+
)
203211
)
204-
.addOption(new CommandOption("--local-build", "Build the deployment image locally"))
205212
.addOption(new CommandOption("--push", "Push the image after local builds").hideHelp())
206213
.addOption(
207214
new CommandOption("--no-push", "Do not push the image after local builds").hideHelp()
@@ -420,14 +427,19 @@ async function _deployCommand(dir: string, options: DeployCommandOptions) {
420427
gitMeta,
421428
type: features.run_engine_v2 ? "MANAGED" : "V1",
422429
runtime: buildManifest.runtime,
430+
isLocalBuild: options.localBuild,
423431
isNativeBuild: false,
424432
triggeredVia: getTriggeredVia(),
425433
},
426434
envVars.TRIGGER_EXISTING_DEPLOYMENT_ID
427435
);
436+
437+
// When `externalBuildData` is not present the deployment implicitly goes into the local build path
438+
// which is used in self-hosted setups. There are a few subtle differences between local builds for the cloud
439+
// and local builds for self-hosted setups. We need to make the separation of the two paths clearer to avoid confusion.
428440
const isLocalBuild = options.localBuild || !deployment.externalBuildData;
429-
// Would be best to actually store this separately in the deployment object. This is an okay proxy for now.
430-
const remoteBuildExplicitlySkipped = options.localBuild && !!deployment.externalBuildData;
441+
const authenticateToTriggerRegistry = options.localBuild;
442+
const skipServerSideRegistryPush = options.localBuild;
431443

432444
// Fail fast if we know local builds will fail
433445
if (isLocalBuild) {
@@ -559,7 +571,7 @@ async function _deployCommand(dir: string, options: DeployCommandOptions) {
559571
network: options.network,
560572
builder: options.builder,
561573
push: options.push,
562-
authenticateToRegistry: remoteBuildExplicitlySkipped,
574+
authenticateToRegistry: authenticateToTriggerRegistry,
563575
});
564576

565577
logger.debug("Build result", buildResult);
@@ -657,7 +669,7 @@ async function _deployCommand(dir: string, options: DeployCommandOptions) {
657669
{
658670
imageDigest: buildResult.digest,
659671
skipPromotion: options.skipPromotion,
660-
skipPushToRegistry: remoteBuildExplicitlySkipped,
672+
skipPushToRegistry: skipServerSideRegistryPush,
661673
},
662674
(logMessage) => {
663675
if (options.plain || isCI) {

packages/core/src/v3/schemas/api.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -601,8 +601,9 @@ const InitializeDeploymentRequestBodyBase = z.object({
601601
type: z.enum(["MANAGED", "UNMANAGED", "V1"]).optional(),
602602
runtime: z.string().optional(),
603603
initialStatus: z.enum(["PENDING", "BUILDING"]).optional(),
604+
isLocalBuild: z.boolean().optional(),
604605
triggeredVia: DeploymentTriggeredVia.optional(),
605-
buildId: z.string().optional()
606+
buildId: z.string().optional(),
606607
});
607608
type BaseOutput = z.output<typeof InitializeDeploymentRequestBodyBase>;
608609

0 commit comments

Comments
 (0)