Skip to content

Commit

Permalink
GitHub webhook (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
adityachoudhari26 authored Aug 27, 2024
1 parent 559e38f commit 67b610e
Show file tree
Hide file tree
Showing 9 changed files with 511 additions and 113 deletions.
2 changes: 2 additions & 0 deletions apps/webservice/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
"@internationalized/date": "^3.5.4",
"@monaco-editor/react": "^4.6.0",
"@octokit/auth-app": "^7.1.0",
"@octokit/rest": "^20.1.1",
"@octokit/webhooks-types": "^7.5.1",
"@opentelemetry/api-logs": "^0.52.1",
"@opentelemetry/instrumentation": "^0.52.1",
"@opentelemetry/sdk-logs": "^0.52.1",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { GithubConfigFile } from "@ctrlplane/db/schema";
import {
Card,
CardContent,
Expand All @@ -7,15 +8,9 @@ import {
} from "@ctrlplane/ui/card";
import { Separator } from "@ctrlplane/ui/separator";

import { api } from "~/trpc/react";

export const GithubConfigFileSync: React.FC<{
workspaceId?: string;
}> = ({ workspaceId }) => {
const configFiles = api.github.configFile.list.useQuery(workspaceId ?? "", {
enabled: workspaceId != null,
});

configFiles: GithubConfigFile[];
}> = ({ configFiles }) => {
return (
<Card className="rounded-md">
<CardHeader className="space-y-2">
Expand All @@ -31,8 +26,8 @@ export const GithubConfigFileSync: React.FC<{
<Separator />

<CardContent className="p-4">
{configFiles.data?.map((configFile) => (
<div key={configFile.id}>{configFile.name}</div>
{configFiles.map((configFile) => (
<div key={configFile.id}>{configFile.path}</div>
))}
</CardContent>
</Card>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ export default function GitHubIntegrationPage({
enabled: session.status === "authenticated",
});

const configFiles = api.github.configFile.list.useQuery(
workspace.data?.id ?? "",
{ enabled: workspace.data != null },
);

return (
<div className="flex flex-col gap-12">
<div className="flex items-center gap-4">
Expand Down Expand Up @@ -77,7 +82,7 @@ export default function GitHubIntegrationPage({
loading={workspace.isLoading || githubUser.isLoading}
/>

<GithubConfigFileSync workspaceId={workspace.data?.id} />
<GithubConfigFileSync configFiles={configFiles.data ?? []} />
</div>
);
}
207 changes: 207 additions & 0 deletions apps/webservice/src/app/api/github/config/handle-configs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
import { and, eq, inArray } from "@ctrlplane/db";
import { db } from "@ctrlplane/db/client";
import type {
GithubOrganization} from "@ctrlplane/db/schema";
import {
deployment,
githubConfigFile,
system,
workspace,
} from "@ctrlplane/db/schema";

interface DeploymentConfig {
name: string;
slug: string;
system: string;
workspace: string;
description?: string;
}

interface ParsedConfig {
path: string;
repositoryName: string;
branch: string;
deployments: DeploymentConfig[];
}

export const handleNewConfigs = async (
newParsedConfigs: ParsedConfig[],
internalOrganization: GithubOrganization,
repositoryName: string,
) => {
if (newParsedConfigs.length === 0) return;

const newConfigs = await db
.insert(githubConfigFile)
.values(
newParsedConfigs.map((cf) => ({
...cf,
workspaceId: internalOrganization.workspaceId,
organizationId: internalOrganization.id,
repositoryName: repositoryName,
})),
)
.returning();

const newDeploymentInfo = await db
.select()
.from(system)
.innerJoin(workspace, eq(system.workspaceId, workspace.id))
.where(
and(
inArray(
system.slug,
newParsedConfigs
.map((d) => d.deployments.map((d) => d.system))
.flat(),
),
inArray(
workspace.slug,
newParsedConfigs
.map((d) => d.deployments.map((d) => d.workspace))
.flat(),
),
),
);

const deploymentsFromNewConfigs = newParsedConfigs
.map((cf) =>
cf.deployments.map((d) => {
const info = newDeploymentInfo.find(
(i) => i.system.slug === d.system && i.workspace.slug === d.workspace,
);
if (info == null) throw new Error("Deployment info not found");
const { system, workspace } = info;

return {
...d,
systemId: system.id,
workspaceId: workspace.id,
description: d.description ?? "",
githubConfigFileId: newConfigs.find(
(icf) =>
icf.path === cf.path && icf.repositoryName === cf.repositoryName,
)?.id,
};
}),
)
.flat();

await db.insert(deployment).values(deploymentsFromNewConfigs);
};

export const handleModifiedConfigs = async (
modifiedParsedConfigs: ParsedConfig[],
internalOrganization: GithubOrganization,
repositoryName: string,
) => {
if (modifiedParsedConfigs.length === 0) return;
const existingConfigs = await db
.select()
.from(githubConfigFile)
.where(
and(
inArray(
githubConfigFile.path,
modifiedParsedConfigs.map((cf) => cf.path),
),
eq(githubConfigFile.organizationId, internalOrganization.id),
eq(githubConfigFile.repositoryName, repositoryName),
),
);

const existingDeployments = await db
.select()
.from(deployment)
.innerJoin(system, eq(deployment.systemId, system.id))
.innerJoin(workspace, eq(system.workspaceId, workspace.id))
.where(
inArray(
deployment.githubConfigFileId,
existingConfigs.map((c) => c.id),
),
);

const deploymentsInConfigFiles = modifiedParsedConfigs
.map((d) => d.deployments)
.flat();

const removedDeployments = existingDeployments.filter(
(ed) =>
!deploymentsInConfigFiles.some(
(dc) =>
dc.slug === ed.deployment.slug &&
dc.system === ed.system.slug &&
dc.workspace === ed.workspace.slug,
),
);

if (removedDeployments.length > 0)
await db.delete(deployment).where(
inArray(
deployment.id,
removedDeployments.map((d) => d.deployment.id),
),
);

const newDeployments = modifiedParsedConfigs
.map((cf) =>
cf.deployments.map((d) => ({
...d,
cf: {
path: cf.path,
repositoryName: cf.repositoryName,
},
})),
)
.flat()
.filter(
(d) =>
!existingDeployments.some(
(ed) =>
ed.deployment.slug === d.slug &&
ed.system.slug === d.system &&
ed.workspace.slug === d.workspace,
),
);

if (newDeployments.length === 0) return;

const newDeploymentInfo = await db
.select()
.from(system)
.innerJoin(workspace, eq(system.workspaceId, workspace.id))
.where(
and(
inArray(
system.slug,
newDeployments.map((d) => d.system),
),
inArray(
workspace.slug,
newDeployments.map((d) => d.workspace),
),
),
);

const newDeploymentsInsert = newDeployments.map((d) => {
const info = newDeploymentInfo.find(
(i) => i.system.slug === d.system && i.workspace.slug === d.workspace,
);
if (info == null) throw new Error("Deployment info not found");
const { system, workspace } = info;

return {
...d,
systemId: system.id,
workspaceId: workspace.id,
description: d.description ?? "",
githubConfigFileId: existingConfigs.find(
(icf) =>
icf.path === d.cf.path && icf.repositoryName === d.cf.repositoryName,
)?.id,
};
});

await db.insert(deployment).values(newDeploymentsInsert);
};
Loading

0 comments on commit 67b610e

Please sign in to comment.