mirror of
https://github.com/codeflash-ai/codeflash-internal.git
synced 2026-05-04 18:25:18 +00:00
193 lines
5.8 KiB
TypeScript
193 lines
5.8 KiB
TypeScript
import dotenv from "dotenv"
|
|
import { createNodeMiddleware } from "octokit"
|
|
import express from "express"
|
|
import suggester from "code-suggester"
|
|
import { type FileDiffContent } from "code-suggester/build/src/types"
|
|
|
|
import { determineValidHunks, objectToMap } from "./utils"
|
|
import { createPullRequestFromDiffContents } from "./create-pr-from-diffcontents"
|
|
import { githubApp, webhookApiPath } from "./github-app"
|
|
import { userNickname } from "./auth0-mgmt"
|
|
|
|
import functions from "@codeflash-ai/common/token-functions"
|
|
import * as console from "console"
|
|
|
|
const userForAPIKey = functions.userForAPIKey
|
|
|
|
if (process.env.NODE_ENV !== "production") {
|
|
console.log("Using .env.local file to supply config environment variables")
|
|
dotenv.config({ path: ".env.local" })
|
|
}
|
|
|
|
const port = process.env.PORT || 3001
|
|
|
|
const appExpress = express()
|
|
|
|
appExpress.use((req, res, next) => {
|
|
console.log(`<<< Received ${req.method} request for ${req.url}`)
|
|
console.log(`<<< Request headers: ${JSON.stringify(req.headers)}`)
|
|
console.log(`<<< Request body: ${JSON.stringify(req.body)}`)
|
|
console.log(`<<< Request params: ${JSON.stringify(req.params)}`)
|
|
console.log(`<<< Request query: ${JSON.stringify(req.query)}`)
|
|
next()
|
|
})
|
|
|
|
// Mount the github webhook middleware onto the express application
|
|
appExpress.use(createNodeMiddleware(githubApp.webhooks, { path: webhookApiPath }))
|
|
|
|
appExpress.use(express.json())
|
|
|
|
appExpress.get("/", async (req, res) => {
|
|
return res.status(200).send("OK")
|
|
})
|
|
|
|
appExpress.get("/healthcheck", async (req, res) => {
|
|
return res.status(200).send("OK")
|
|
})
|
|
|
|
// Middleware to check for valid API key
|
|
appExpress.use(async (req, res, next) => {
|
|
const authHeader = req.headers.authorization
|
|
if (!authHeader) {
|
|
return res.status(401).send("Authorization header is missing")
|
|
}
|
|
|
|
const apiKey = authHeader.replace(/^Bearer\s+/, "")
|
|
const userId = await userForAPIKey(apiKey)
|
|
if (userId == null) {
|
|
console.log(`Userid null for API key ${apiKey}. Returning 403`)
|
|
return res.status(403).send("Invalid API key")
|
|
}
|
|
req.userId = userId
|
|
|
|
next()
|
|
})
|
|
|
|
appExpress.post("/cfapi/suggest-pr-changes", async (req, res) => {
|
|
try {
|
|
const { owner, repo, pullNumber, diffContents, prComment } = req.body
|
|
const userId = req.userId
|
|
|
|
if (!repo || !owner || !pullNumber) {
|
|
return res.status(400).send("Missing required fields")
|
|
}
|
|
|
|
const nickname = await userNickname(userId)
|
|
if (!nickname) {
|
|
return res.status(401).send("Unauthorized") // Error getting user nickname
|
|
}
|
|
|
|
const repoInstallation = await githubApp.octokit.rest.apps.getRepoInstallation({
|
|
owner,
|
|
repo,
|
|
})
|
|
const installationId = repoInstallation.data.id
|
|
const installationOctokit = await githubApp.getInstallationOctokit(installationId)
|
|
|
|
try {
|
|
// Check if the user is a collaborator on the repository
|
|
const response = await installationOctokit.rest.repos.checkCollaborator({
|
|
owner,
|
|
repo,
|
|
username: nickname,
|
|
})
|
|
// If the request is successful, the user is a collaborator and we can continue
|
|
if (response.status == 204) {
|
|
console.log(`${nickname} is a collaborator on ${owner}/${repo}`)
|
|
}
|
|
} catch (error) {
|
|
if (error.status === 404) {
|
|
return res.status(401).send("Unauthorized") // User is not a collaborator
|
|
}
|
|
// Handle other potential errors
|
|
return res.status(500).send(`Error`) // Error checking collaborator status
|
|
}
|
|
|
|
// Suggest changes
|
|
|
|
const diffContentsMap: Map<string, FileDiffContent> = objectToMap(diffContents)
|
|
|
|
const { validHunks, invalidHunks } = await determineValidHunks(
|
|
installationOctokit.rest,
|
|
{ owner, repo },
|
|
pullNumber,
|
|
100,
|
|
diffContentsMap,
|
|
)
|
|
|
|
if (invalidHunks.size > 0) {
|
|
// we can't suggest all of the hunks for this PR, because some of them are invalid (out of scope for this PR).
|
|
// so instead, let's make a new branch, commit the changes,
|
|
// and make a new PR from that branch onto the PR's branch
|
|
|
|
const newPrData = await createPullRequestFromDiffContents(
|
|
installationOctokit,
|
|
owner,
|
|
repo,
|
|
pullNumber,
|
|
diffContentsMap,
|
|
)
|
|
|
|
// Add explanation comment
|
|
const result = await installationOctokit.rest.issues.createComment({
|
|
owner,
|
|
repo,
|
|
issue_number: newPrData.data.number,
|
|
body: prComment,
|
|
})
|
|
|
|
// Respond with the new PR details
|
|
res.json(newPrData.data.number)
|
|
} else {
|
|
// all suggestions are valid and can be made on this PR.
|
|
// let's make the suggestions
|
|
|
|
const reviewNumber = await suggester.reviewPullRequest(
|
|
installationOctokit.rest,
|
|
diffContentsMap,
|
|
{
|
|
repo,
|
|
owner,
|
|
pullNumber,
|
|
pageSize: 100,
|
|
},
|
|
)
|
|
|
|
// Add explanation comment
|
|
const result = await installationOctokit.rest.issues.createComment({
|
|
owner,
|
|
repo,
|
|
issue_number: pullNumber,
|
|
body: prComment,
|
|
})
|
|
res.json(reviewNumber)
|
|
}
|
|
} catch (error) {
|
|
res.status(500).send(`Error creating pull request: ${error.message}`)
|
|
}
|
|
})
|
|
|
|
// WORKS without express.json() vvvvv
|
|
// const router = express.Router();
|
|
// // router.use(express.json());
|
|
// router.use(createNodeMiddleware(ghApp.webhooks, { path: "/api/github/webhooks" }));
|
|
//
|
|
// const app = express();
|
|
// app.use('/', router);
|
|
//
|
|
// app.listen(port)
|
|
|
|
// also works vvvvv
|
|
// const server = http.createServer(createNodeMiddleware(ghApp.webhooks));
|
|
// server.listen()
|
|
// \/\/\/\/\//\/\
|
|
|
|
// const server = http.createServer(appExpress.);
|
|
|
|
// Start the server
|
|
appExpress.listen(port, () => {
|
|
console.log(
|
|
`Server is listening on ${port} for CF API requests. Github App webhook events mounted at ${webhookApiPath}`,
|
|
)
|
|
console.log("Press Ctrl + C to quit.")
|
|
})
|