Skip to content

Commit 7be7c30

Browse files
committed
Added Git data to deployments
1 parent ed30009 commit 7be7c30

File tree

6 files changed

+150
-86
lines changed

6 files changed

+150
-86
lines changed
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { GitPullRequestIcon, GitCommitIcon, GitBranchIcon } from "lucide-react";
2+
import { type GitMetaLinks } from "~/presenters/v3/BranchesPresenter.server";
3+
import { LinkButton } from "./primitives/Buttons";
4+
5+
export function GitMetadata({ git }: { git?: GitMetaLinks | null }) {
6+
if (!git) return null;
7+
return (
8+
<>
9+
{git.branchUrl && <GitMetadataBranch git={git} />}
10+
{git.shortSha && <GitMetadataCommit git={git} />}
11+
{git.pullRequestUrl && git.pullRequestNumber && <GitMetadataPullRequest git={git} />}
12+
</>
13+
);
14+
}
15+
16+
export function GitMetadataBranch({
17+
git,
18+
}: {
19+
git: Pick<GitMetaLinks, "branchUrl" | "branchName">;
20+
}) {
21+
return (
22+
<LinkButton
23+
variant="minimal/small"
24+
LeadingIcon={<GitBranchIcon className="size-4" />}
25+
iconSpacing="gap-x-1"
26+
to={git.branchUrl}
27+
className="pl-1"
28+
>
29+
{git.branchName}
30+
</LinkButton>
31+
);
32+
}
33+
34+
export function GitMetadataCommit({
35+
git,
36+
}: {
37+
git: Pick<GitMetaLinks, "commitUrl" | "shortSha" | "commitMessage">;
38+
}) {
39+
return (
40+
<LinkButton
41+
variant="minimal/small"
42+
to={git.commitUrl}
43+
LeadingIcon={<GitCommitIcon className="size-4" />}
44+
iconSpacing="gap-x-1"
45+
className="pl-1"
46+
>
47+
{`${git.shortSha} / ${git.commitMessage}`}
48+
</LinkButton>
49+
);
50+
}
51+
52+
export function GitMetadataPullRequest({
53+
git,
54+
}: {
55+
git: Pick<GitMetaLinks, "pullRequestUrl" | "pullRequestNumber">;
56+
}) {
57+
if (!git.pullRequestUrl || !git.pullRequestNumber) return null;
58+
59+
return (
60+
<LinkButton
61+
variant="minimal/small"
62+
to={git.pullRequestUrl}
63+
LeadingIcon={<GitPullRequestIcon className="size-4" />}
64+
iconSpacing="gap-x-1"
65+
className="pl-1"
66+
>
67+
#{git.pullRequestNumber}
68+
</LinkButton>
69+
);
70+
}

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

Lines changed: 53 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { GitMeta } from "@trigger.dev/core/v3";
22
import { type z } from "zod";
3-
import { type PrismaClient, prisma } from "~/db.server";
3+
import { Prisma, type PrismaClient, prisma } from "~/db.server";
44
import { type Project } from "~/models/project.server";
55
import { type User } from "~/models/user.server";
66
import { type BranchesOptions } from "~/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.branches/route";
@@ -13,7 +13,7 @@ const BRANCHES_PER_PAGE = 25;
1313

1414
type Options = z.infer<typeof BranchesOptions>;
1515

16-
type GitMetaLinks = {
16+
export type GitMetaLinks = {
1717
/** The cleaned repository URL without any username/password */
1818
repositoryUrl: string;
1919
/** The branch name */
@@ -170,13 +170,7 @@ export class BranchesPresenter {
170170
return [];
171171
}
172172

173-
let git: GitMetaLinks | null = null;
174-
if (branch.git) {
175-
const parsed = GitMeta.safeParse(branch.git);
176-
if (parsed.success) {
177-
git = this.processGitMeta(parsed.data);
178-
}
179-
}
173+
const git = processGitMetadata(branch.git);
180174

181175
return [
182176
{
@@ -190,48 +184,57 @@ export class BranchesPresenter {
190184
limits,
191185
};
192186
}
187+
}
193188

194-
private processGitMeta(gitMeta: GitMeta): GitMetaLinks | null {
195-
if (!gitMeta || !gitMeta.remoteUrl) return null;
196-
197-
// Clean the remote URL by removing any username/password and ensuring it's a proper GitHub URL
198-
const cleanRemoteUrl = (() => {
199-
try {
200-
const url = new URL(gitMeta.remoteUrl);
201-
// Remove any username/password from the URL
202-
url.username = "";
203-
url.password = "";
204-
// Ensure we're using https
205-
url.protocol = "https:";
206-
// Remove any trailing .git
207-
return url.toString().replace(/\.git$/, "");
208-
} catch (e) {
209-
// If URL parsing fails, try to clean it manually
210-
return gitMeta.remoteUrl
211-
.replace(/^git@github\.com:/, "https://github.com/")
212-
.replace(/^https?:\/\/[^@]+@/, "https://")
213-
.replace(/\.git$/, "");
214-
}
215-
})();
216-
217-
if (!gitMeta.commitRef || !gitMeta.commitSha) return null;
218-
219-
const shortSha = gitMeta.commitSha.slice(0, 7);
189+
export function processGitMetadata(data: Prisma.JsonValue): GitMetaLinks | null {
190+
if (!data) return null;
220191

221-
return {
222-
repositoryUrl: cleanRemoteUrl,
223-
branchName: gitMeta.commitRef,
224-
branchUrl: `${cleanRemoteUrl}/tree/${gitMeta.commitRef}`,
225-
commitUrl: `${cleanRemoteUrl}/commit/${gitMeta.commitSha}`,
226-
pullRequestUrl: gitMeta.pullRequestNumber
227-
? `${cleanRemoteUrl}/pull/${gitMeta.pullRequestNumber}`
228-
: undefined,
229-
pullRequestNumber: gitMeta.pullRequestNumber,
230-
compareUrl: `${cleanRemoteUrl}/compare/main...${gitMeta.commitRef}`,
231-
shortSha,
232-
isDirty: gitMeta.dirty ?? false,
233-
commitMessage: gitMeta.commitMessage ?? "",
234-
commitAuthor: gitMeta.commitAuthorName ?? "",
235-
};
192+
const parsed = GitMeta.safeParse(data);
193+
if (!parsed.success) {
194+
return null;
236195
}
196+
197+
if (!parsed.data.remoteUrl) {
198+
return null;
199+
}
200+
201+
// Clean the remote URL by removing any username/password and ensuring it's a proper GitHub URL
202+
const cleanRemoteUrl = (() => {
203+
try {
204+
const url = new URL(parsed.data.remoteUrl);
205+
// Remove any username/password from the URL
206+
url.username = "";
207+
url.password = "";
208+
// Ensure we're using https
209+
url.protocol = "https:";
210+
// Remove any trailing .git
211+
return url.toString().replace(/\.git$/, "");
212+
} catch (e) {
213+
// If URL parsing fails, try to clean it manually
214+
return parsed.data.remoteUrl
215+
.replace(/^git@github\.com:/, "https://github.com/")
216+
.replace(/^https?:\/\/[^@]+@/, "https://")
217+
.replace(/\.git$/, "");
218+
}
219+
})();
220+
221+
if (!parsed.data.commitRef || !parsed.data.commitSha) return null;
222+
223+
const shortSha = parsed.data.commitSha.slice(0, 7);
224+
225+
return {
226+
repositoryUrl: cleanRemoteUrl,
227+
branchName: parsed.data.commitRef,
228+
branchUrl: `${cleanRemoteUrl}/tree/${parsed.data.commitRef}`,
229+
commitUrl: `${cleanRemoteUrl}/commit/${parsed.data.commitSha}`,
230+
pullRequestUrl: parsed.data.pullRequestNumber
231+
? `${cleanRemoteUrl}/pull/${parsed.data.pullRequestNumber}`
232+
: undefined,
233+
pullRequestNumber: parsed.data.pullRequestNumber,
234+
compareUrl: `${cleanRemoteUrl}/compare/main...${parsed.data.commitRef}`,
235+
shortSha,
236+
isDirty: parsed.data.dirty ?? false,
237+
commitMessage: parsed.data.commitMessage ?? "",
238+
commitAuthor: parsed.data.commitAuthorName ?? "",
239+
};
237240
}

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1-
import { type WorkerDeploymentStatus, type WorkerInstanceGroupType } from "@trigger.dev/database";
1+
import {
2+
Prisma,
3+
type WorkerDeploymentStatus,
4+
type WorkerInstanceGroupType,
5+
} from "@trigger.dev/database";
26
import { sqlDatabaseSchema, type PrismaClient, prisma } from "~/db.server";
37
import { type Organization } from "~/models/organization.server";
48
import { type Project } from "~/models/project.server";
59
import { findEnvironmentBySlug } from "~/models/runtimeEnvironment.server";
610
import { type User } from "~/models/user.server";
11+
import { processGitMetadata } from "./BranchesPresenter.server";
712

813
const pageSize = 20;
914

@@ -102,6 +107,7 @@ export class DeploymentListPresenter {
102107
userDisplayName: string | null;
103108
userAvatarUrl: string | null;
104109
type: WorkerInstanceGroupType;
110+
git: Prisma.JsonValue | null;
105111
}[]
106112
>`
107113
SELECT
@@ -117,7 +123,8 @@ export class DeploymentListPresenter {
117123
u."avatarUrl" AS "userAvatarUrl",
118124
wd."builtAt",
119125
wd."deployedAt",
120-
wd."type"
126+
wd."type",
127+
wd."git"
121128
FROM
122129
${sqlDatabaseSchema}."WorkerDeployment" as wd
123130
INNER JOIN
@@ -164,6 +171,7 @@ LIMIT ${pageSize} OFFSET ${pageSize * (page - 1)};`;
164171
avatarUrl: deployment.userAvatarUrl,
165172
}
166173
: undefined,
174+
git: processGitMetadata(deployment.git),
167175
};
168176
}),
169177
};

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { type Project } from "~/models/project.server";
1010
import { findEnvironmentBySlug } from "~/models/runtimeEnvironment.server";
1111
import { type User } from "~/models/user.server";
1212
import { getUsername } from "~/utils/username";
13+
import { processGitMetadata } from "./BranchesPresenter.server";
1314

1415
export type ErrorData = {
1516
name: string;
@@ -98,6 +99,7 @@ export class DeploymentPresenter {
9899
builtAt: true,
99100
deployedAt: true,
100101
createdAt: true,
102+
git: true,
101103
promotions: {
102104
select: {
103105
label: true,
@@ -162,6 +164,7 @@ export class DeploymentPresenter {
162164
errorData: DeploymentPresenter.prepareErrorData(deployment.errorData),
163165
isBuilt: !!deployment.builtAt,
164166
type: deployment.type,
167+
git: processGitMetadata(deployment.git),
165168
},
166169
};
167170
}

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

Lines changed: 7 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ import { GitMeta } from "@trigger.dev/core/v3";
7979
import { logger } from "~/services/logger.server";
8080
import { TextLink } from "~/components/primitives/TextLink";
8181
import { GitBranchIcon, GitCommitIcon, GitPullRequestIcon } from "lucide-react";
82+
import { GitMetadata } from "~/components/GitMetadata";
8283

8384
export const BranchesOptions = z.object({
8485
search: z.string().optional(),
@@ -142,7 +143,9 @@ export async function action({ request }: ActionFunctionArgs) {
142143
if (result.success) {
143144
if (result.alreadyExisted) {
144145
submission.error = {
145-
branchName: `Branch "${result.branch.branchName}" already exists. You can archive it and create a new one with the same name.`,
146+
branchName: [
147+
`Branch "${result.branch.branchName}" already exists. You can archive it and create a new one with the same name.`,
148+
],
146149
};
147150
return json(submission);
148151
}
@@ -154,7 +157,7 @@ export async function action({ request }: ActionFunctionArgs) {
154157
);
155158
}
156159

157-
submission.error = { branchName: result.error };
160+
submission.error = { branchName: [result.error] };
158161
return json(submission);
159162
}
160163

@@ -308,40 +311,10 @@ export default function Page() {
308311
<DateTime date={branch.createdAt} />
309312
</TableCell>
310313
<TableCell className={cellClass}>
311-
<div className="-ml-2 flex items-center">
312-
{branch.git?.branchUrl && (
313-
<LinkButton
314-
variant="minimal/small"
315-
LeadingIcon={<GitBranchIcon className="size-4" />}
316-
iconSpacing="gap-x-1"
317-
to={branch.git.branchUrl}
318-
>
319-
{branch.branchName}
320-
</LinkButton>
321-
)}
322-
{branch.git?.shortSha && (
323-
<LinkButton
324-
variant="minimal/small"
325-
to={branch.git.commitUrl}
326-
LeadingIcon={<GitCommitIcon className="size-4" />}
327-
iconSpacing="gap-x-1"
328-
>
329-
{`${branch.git.shortSha} / ${branch.git.commitMessage}`}
330-
</LinkButton>
331-
)}
332-
{branch.git?.pullRequestUrl && (
333-
<LinkButton
334-
variant="minimal/small"
335-
to={branch.git.pullRequestUrl}
336-
LeadingIcon={<GitPullRequestIcon className="size-4" />}
337-
iconSpacing="gap-x-1"
338-
>
339-
#{branch.git.pullRequestNumber}
340-
</LinkButton>
341-
)}
314+
<div className="-ml-1 flex items-center">
315+
<GitMetadata git={branch.git} />
342316
</div>
343317
</TableCell>
344-
345318
<TableCell className={cellClass}>
346319
{branch.archivedAt ? (
347320
<CheckIcon className="size-4 text-charcoal-400" />

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ import { createSearchParams } from "~/utils/searchParams";
5353
import { deploymentIndexingIsRetryable } from "~/v3/deploymentStatus";
5454
import { compareDeploymentVersions } from "~/v3/utils/deploymentVersions";
5555
import { useEffect } from "react";
56+
import { GitMetadata } from "~/components/GitMetadata";
5657

5758
export const meta: MetaFunction = () => {
5859
return [
@@ -193,6 +194,7 @@ export default function Page() {
193194
<TableHeaderCell>Tasks</TableHeaderCell>
194195
<TableHeaderCell>Deployed at</TableHeaderCell>
195196
<TableHeaderCell>Deployed by</TableHeaderCell>
197+
<TableHeaderCell>Git</TableHeaderCell>
196198
<TableHeaderCell hiddenLabel>Go to page</TableHeaderCell>
197199
</TableRow>
198200
</TableHeader>
@@ -256,6 +258,11 @@ export default function Page() {
256258
"–"
257259
)}
258260
</TableCell>
261+
<TableCell isSelected={isSelected}>
262+
<div className="-ml-1 flex items-center">
263+
<GitMetadata git={deployment.git} />
264+
</div>
265+
</TableCell>
259266
<DeploymentActionsCell
260267
deployment={deployment}
261268
path={path}

0 commit comments

Comments
 (0)