Skip to content

Commit 5966edc

Browse files
committed
feat(webapp): show the external deployment id on deployments and runs
Deployments page: an always-visible External ID column after Deployed by, and an External ID row in the deployment inspector under Worker type, both showing an en dash when a deploy carried no id. The Vercel Linked column now renders before Git, still only when a Vercel integration is connected. Also corrects the blank-row colSpan, which was already off by one before this column existed. Run inspector: an External deployment ID row between Version and SDK version, read from the run annotations, so an operator can see which id a run was pinned to - including a run that expired before its deployment ever arrived, where the locked version is empty but the id is the whole story. Buffered runs read the id from the same annotations rather than reporting none. Long ids are head-truncated with the full value behind the copy button: a commit SHA is meaningful in its prefix, and the inspector panel can be narrowed to 250px, where an unbroken 40-character SHA would otherwise scroll the properties list sideways and push the copy button off-panel (TRI-12923, TRI-13000).
1 parent 8f7617a commit 5966edc

9 files changed

Lines changed: 102 additions & 7 deletions

File tree

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
area: webapp
3+
type: feature
4+
---
5+
6+
Deployments and runs now show the external ID they were deployed or pinned with, so you can trace a run back to the release of your app that triggered it.

apps/webapp/app/presenters/v3/DeploymentListPresenter.server.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ export class DeploymentListPresenter {
153153
userDisplayName: string | null;
154154
userAvatarUrl: string | null;
155155
type: WorkerInstanceGroupType;
156+
externalId: string | null;
156157
git: Prisma.JsonValue | null;
157158
integrationDeploymentId: string | null;
158159
}[]
@@ -173,6 +174,7 @@ export class DeploymentListPresenter {
173174
wd."builtAt",
174175
wd."deployedAt",
175176
wd."type",
177+
wd."externalId",
176178
wd."git"
177179
${vercelSelect}
178180
FROM
@@ -258,6 +260,7 @@ LIMIT ${pageSize} OFFSET ${pageSize * (page - 1)};`;
258260
avatarUrl: deployment.userAvatarUrl,
259261
}
260262
: undefined,
263+
externalId: deployment.externalId,
261264
git: processGitMetadata(deployment.git),
262265
vercelDeploymentUrl,
263266
};

apps/webapp/app/presenters/v3/DeploymentPresenter.server.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ export class DeploymentPresenter {
101101
externalBuildData: true,
102102
projectId: true,
103103
type: true,
104+
externalId: true,
104105
environment: {
105106
select: {
106107
id: true,
@@ -272,6 +273,7 @@ export class DeploymentPresenter {
272273
errorData: DeploymentPresenter.prepareErrorData(deployment.errorData),
273274
isBuilt: !!deployment.builtAt,
274275
type: deployment.type,
276+
externalId: deployment.externalId,
275277
git: gitMetadata,
276278
triggeredVia: deployment.triggeredVia,
277279
vercelDeploymentUrl,

apps/webapp/app/presenters/v3/SpanPresenter.server.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { readExternalDeploymentIdAnnotation } from "@internal/run-engine";
12
import {
23
type MachinePreset,
34
prettyPrintPacket,
@@ -399,6 +400,7 @@ export class SpanPresenter extends BasePresenter {
399400
ttl: run.ttl,
400401
taskIdentifier: run.taskIdentifier,
401402
version: lockedWorker?.lockedToVersion?.version,
403+
externalDeploymentId: readExternalDeploymentIdAnnotation(run.annotations),
402404
sdkVersion: lockedWorker?.lockedToVersion?.sdkVersion,
403405
runtime: lockedWorker?.lockedToVersion?.runtime,
404406
runtimeVersion: lockedWorker?.lockedToVersion?.runtimeVersion,

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments.$deploymentParam/route.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,21 @@ function getTriggeredViaDisplay(triggeredVia: string | null | undefined): {
180180
}
181181
}
182182

183+
const EXTERNAL_ID_DISPLAY_LENGTH = 24;
184+
185+
function ExternalIdValue({ externalId }: { externalId: string | null }) {
186+
if (!externalId) {
187+
return <></>;
188+
}
189+
190+
const display =
191+
externalId.length > EXTERNAL_ID_DISPLAY_LENGTH
192+
? `${externalId.slice(0, EXTERNAL_ID_DISPLAY_LENGTH)}…`
193+
: externalId;
194+
195+
return <CopyableText value={display} copyValue={externalId} className="font-mono text-sm" />;
196+
}
197+
183198
export default function Page() {
184199
const { deployment, eventStream } = useTypedLoaderData<typeof loader>();
185200
const organization = useOrganization();
@@ -445,6 +460,12 @@ export default function Page() {
445460
<Property.Label>Worker type</Property.Label>
446461
<Property.Value>{capitalizeWord(deployment.type)}</Property.Value>
447462
</Property.Item>
463+
<Property.Item>
464+
<Property.Label>External ID</Property.Label>
465+
<Property.Value>
466+
<ExternalIdValue externalId={deployment.externalId} />
467+
</Property.Value>
468+
</Property.Item>
448469
<Property.Item>
449470
<Property.Label>Started at</Property.Label>
450471
<Property.Value>

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments/route.tsx

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import {
4242
collapsibleHandleClassName,
4343
} from "~/components/primitives/Resizable";
4444
import {
45+
CopyableTableCell,
4546
Table,
4647
TableBlankRow,
4748
TableBody,
@@ -256,8 +257,9 @@ export default function Page() {
256257
<TableHeaderCell>Tasks</TableHeaderCell>
257258
<TableHeaderCell>Deployed at</TableHeaderCell>
258259
<TableHeaderCell>Deployed by</TableHeaderCell>
259-
<TableHeaderCell>Git</TableHeaderCell>
260+
<TableHeaderCell>External ID</TableHeaderCell>
260261
{hasVercelIntegration && <TableHeaderCell>Linked</TableHeaderCell>}
262+
<TableHeaderCell>Git</TableHeaderCell>
261263
<TableHeaderCell hiddenLabel>Go to page</TableHeaderCell>
262264
</TableRow>
263265
</TableHeader>
@@ -332,11 +334,11 @@ export default function Page() {
332334
"–"
333335
)}
334336
</TableCell>
335-
<TableCell isSelected={isSelected}>
336-
<div className="-ml-1 flex items-center">
337-
<GitMetadata git={deployment.git} />
338-
</div>
339-
</TableCell>
337+
<DeploymentExternalIdCell
338+
externalId={deployment.externalId}
339+
path={path}
340+
isSelected={isSelected}
341+
/>
340342
{hasVercelIntegration && (
341343
<TableCell isSelected={isSelected}>
342344
{deployment.vercelDeploymentUrl ? (
@@ -353,6 +355,11 @@ export default function Page() {
353355
)}
354356
</TableCell>
355357
)}
358+
<TableCell isSelected={isSelected}>
359+
<div className="-ml-1 flex items-center">
360+
<GitMetadata git={deployment.git} />
361+
</div>
362+
</TableCell>
356363
<DeploymentActionsCell
357364
deployment={deployment}
358365
path={path}
@@ -364,7 +371,7 @@ export default function Page() {
364371
);
365372
})
366373
) : (
367-
<TableBlankRow colSpan={hasVercelIntegration ? 9 : 8}>
374+
<TableBlankRow colSpan={hasVercelIntegration ? 11 : 10}>
368375
<Paragraph className="flex items-center justify-center">
369376
No deploys match your filters
370377
</Paragraph>
@@ -602,6 +609,30 @@ function DeploymentActionsCell({
602609
);
603610
}
604611

612+
function DeploymentExternalIdCell({
613+
externalId,
614+
path,
615+
isSelected,
616+
}: {
617+
externalId: string | null;
618+
path: string;
619+
isSelected: boolean;
620+
}) {
621+
if (!externalId) {
622+
return (
623+
<TableCell to={path} isSelected={isSelected}>
624+
625+
</TableCell>
626+
);
627+
}
628+
629+
return (
630+
<CopyableTableCell to={path} isSelected={isSelected} className="font-mono" value={externalId}>
631+
{externalId.length > 12 ? `${externalId.slice(0, 12)}…` : externalId}
632+
</CopyableTableCell>
633+
);
634+
}
635+
605636
type RollbackDeploymentDialogProps = {
606637
projectId: string;
607638
deploymentShortCode: string;

apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -872,6 +872,12 @@ function RunBody({
872872
)}
873873
</Property.Value>
874874
</Property.Item>
875+
<Property.Item>
876+
<Property.Label>External deployment ID</Property.Label>
877+
<Property.Value>
878+
<ExternalDeploymentIdValue externalDeploymentId={run.externalDeploymentId} />
879+
</Property.Value>
880+
</Property.Item>
875881
<Property.Item>
876882
<Property.Label>SDK version</Property.Label>
877883
<Property.Value>
@@ -1274,6 +1280,27 @@ function MiniStat({
12741280
);
12751281
}
12761282

1283+
const EXTERNAL_DEPLOYMENT_ID_DISPLAY_LENGTH = 24;
1284+
1285+
function ExternalDeploymentIdValue({
1286+
externalDeploymentId,
1287+
}: {
1288+
externalDeploymentId: string | undefined;
1289+
}) {
1290+
if (!externalDeploymentId) {
1291+
return <></>;
1292+
}
1293+
1294+
const display =
1295+
externalDeploymentId.length > EXTERNAL_DEPLOYMENT_ID_DISPLAY_LENGTH
1296+
? `${externalDeploymentId.slice(0, EXTERNAL_DEPLOYMENT_ID_DISPLAY_LENGTH)}…`
1297+
: externalDeploymentId;
1298+
1299+
return (
1300+
<CopyableText value={display} copyValue={externalDeploymentId} className="font-mono" asChild />
1301+
);
1302+
}
1303+
12771304
// A compact "mini queue" for a waiting run: the queue page's stat blocks + charts, scaled down.
12781305
function WaitingInQueueBlock({
12791306
queueName,

apps/webapp/app/v3/mollifier/syntheticSpanRun.server.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { readExternalDeploymentIdAnnotation } from "@internal/run-engine";
12
import { prettyPrintPacket, RunAnnotations } from "@trigger.dev/core/v3";
23
import { getMaxDuration } from "@trigger.dev/core/v3/isomorphic";
34
import {
@@ -124,6 +125,7 @@ export async function buildSyntheticSpanRun(args: {
124125
ttl: run.ttl ?? null,
125126
taskIdentifier: run.taskIdentifier ?? "",
126127
version: undefined,
128+
externalDeploymentId: readExternalDeploymentIdAnnotation(run.annotations),
127129
sdkVersion: undefined,
128130
runtime: undefined,
129131
runtimeVersion: undefined,

internal-packages/run-engine/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export type {
1212
PendingVersionRunIdLookupResult,
1313
} from "./engine/services/pendingVersionLookup.js";
1414
export { NoopPendingVersionRunIdLookup } from "./engine/services/pendingVersionLookup.js";
15+
export { readExternalDeploymentIdAnnotation } from "./engine/systems/pendingVersionSystem.js";
1516
export { PassthroughControlPlaneResolver } from "./engine/controlPlaneResolver.js";
1617
export type {
1718
ControlPlaneResolver,

0 commit comments

Comments
 (0)