model param and make file

This commit is contained in:
sadath-12 2023-07-16 09:48:36 +05:30
parent 93a0591d83
commit 67d43e592a
3 changed files with 181 additions and 168 deletions

119
dist/index.js vendored
View file

@ -16613,8 +16613,8 @@ const openai_1 = __nccwpck_require__(8538);
const rest_1 = __nccwpck_require__(7461); const rest_1 = __nccwpck_require__(7461);
const parse_diff_1 = __importDefault(__nccwpck_require__(851)); const parse_diff_1 = __importDefault(__nccwpck_require__(851));
const minimatch_1 = __importDefault(__nccwpck_require__(332)); const minimatch_1 = __importDefault(__nccwpck_require__(332));
const GITHUB_TOKEN = core.getInput("GITHUB_TOKEN"); const GITHUB_TOKEN = core.getInput('GITHUB_TOKEN');
const OPENAI_API_KEY = core.getInput("OPENAI_API_KEY"); const OPENAI_API_KEY = core.getInput('OPENAI_API_KEY');
const OPENAI_MODEL = core.getInput('OPENAI_MODEL'); const OPENAI_MODEL = core.getInput('OPENAI_MODEL');
const octokit = new rest_1.Octokit({ auth: GITHUB_TOKEN }); const octokit = new rest_1.Octokit({ auth: GITHUB_TOKEN });
const configuration = new openai_1.Configuration({ const configuration = new openai_1.Configuration({
@ -16624,7 +16624,7 @@ const openai = new openai_1.OpenAIApi(configuration);
function getPRDetails() { function getPRDetails() {
var _a, _b; var _a, _b;
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
const { repository, number } = JSON.parse((0, fs_1.readFileSync)(process.env.GITHUB_EVENT_PATH || "", "utf8")); const { repository, number } = JSON.parse((0, fs_1.readFileSync)(process.env.GITHUB_EVENT_PATH || '', 'utf8'));
const prResponse = yield octokit.pulls.get({ const prResponse = yield octokit.pulls.get({
owner: repository.owner.login, owner: repository.owner.login,
repo: repository.name, repo: repository.name,
@ -16634,8 +16634,8 @@ function getPRDetails() {
owner: repository.owner.login, owner: repository.owner.login,
repo: repository.name, repo: repository.name,
pull_number: number, pull_number: number,
title: (_a = prResponse.data.title) !== null && _a !== void 0 ? _a : "", title: (_a = prResponse.data.title) !== null && _a !== void 0 ? _a : '',
description: (_b = prResponse.data.body) !== null && _b !== void 0 ? _b : "", description: (_b = prResponse.data.body) !== null && _b !== void 0 ? _b : '',
}; };
}); });
} }
@ -16645,7 +16645,7 @@ function getDiff(owner, repo, pull_number) {
owner, owner,
repo, repo,
pull_number, pull_number,
mediaType: { format: "diff" }, mediaType: { format: 'diff' },
}); });
// @ts-expect-error - response.data is a string // @ts-expect-error - response.data is a string
return response.data; return response.data;
@ -16655,7 +16655,7 @@ function analyzeCode(parsedDiff, prDetails) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
const comments = []; const comments = [];
for (const file of parsedDiff) { for (const file of parsedDiff) {
if (file.to === "/dev/null") if (file.to === '/dev/null')
continue; // Ignore deleted files continue; // Ignore deleted files
for (const chunk of file.chunks) { for (const chunk of file.chunks) {
const prompt = createPrompt(file, chunk, prDetails); const prompt = createPrompt(file, chunk, prDetails);
@ -16692,7 +16692,7 @@ function createPrompt(file, chunk, prDetails) {
- Write the comment in GitHub Markdown format. - Write the comment in GitHub Markdown format.
- Use the given description only for the overall context and only comment the code. - Use the given description only for the overall context and only comment the code.
- IMPORTANT: NEVER suggest adding comments to the code. - IMPORTANT: NEVER suggest adding comments to the code.
- If you don't have anything to say just say I dont have anything to say - If you don't have anything to say just say I don't have anything to say
Review the following code diff in the file "${file.to}" and take the pull request title and description into account when writing the response. Review the following code diff in the file "${file.to}" and take the pull request title and description into account when writing the response.
Pull request title: ${prDetails.title} Pull request title: ${prDetails.title}
@ -16709,7 +16709,7 @@ ${chunk.content}
${chunk.changes ${chunk.changes
// @ts-expect-error - ln and ln2 exists where needed // @ts-expect-error - ln and ln2 exists where needed
.map((c) => `${c.ln ? c.ln : c.ln2} ${c.content}`) .map((c) => `${c.ln ? c.ln : c.ln2} ${c.content}`)
.join("\n")} .join('\n')}
\`\`\` \`\`\`
`; `;
} }
@ -16727,15 +16727,15 @@ function getAIResponse(prompt) {
try { try {
const response = yield openai.createChatCompletion(Object.assign(Object.assign({}, queryConfig), { messages: [ const response = yield openai.createChatCompletion(Object.assign(Object.assign({}, queryConfig), { messages: [
{ {
role: "system", role: 'system',
content: prompt, content: prompt,
}, },
] })); ] }));
const res = ((_b = (_a = response.data.choices[0].message) === null || _a === void 0 ? void 0 : _a.content) === null || _b === void 0 ? void 0 : _b.trim()) || "nothing can be said"; const res = ((_b = (_a = response.data.choices[0].message) === null || _a === void 0 ? void 0 : _a.content) === null || _b === void 0 ? void 0 : _b.trim()) || 'nothing can be said';
return JSON.parse(res); return JSON.parse(res);
} }
catch (error) { catch (error) {
console.error("Error:", error); console.error('Error:', error);
return null; return null;
} }
}); });
@ -16759,60 +16759,69 @@ function createReviewComment(owner, repo, pull_number, comments) {
repo, repo,
pull_number, pull_number,
comments, comments,
event: "COMMENT", event: 'COMMENT',
}); });
}); });
} }
function main() { function main() {
var _a; var _a;
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
const prDetails = yield getPRDetails(); try {
let diff; const prDetails = yield getPRDetails();
const eventData = JSON.parse((0, fs_1.readFileSync)((_a = process.env.GITHUB_EVENT_PATH) !== null && _a !== void 0 ? _a : "", "utf8")); let diff;
if (eventData.action === "opened") { const eventData = JSON.parse((0, fs_1.readFileSync)((_a = process.env.GITHUB_EVENT_PATH) !== null && _a !== void 0 ? _a : '', 'utf8'));
diff = yield getDiff(prDetails.owner, prDetails.repo, prDetails.pull_number); if (eventData.action === 'opened') {
} diff = yield getDiff(prDetails.owner, prDetails.repo, prDetails.pull_number);
else if (eventData.action === "synchronize") { console.log('Diff retrieved for opened event.');
const newBaseSha = eventData.before; }
const newHeadSha = eventData.after; else if (eventData.action === 'synchronize') {
const response = yield octokit.repos.compareCommits({ const newBaseSha = eventData.before;
owner: prDetails.owner, const newHeadSha = eventData.after;
repo: prDetails.repo, const response = yield octokit.repos.compareCommits({
base: newBaseSha, owner: prDetails.owner,
head: newHeadSha, repo: prDetails.repo,
base: newBaseSha,
head: newHeadSha,
});
diff = response.data.diff_url
? yield octokit
.request({ url: response.data.diff_url })
.then((res) => res.data)
: null;
console.log('Diff retrieved for synchronize event.');
}
else {
console.log('Unsupported event:', process.env.GITHUB_EVENT_NAME);
return;
}
if (!diff) {
console.log('No diff found');
return;
}
const parsedDiff = (0, parse_diff_1.default)(diff);
const excludePatterns = core
.getInput('exclude')
.split(',')
.map((s) => s.trim());
const filteredDiff = parsedDiff.filter((file) => {
return !excludePatterns.some((pattern) => { var _a; return (0, minimatch_1.default)((_a = file.to) !== null && _a !== void 0 ? _a : '', pattern); });
}); });
diff = response.data.diff_url const comments = yield analyzeCode(filteredDiff, prDetails);
? yield octokit if (comments.length > 0) {
.request({ url: response.data.diff_url }) yield createReviewComment(prDetails.owner, prDetails.repo, prDetails.pull_number, comments);
.then((res) => res.data) console.log(`Review comment created with ${comments.length} comment(s).`);
: null; }
else {
console.log('No comments to create.');
}
} }
else { catch (error) {
console.log("Unsupported event:", process.env.GITHUB_EVENT_NAME); console.error('Error:', error);
return; process.exit(1);
}
if (!diff) {
console.log("No diff found");
return;
}
const parsedDiff = (0, parse_diff_1.default)(diff);
const excludePatterns = core
.getInput("exclude")
.split(",")
.map((s) => s.trim());
const filteredDiff = parsedDiff.filter((file) => {
return !excludePatterns.some((pattern) => { var _a; return (0, minimatch_1.default)((_a = file.to) !== null && _a !== void 0 ? _a : "", pattern); });
});
const comments = yield analyzeCode(filteredDiff, prDetails);
if (comments.length > 0) {
yield createReviewComment(prDetails.owner, prDetails.repo, prDetails.pull_number, comments);
} }
}); });
} }
main().catch((error) => { main();
console.error("Error:", error);
process.exit(1);
});
/***/ }), /***/ }),

2
dist/index.js.map vendored

File diff suppressed because one or more lines are too long

View file

@ -1,46 +1,46 @@
import { readFileSync } from "fs"; import { readFileSync } from 'fs'
import * as core from "@actions/core"; import * as core from '@actions/core'
import { Configuration, OpenAIApi } from "openai"; import { Configuration, OpenAIApi } from 'openai'
import { Octokit } from "@octokit/rest"; import { Octokit } from '@octokit/rest'
import parseDiff, { Chunk, File } from "parse-diff"; import parseDiff, { Chunk, File } from 'parse-diff'
import minimatch from "minimatch"; import minimatch from 'minimatch'
const GITHUB_TOKEN: string = core.getInput("GITHUB_TOKEN"); const GITHUB_TOKEN: string = core.getInput('GITHUB_TOKEN')
const OPENAI_API_KEY: string = core.getInput("OPENAI_API_KEY"); const OPENAI_API_KEY: string = core.getInput('OPENAI_API_KEY')
const OPENAI_MODEL: string = core.getInput('OPENAI_MODEL') const OPENAI_MODEL: string = core.getInput('OPENAI_MODEL')
const octokit = new Octokit({ auth: GITHUB_TOKEN }); const octokit = new Octokit({ auth: GITHUB_TOKEN })
const configuration = new Configuration({ const configuration = new Configuration({
apiKey: OPENAI_API_KEY, apiKey: OPENAI_API_KEY,
}); })
const openai = new OpenAIApi(configuration); const openai = new OpenAIApi(configuration)
interface PRDetails { interface PRDetails {
owner: string; owner: string
repo: string; repo: string
pull_number: number; pull_number: number
title: string; title: string
description: string; description: string
} }
async function getPRDetails(): Promise<PRDetails> { async function getPRDetails(): Promise<PRDetails> {
const { repository, number } = JSON.parse( const { repository, number } = JSON.parse(
readFileSync(process.env.GITHUB_EVENT_PATH || "", "utf8") readFileSync(process.env.GITHUB_EVENT_PATH || '', 'utf8')
); )
const prResponse = await octokit.pulls.get({ const prResponse = await octokit.pulls.get({
owner: repository.owner.login, owner: repository.owner.login,
repo: repository.name, repo: repository.name,
pull_number: number, pull_number: number,
}); })
return { return {
owner: repository.owner.login, owner: repository.owner.login,
repo: repository.name, repo: repository.name,
pull_number: number, pull_number: number,
title: prResponse.data.title ?? "", title: prResponse.data.title ?? '',
description: prResponse.data.body ?? "", description: prResponse.data.body ?? '',
}; }
} }
async function getDiff( async function getDiff(
@ -52,32 +52,32 @@ async function getDiff(
owner, owner,
repo, repo,
pull_number, pull_number,
mediaType: { format: "diff" }, mediaType: { format: 'diff' },
}); })
// @ts-expect-error - response.data is a string // @ts-expect-error - response.data is a string
return response.data; return response.data
} }
async function analyzeCode( async function analyzeCode(
parsedDiff: File[], parsedDiff: File[],
prDetails: PRDetails prDetails: PRDetails
): Promise<Array<{ body: string; path: string; line: number }>> { ): Promise<Array<{ body: string; path: string; line: number }>> {
const comments: Array<{ body: string; path: string; line: number }> = []; const comments: Array<{ body: string; path: string; line: number }> = []
for (const file of parsedDiff) { for (const file of parsedDiff) {
if (file.to === "/dev/null") continue; // Ignore deleted files if (file.to === '/dev/null') continue // Ignore deleted files
for (const chunk of file.chunks) { for (const chunk of file.chunks) {
const prompt = createPrompt(file, chunk, prDetails); const prompt = createPrompt(file, chunk, prDetails)
const aiResponse = await getAIResponse(prompt); const aiResponse = await getAIResponse(prompt)
if (aiResponse) { if (aiResponse) {
const newComments = createComment(file, chunk, aiResponse); const newComments = createComment(file, chunk, aiResponse)
if (newComments) { if (newComments) {
comments.push(...newComments); comments.push(...newComments)
} }
} }
} }
} }
return comments; return comments
} }
async function getBaseAndHeadShas( async function getBaseAndHeadShas(
@ -89,11 +89,11 @@ async function getBaseAndHeadShas(
owner, owner,
repo, repo,
pull_number, pull_number,
}); })
return { return {
baseSha: prResponse.data.base.sha, baseSha: prResponse.data.base.sha,
headSha: prResponse.data.head.sha, headSha: prResponse.data.head.sha,
}; }
} }
function createPrompt(file: File, chunk: Chunk, prDetails: PRDetails): string { function createPrompt(file: File, chunk: Chunk, prDetails: PRDetails): string {
@ -104,7 +104,7 @@ function createPrompt(file: File, chunk: Chunk, prDetails: PRDetails): string {
- Write the comment in GitHub Markdown format. - Write the comment in GitHub Markdown format.
- Use the given description only for the overall context and only comment the code. - Use the given description only for the overall context and only comment the code.
- IMPORTANT: NEVER suggest adding comments to the code. - IMPORTANT: NEVER suggest adding comments to the code.
- If you don't have anything to say just say I dont have anything to say - If you don't have anything to say just say I don't have anything to say
Review the following code diff in the file "${ Review the following code diff in the file "${
file.to file.to
}" and take the pull request title and description into account when writing the response. }" and take the pull request title and description into account when writing the response.
@ -123,15 +123,14 @@ ${chunk.content}
${chunk.changes ${chunk.changes
// @ts-expect-error - ln and ln2 exists where needed // @ts-expect-error - ln and ln2 exists where needed
.map((c) => `${c.ln ? c.ln : c.ln2} ${c.content}`) .map((c) => `${c.ln ? c.ln : c.ln2} ${c.content}`)
.join("\n")} .join('\n')}
\`\`\` \`\`\`
`; `
} }
async function getAIResponse(prompt: string): Promise<Array<{ async function getAIResponse(
lineNumber: string; prompt: string
reviewComment: string; ): Promise<Array<{ lineNumber: string; reviewComment: string }> | null> {
}> | null> {
const queryConfig = { const queryConfig = {
model: OPENAI_MODEL, model: OPENAI_MODEL,
temperature: 0.2, temperature: 0.2,
@ -139,45 +138,43 @@ async function getAIResponse(prompt: string): Promise<Array<{
top_p: 1, top_p: 1,
frequency_penalty: 0, frequency_penalty: 0,
presence_penalty: 0, presence_penalty: 0,
}; }
try { try {
const response = await openai.createChatCompletion({ const response = await openai.createChatCompletion({
...queryConfig, ...queryConfig,
messages: [ messages: [
{ {
role: "system", role: 'system',
content: prompt, content: prompt,
}, },
], ],
}); })
const res = response.data.choices[0].message?.content?.trim() || "nothing can be said"; const res =
return JSON.parse(res); response.data.choices[0].message?.content?.trim() || 'nothing can be said'
return JSON.parse(res)
} catch (error) { } catch (error) {
console.error("Error:", error); console.error('Error:', error)
return null; return null
} }
} }
function createComment( function createComment(
file: File, file: File,
chunk: Chunk, chunk: Chunk,
aiResponses: Array<{ aiResponses: Array<{ lineNumber: string; reviewComment: string }>
lineNumber: string;
reviewComment: string;
}>
): Array<{ body: string; path: string; line: number }> { ): Array<{ body: string; path: string; line: number }> {
return aiResponses.flatMap((aiResponse) => { return aiResponses.flatMap((aiResponse) => {
if (!file.to) { if (!file.to) {
return [] return []
} }
return { return {
body: aiResponse.reviewComment, body: aiResponse.reviewComment,
path: file.to, path: file.to,
line: Number(aiResponse.lineNumber), line: Number(aiResponse.lineNumber),
}; }
}); })
} }
async function createReviewComment( async function createReviewComment(
@ -191,74 +188,81 @@ async function createReviewComment(
repo, repo,
pull_number, pull_number,
comments, comments,
event: "COMMENT", event: 'COMMENT',
}); })
} }
async function main() { async function main() {
const prDetails = await getPRDetails(); try {
let diff: string | null; const prDetails = await getPRDetails()
const eventData = JSON.parse( let diff: string | null
readFileSync(process.env.GITHUB_EVENT_PATH ?? "", "utf8") const eventData = JSON.parse(
); readFileSync(process.env.GITHUB_EVENT_PATH ?? '', 'utf8')
)
if (eventData.action === "opened") { if (eventData.action === 'opened') {
diff = await getDiff( diff = await getDiff(
prDetails.owner, prDetails.owner,
prDetails.repo, prDetails.repo,
prDetails.pull_number prDetails.pull_number
); )
} else if (eventData.action === "synchronize") { console.log('Diff retrieved for opened event.')
const newBaseSha = eventData.before; } else if (eventData.action === 'synchronize') {
const newHeadSha = eventData.after; const newBaseSha = eventData.before
const newHeadSha = eventData.after
const response = await octokit.repos.compareCommits({ const response = await octokit.repos.compareCommits({
owner: prDetails.owner, owner: prDetails.owner,
repo: prDetails.repo, repo: prDetails.repo,
base: newBaseSha, base: newBaseSha,
head: newHeadSha, head: newHeadSha,
}); })
diff = response.data.diff_url diff = response.data.diff_url
? await octokit ? await octokit
.request({ url: response.data.diff_url }) .request({ url: response.data.diff_url })
.then((res) => res.data) .then((res) => res.data)
: null; : null
} else { console.log('Diff retrieved for synchronize event.')
console.log("Unsupported event:", process.env.GITHUB_EVENT_NAME); } else {
return; console.log('Unsupported event:', process.env.GITHUB_EVENT_NAME)
} return
}
// if (!diff) { if (!diff) {
// console.log("No diff found"); console.log('No diff found')
// return; return
// } }
const parsedDiff = parseDiff(diff); const parsedDiff = parseDiff(diff)
const excludePatterns = core const excludePatterns = core
.getInput("exclude") .getInput('exclude')
.split(",") .split(',')
.map((s) => s.trim()); .map((s) => s.trim())
const filteredDiff = parsedDiff.filter((file) => { const filteredDiff = parsedDiff.filter((file) => {
return !excludePatterns.some((pattern) => return !excludePatterns.some((pattern) =>
minimatch(file.to ?? "", pattern) minimatch(file.to ?? '', pattern)
); )
}); })
const comments = await analyzeCode(filteredDiff, prDetails); const comments = await analyzeCode(filteredDiff, prDetails)
if (comments.length > 0) { if (comments.length > 0) {
await createReviewComment( await createReviewComment(
prDetails.owner, prDetails.owner,
prDetails.repo, prDetails.repo,
prDetails.pull_number, prDetails.pull_number,
comments comments
); )
console.log(`Review comment created with ${comments.length} comment(s).`)
} else {
console.log('No comments to create.')
}
} catch (error) {
console.error('Error:', error)
process.exit(1)
} }
} }
main().catch((error) => { main()
console.error("Error:", error);
process.exit(1);
});