Skip to content

Commit

Permalink
add codebuild service
Browse files Browse the repository at this point in the history
  • Loading branch information
harishv7 committed Jul 29, 2024
1 parent 4d4dbef commit a46c87c
Show file tree
Hide file tree
Showing 3 changed files with 168 additions and 3 deletions.
110 changes: 110 additions & 0 deletions apps/studio/src/server/modules/aws/codebuild.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import {
BatchGetProjectsCommand,
CodeBuildClient,
CreateProjectCommand,
StartBuildCommand,
} from "@aws-sdk/client-codebuild"
import { ServiceException } from "@aws-sdk/smithy-client"

const client = new CodeBuildClient({ region: "ap-southeast-1" })

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const getProjectById = async (projectId: string): Promise<any> => {
const command = new BatchGetProjectsCommand({ names: [projectId] })

try {
const response = await client.send(command)
console.log("AWS response", JSON.stringify(response))
if (response.projects && response.projects.length > 0) {
return response.projects[0]
} else {
throw new Error(`Project with ID ${projectId} not found`)
}
} catch (error) {
if (error instanceof ServiceException) {
console.error("Service error:", error)
} else {
console.error("Unexpected error:", error)
}
throw error
}
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const startProjectById = async (projectId: string): Promise<any> => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const project = await getProjectById(projectId)

if (!project) {
throw new Error(`Project with ID ${projectId} not found`)
}

const command = new StartBuildCommand({ projectName: projectId })

try {
const response = await client.send(command)
return response
} catch (error) {
if (error instanceof ServiceException) {
console.error("Service error:", error)
} else {
console.error("Unexpected error:", error)
}
throw error
}
}

export const createCodeBuildProject = async ({
projectId,
siteId,
}: {
projectId: string
siteId: number
}): Promise<any> => {
/* TODO: Things to add
1. VPC config
2. Default service role
3. Move buildspec out
4. Setup logs
*/
const command = new CreateProjectCommand({
name: projectId,
source: {
type: "NO_SOURCE",
buildspec:
'version: 0.2\n\nphases:\n build:\n commands:\n - echo "hello"\n',
},
artifacts: {
type: "NO_ARTIFACTS",
},
environment: {
type: "LINUX_CONTAINER",
image: "aws/codebuild/amazonlinux2-x86_64-standard:5.0",
imagePullCredentialsType: "CODEBUILD",
computeType: "BUILD_GENERAL1_SMALL",
environmentVariables: [{ name: "SITE_ID", value: siteId.toString() }],
},
serviceRole: "",
logsConfig: {
cloudWatchLogs: {
status: "DISABLED",
},
s3Logs: {
status: "DISABLED",
},
},
})

try {
const response = await client.send(command)
console.log("AWS Create project res: ", JSON.stringify(response))
return response
} catch (error) {
if (error instanceof ServiceException) {
console.error("Service error:", error)
} else {
console.error("Unexpected error:", error)
}
throw error
}
}
45 changes: 42 additions & 3 deletions apps/studio/src/server/modules/page/page.router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,21 @@ import {
} from "~/schemas/page"
import { protectedProcedure, router } from "~/server/trpc"
import { safeJsonParse } from "~/utils/safeJsonParse"
import {
createCodeBuildProject,
startProjectById,
} from "../aws/codebuild.service"
import { db, ResourceType } from "../database"
import {
getFooter,
getFullPageById,
getNavBar,
} from "../resource/resource.service"
import { getSiteConfig } from "../site/site.service"
import {
getSiteConfig,
getSiteNameAndCodeBuildId,
setSiteCodeBuildId,
} from "../site/site.service"
import { addNewVersion, createDefaultPage } from "./page.service"

const ajv = new Ajv({ allErrors: true, strict: false, logger: false })
Expand Down Expand Up @@ -143,12 +151,43 @@ export const pageRouter = router({
),
publishPage: protectedProcedure
.input(publishPageSchema)
.mutation(async ({ input: { siteId, pageId } }) => {
.mutation(async ({ ctx, input: { siteId, pageId } }) => {
/* Step 1: Update DB table to latest state */
// Create a new version
const addedVersionResult = await addNewVersion(siteId, pageId)
return addedVersionResult

/* TODO: Step 2: Use AWS SDK to start a CodeBuild */
const site = await getSiteNameAndCodeBuildId(siteId)
let codeBuildId = site.codeBuildId
if (!codeBuildId) {
// create a codebuild project
const projectName = site.shortName || site.name
const formattedProjectName = projectName
.toLowerCase()
.split(" ")
.join("-")
const projectId = `${formattedProjectName}-${siteId}`

try {
await createCodeBuildProject({
projectId,
siteId,
})
} catch (e) {
ctx.logger.error("CodeBuild project creation failure", {
userId: ctx.user.id,
siteId,
})
}

// update site to the newly created codebuild project id
await setSiteCodeBuildId(siteId, projectId)
codeBuildId = projectId
}

// initiate new build
await startProjectById(codeBuildId)

return addedVersionResult
}),
})
16 changes: 16 additions & 0 deletions apps/studio/src/server/modules/site/site.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,22 @@ export const getSiteConfig = async (siteId: number) => {
return config
}

export const getSiteNameAndCodeBuildId = async (siteId: number) => {
return await db
.selectFrom("Site")
.where("id", "=", siteId)
.select(["Site.codeBuildId", "Site.name", "Site.shortName"])
.executeTakeFirstOrThrow()
}

export const setSiteCodeBuildId = async (siteId: number, projectId: string) => {
return await db
.updateTable("Site")
.set({ codeBuildId: projectId })
.where("id", "=", siteId)
.executeTakeFirstOrThrow()
}

// Note: This overwrites the full site config
// TODO: Should triger immediate re-publish of site
export const setSiteConfig = async (
Expand Down

0 comments on commit a46c87c

Please sign in to comment.