Skip to content

Commit 7b296ce

Browse files
committed
feat(deployments): propagate build metadata and conditionally enqueue
Include build server metadata in progress API and deployment handling, add skipEnqueue flag, and avoid enque builds for GitHub-integrated ments without artifact keys. - Add BuildServerMetadata schema and include it in ProgressDeploymentRequestBody. - Thread buildServerMetadata through API handler into deployment service. - Make artifactKey optional for native builds and add skipEnqueue with default false to request validation. - When progressing deployments, merge incoming buildServerMetadata and validate against existing metadata. - Only enqueue native builds when artifactKey is present and skipEnqueue is false. This prevents enqueue attempts for GitHub integrated builds that lack an artifactKey.
1 parent bfe417f commit 7b296ce

File tree

4 files changed

+92
-52
lines changed

4 files changed

+92
-52
lines changed

apps/webapp/app/routes/api.v1.deployments.$deploymentId.progress.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ export async function action({ request, params }: ActionFunctionArgs) {
4848
contentHash: body.data.contentHash,
4949
git: body.data.gitMeta,
5050
runtime: body.data.runtime,
51+
buildServerMetadata: body.data.buildServerMetadata,
5152
})
5253
.match(
5354
() => {

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

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@ import { type AuthenticatedEnvironment } from "~/services/apiAuth.server";
22
import { BaseService } from "./baseService.server";
33
import { errAsync, fromPromise, okAsync, type ResultAsync } from "neverthrow";
44
import { type WorkerDeployment, type Project } from "@trigger.dev/database";
5-
import { BuildServerMetadata, logger, type GitMeta, type DeploymentEvent } from "@trigger.dev/core/v3";
5+
import {
6+
BuildServerMetadata,
7+
logger,
8+
type GitMeta,
9+
type DeploymentEvent,
10+
} from "@trigger.dev/core/v3";
611
import { TimeoutDeploymentService } from "./timeoutDeployment.server";
712
import { env } from "~/env.server";
813
import { createRemoteImageBuild } from "../remoteImageBuilder.server";
@@ -38,9 +43,20 @@ export class DeploymentService extends BaseService {
3843
public progressDeployment(
3944
authenticatedEnv: AuthenticatedEnvironment,
4045
friendlyId: string,
41-
updates: Partial<Pick<WorkerDeployment, "contentHash" | "runtime"> & { git: GitMeta }>
46+
updates: Partial<
47+
Pick<WorkerDeployment, "contentHash" | "runtime"> & {
48+
git: GitMeta;
49+
buildServerMetadata: BuildServerMetadata;
50+
}
51+
>
4252
) {
43-
const validateDeployment = (deployment: Pick<WorkerDeployment, "id" | "status"> & { buildServerMetadata?: BuildServerMetadata }) => {
53+
const { buildServerMetadata: newBuildServerMetadata, ...restUpdates } = updates;
54+
55+
const validateDeployment = (
56+
deployment: Pick<WorkerDeployment, "id" | "status"> & {
57+
buildServerMetadata?: BuildServerMetadata;
58+
}
59+
) => {
4460
if (deployment.status !== "PENDING" && deployment.status !== "INSTALLING") {
4561
logger.warn(
4662
"Attempted progressing deployment that is not in PENDING or INSTALLING status",
@@ -54,12 +70,27 @@ export class DeploymentService extends BaseService {
5470
return okAsync(deployment);
5571
};
5672

57-
const progressToInstalling = (deployment: Pick<WorkerDeployment, "id">) =>
58-
fromPromise(
73+
const progressToInstalling = (
74+
deployment: Pick<WorkerDeployment, "id"> & { buildServerMetadata?: BuildServerMetadata }
75+
) => {
76+
const existingBuildServerMetadata = deployment.buildServerMetadata as
77+
| BuildServerMetadata
78+
| null
79+
| undefined;
80+
81+
return fromPromise(
5982
this._prisma.workerDeployment.updateMany({
6083
where: { id: deployment.id, status: "PENDING" }, // status could've changed in the meantime, we're not locking the row
6184
data: {
62-
...updates,
85+
...restUpdates,
86+
...(newBuildServerMetadata
87+
? {
88+
buildServerMetadata: {
89+
...(existingBuildServerMetadata ?? {}),
90+
...newBuildServerMetadata,
91+
},
92+
}
93+
: {}),
6394
status: "INSTALLING",
6495
startedAt: new Date(),
6596
},
@@ -74,6 +105,7 @@ export class DeploymentService extends BaseService {
74105
}
75106
return okAsync({ id: deployment.id, status: "INSTALLING" as const });
76107
});
108+
};
77109

78110
const progressToBuilding = (
79111
deployment: Pick<WorkerDeployment, "id"> & { buildServerMetadata?: BuildServerMetadata }
@@ -85,13 +117,26 @@ export class DeploymentService extends BaseService {
85117
cause: error,
86118
}));
87119

120+
const existingBuildServerMetadata = deployment.buildServerMetadata as
121+
| BuildServerMetadata
122+
| null
123+
| undefined;
124+
88125
return createRemoteBuildIfNeeded
89126
.andThen((externalBuildData) =>
90127
fromPromise(
91128
this._prisma.workerDeployment.updateMany({
92129
where: { id: deployment.id, status: "INSTALLING" }, // status could've changed in the meantime, we're not locking the row
93130
data: {
94-
...updates,
131+
...restUpdates,
132+
...(newBuildServerMetadata
133+
? {
134+
buildServerMetadata: {
135+
...(existingBuildServerMetadata ?? {}),
136+
...newBuildServerMetadata,
137+
},
138+
}
139+
: {}),
95140
externalBuildData,
96141
status: "BUILDING",
97142
installedAt: new Date(),

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ export class InitializeDeploymentService extends BaseService {
200200
artifactKey: payload.artifactKey,
201201
skipPromotion: payload.skipPromotion,
202202
configFilePath: payload.configFilePath,
203+
skipEnqueue: payload.skipEnqueue,
203204
}
204205
: {}),
205206
}
@@ -238,7 +239,8 @@ export class InitializeDeploymentService extends BaseService {
238239
new Date(Date.now() + timeoutMs)
239240
);
240241

241-
if (payload.isNativeBuild) {
242+
// For github integration there is no artifactKey, hence we skip it here
243+
if (payload.isNativeBuild && payload.artifactKey && !payload.skipEnqueue) {
242244
const result = await deploymentService
243245
.enqueueBuild(environment, deployment, payload.artifactKey, {
244246
skipPromotion: payload.skipPromotion,

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

Lines changed: 36 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -485,10 +485,22 @@ export const FinalizeDeploymentRequestBody = z.object({
485485

486486
export type FinalizeDeploymentRequestBody = z.infer<typeof FinalizeDeploymentRequestBody>;
487487

488+
export const BuildServerMetadata = z.object({
489+
buildId: z.string().optional(),
490+
isNativeBuild: z.boolean().optional(),
491+
artifactKey: z.string().optional(),
492+
skipPromotion: z.boolean().optional(),
493+
configFilePath: z.string().optional(),
494+
skipEnqueue: z.boolean().optional(),
495+
});
496+
497+
export type BuildServerMetadata = z.infer<typeof BuildServerMetadata>;
498+
488499
export const ProgressDeploymentRequestBody = z.object({
489500
contentHash: z.string().optional(),
490501
gitMeta: GitMeta.optional(),
491502
runtime: z.string().optional(),
503+
buildServerMetadata: BuildServerMetadata.optional(),
492504
});
493505

494506
export type ProgressDeploymentRequestBody = z.infer<typeof ProgressDeploymentRequestBody>;
@@ -528,16 +540,6 @@ export const DeploymentTriggeredVia = z
528540

529541
export type DeploymentTriggeredVia = z.infer<typeof DeploymentTriggeredVia>;
530542

531-
export const BuildServerMetadata = z.object({
532-
buildId: z.string().optional(),
533-
isNativeBuild: z.boolean().optional(),
534-
artifactKey: z.string().optional(),
535-
skipPromotion: z.boolean().optional(),
536-
configFilePath: z.string().optional(),
537-
});
538-
539-
export type BuildServerMetadata = z.infer<typeof BuildServerMetadata>;
540-
541543
export const UpsertBranchRequestBody = z.object({
542544
git: GitMeta.optional(),
543545
env: z.enum(["preview"]),
@@ -590,41 +592,31 @@ export const InitializeDeploymentResponseBody = z.object({
590592

591593
export type InitializeDeploymentResponseBody = z.infer<typeof InitializeDeploymentResponseBody>;
592594

593-
export const InitializeDeploymentRequestBody = z
594-
.object({
595-
contentHash: z.string(),
596-
userId: z.string().optional(),
597-
/** @deprecated This is now determined by the webapp. This is only used to warn users with old CLI versions. */
598-
selfHosted: z.boolean().optional(),
599-
gitMeta: GitMeta.optional(),
600-
type: z.enum(["MANAGED", "UNMANAGED", "V1"]).optional(),
601-
runtime: z.string().optional(),
602-
initialStatus: z.enum(["PENDING", "BUILDING"]).optional(),
603-
triggeredVia: DeploymentTriggeredVia.optional(),
604-
buildId: z.string().optional(),
595+
const InitializeDeploymentRequestBodyBase = z.object({
596+
contentHash: z.string(),
597+
userId: z.string().optional(),
598+
/** @deprecated This is now determined by the webapp. This is only used to warn users with old CLI versions. */
599+
selfHosted: z.boolean().optional(),
600+
gitMeta: GitMeta.optional(),
601+
type: z.enum(["MANAGED", "UNMANAGED", "V1"]).optional(),
602+
runtime: z.string().optional(),
603+
initialStatus: z.enum(["PENDING", "BUILDING"]).optional(),
604+
triggeredVia: DeploymentTriggeredVia.optional(),
605+
buildId: z.string().optional(),
606+
isNativeBuild: z.boolean().default(false).optional()
607+
})
608+
export const InitializeDeploymentRequestBody = z.discriminatedUnion("isNativeBuild", [
609+
InitializeDeploymentRequestBodyBase.extend({
610+
isNativeBuild: z.literal(true),
611+
skipPromotion: z.boolean().optional(),
612+
artifactKey: z.string().optional(),
613+
configFilePath: z.string().optional(),
614+
skipEnqueue: z.boolean().default(false).optional(),
615+
}),
616+
InitializeDeploymentRequestBodyBase.extend({
617+
isNativeBuild: z.literal(false).optional(),
605618
})
606-
.and(
607-
z.preprocess(
608-
(val) => {
609-
const obj = val as any;
610-
if (!obj || !obj.isNativeBuild) {
611-
return { ...obj, isNativeBuild: false };
612-
}
613-
return obj;
614-
},
615-
z.discriminatedUnion("isNativeBuild", [
616-
z.object({
617-
isNativeBuild: z.literal(true),
618-
skipPromotion: z.boolean(),
619-
artifactKey: z.string(),
620-
configFilePath: z.string().optional(),
621-
}),
622-
z.object({
623-
isNativeBuild: z.literal(false),
624-
}),
625-
])
626-
)
627-
);
619+
]);
628620

629621
export type InitializeDeploymentRequestBody = z.infer<typeof InitializeDeploymentRequestBody>;
630622

0 commit comments

Comments
 (0)