151 lines
4.7 KiB
TypeScript
151 lines
4.7 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 {PrismaClient} from '@prisma/client'
|
|
|
|
const port = process.env.PORT || 3001
|
|
|
|
const prisma = new PrismaClient()
|
|
|
|
async function validateApiKey(apiKey: string): Promise<boolean> {
|
|
const apiKeyRecord = await prisma.cf_api_keys.findUnique({
|
|
where: {
|
|
key: apiKey,
|
|
},
|
|
});
|
|
return apiKeyRecord !== null;
|
|
}
|
|
|
|
|
|
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 validateApiKey(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.');
|
|
});
|
|
|