codeflash-internal/js/cf-api/index.ts
2023-12-03 18:25:37 -08:00

141 lines
4.5 KiB
TypeScript

import {createNodeMiddleware} from '@octokit/webhooks';
import express from 'express';
import suggester from "code-suggester";
import {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 functions from "../common/token-functions";
const apiKeyExists = functions.apiKeyExists;
const port = process.env.PORT || 3001
const appExpress = express();
// Mount the github webhook middleware onto the express application
appExpress.use(createNodeMiddleware(githubApp.webhooks, {path: webhookApiPath}));
appExpress.use(express.json());
// 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 isValidApiKey = await apiKeyExists(apiKey);
if (!isValidApiKey) {
return res.status(403).send('Invalid API key');
}
next();
});
appExpress.post('/api/suggest-pr-changes', async (req, res) => {
try {
const {owner, repo, pullNumber, diffContents, prComment} = req.body;
if (!repo || !owner || !pullNumber) {
return res.status(400).send('Missing required fields');
}
const repoInstallation = await githubApp.octokit.rest.apps.getRepoInstallation({
owner: owner,
repo: repo
})
const installationId = repoInstallation.data.id
const installationOctokit = await githubApp.getInstallationOctokit(installationId)
const diffContentsMap: Map<string, FileDiffContent> = objectToMap(diffContents);
// Suggest changes
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: owner,
repo: 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: owner,
repo: 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.');
});