From dd84cb8d1aa70791d192903db74268f370744d10 Mon Sep 17 00:00:00 2001 From: anc95 <1481988258@qq.com> Date: Sun, 16 Mar 2025 13:58:54 +0800 Subject: [PATCH 1/5] feat: add lgtm --- src/bot.ts | 6 +++--- src/chat.ts | 40 +++++++++++++++++++++++++++++++--------- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/bot.ts b/src/bot.ts index dc142eec..89f55c11 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -156,10 +156,10 @@ export const robot = (app: Probot) => { } try { const res = await chat?.codeReview(patch); - if (!!res) { + if (!res.lgtm && !!res.review_comment) { ress.push({ path: file.filename, - body: res, + body: res.review_comment, position: patch.split('\n').length - 1, }) } @@ -172,7 +172,7 @@ export const robot = (app: Probot) => { repo: repo.repo, owner: repo.owner, pull_number: context.pullRequest().pull_number, - body: "Code review by ChatGPT", + body: ress.length ? "Code review by ChatGPT" : "LGTM 👍", event: 'COMMENT', commit_id: commits[commits.length - 1].sha, comments: ress, diff --git a/src/chat.ts b/src/chat.ts index b6a547b2..bb82e536 100644 --- a/src/chat.ts +++ b/src/chat.ts @@ -31,18 +31,26 @@ export class Chat { ? `Answer me in ${process.env.LANGUAGE},` : ''; - const prompt = - process.env.PROMPT || - 'Below is a code patch, please help me do a brief code review on it. Any bug risks and/or improvement suggestions are welcome:'; + const userPrompt = process.env.PROMPT || 'Please review the following code patch. Focus on potential bugs, risks, and improvement suggestions.'; + + const jsonFormatRequirement = '\nProvide your feedback in a strict JSON format with the following structure:\n' + + '{\n' + + ' "lgtm": boolean, // true if the code looks good to merge, false if there are concerns\n' + + ' "review_comment": string // Your detailed review comments. You can use markdown syntax in this string, but the overall response must be a valid JSON\n' + + '}\n' + + 'Ensure your response is a valid JSON object.\n'; - return `${prompt}, ${answerLanguage}: - ${patch} + return `${userPrompt}${jsonFormatRequirement} ${answerLanguage}: + ${patch} `; }; - public codeReview = async (patch: string) => { + public codeReview = async (patch: string): Promise<{ lgtm: boolean, review_comment: string }> => { if (!patch) { - return ''; + return { + lgtm: true, + review_comment: "" + }; } console.time('code-review cost'); @@ -59,14 +67,28 @@ export class Chat { temperature: +(process.env.temperature || 0) || 1, top_p: +(process.env.top_p || 0) || 1, max_tokens: process.env.max_tokens ? +process.env.max_tokens : undefined, + response_format: { + type: "json_object" + }, }); console.timeEnd('code-review cost'); if (res.choices.length) { - return res.choices[0].message.content; + try { + const json = JSON.parse(res.choices[0].message.content || ""); + return json + } catch (e) { + return { + lgtm: false, + review_comment: res.choices[0].message.content || "" + } + } } - return ''; + return { + lgtm: true, + review_comment: "" + } }; } From 9cb205e9abc009fc671b0c88b6611ccb9cf5430b Mon Sep 17 00:00:00 2001 From: anc95 <1481988258@qq.com> Date: Sun, 16 Mar 2025 14:05:51 +0800 Subject: [PATCH 2/5] chore: add lo --- src/bot.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bot.ts b/src/bot.ts index 89f55c11..a557761b 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -110,6 +110,7 @@ export const robot = (app: Probot) => { log.debug('ignoreList:', ignoreList); log.debug('ignorePatterns:', ignorePatterns); + log.debug('includePatterns:', includePatterns); changedFiles = changedFiles?.filter( (file) => { From 1f8b4c2ffe5093d81058600b5527b71cab662dfd Mon Sep 17 00:00:00 2001 From: anc95 <1481988258@qq.com> Date: Sun, 16 Mar 2025 14:08:22 +0800 Subject: [PATCH 3/5] build --- action/index.cjs | 44 ++++++++++++++++++++++++++++++++++---------- action/src/chat.d.ts | 5 ++++- 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/action/index.cjs b/action/index.cjs index a37bbd11..ab009179 100644 --- a/action/index.cjs +++ b/action/index.cjs @@ -150469,6 +150469,7 @@ const robot = (app) => { const includePatterns = (process.env.INCLUDE_PATTERNS || '').split(',').filter((v) => Boolean(v.trim())); loglevel_1.default.debug('ignoreList:', ignoreList); loglevel_1.default.debug('ignorePatterns:', ignorePatterns); + loglevel_1.default.debug('includePatterns:', includePatterns); changedFiles = changedFiles?.filter((file) => { const url = new URL(file.contents_url); // if includePatterns is not empty, only include files that match the pattern @@ -150502,10 +150503,10 @@ const robot = (app) => { } try { const res = await chat?.codeReview(patch); - if (!!res) { + if (!res.lgtm && !!res.review_comment) { ress.push({ path: file.filename, - body: res, + body: res.review_comment, position: patch.split('\n').length - 1, }); } @@ -150519,7 +150520,7 @@ const robot = (app) => { repo: repo.repo, owner: repo.owner, pull_number: context.pullRequest().pull_number, - body: "Code review by ChatGPT", + body: ress.length ? "Code review by ChatGPT" : "LGTM 👍", event: 'COMMENT', commit_id: commits[commits.length - 1].sha, comments: ress, @@ -150588,15 +150589,23 @@ class Chat { const answerLanguage = process.env.LANGUAGE ? `Answer me in ${process.env.LANGUAGE},` : ''; - const prompt = process.env.PROMPT || - 'Below is a code patch, please help me do a brief code review on it. Any bug risks and/or improvement suggestions are welcome:'; - return `${prompt}, ${answerLanguage}: - ${patch} + const userPrompt = process.env.PROMPT || 'Please review the following code patch. Focus on potential bugs, risks, and improvement suggestions.'; + const jsonFormatRequirement = '\nProvide your feedback in a strict JSON format with the following structure:\n' + + '{\n' + + ' "lgtm": boolean, // true if the code looks good to merge, false if there are concerns\n' + + ' "review_comment": string // Your detailed review comments. You can use markdown syntax in this string, but the overall response must be a valid JSON\n' + + '}\n' + + 'Ensure your response is a valid JSON object.\n'; + return `${userPrompt}${jsonFormatRequirement} ${answerLanguage}: + ${patch} `; }; codeReview = async (patch) => { if (!patch) { - return ''; + return { + lgtm: true, + review_comment: "" + }; } console.time('code-review cost'); const prompt = this.generatePrompt(patch); @@ -150611,12 +150620,27 @@ class Chat { temperature: +(process.env.temperature || 0) || 1, top_p: +(process.env.top_p || 0) || 1, max_tokens: process.env.max_tokens ? +process.env.max_tokens : undefined, + response_format: { + type: "json_object" + }, }); console.timeEnd('code-review cost'); if (res.choices.length) { - return res.choices[0].message.content; + try { + const json = JSON.parse(res.choices[0].message.content || ""); + return json; + } + catch (e) { + return { + lgtm: false, + review_comment: res.choices[0].message.content || "" + }; + } } - return ''; + return { + lgtm: true, + review_comment: "" + }; }; } exports.Chat = Chat; diff --git a/action/src/chat.d.ts b/action/src/chat.d.ts index 88fd6b1f..00c54cd9 100644 --- a/action/src/chat.d.ts +++ b/action/src/chat.d.ts @@ -3,5 +3,8 @@ export declare class Chat { private isAzure; constructor(apikey: string); private generatePrompt; - codeReview: (patch: string) => Promise; + codeReview: (patch: string) => Promise<{ + lgtm: boolean; + review_comment: string; + }>; } From 68ca958453871ab2210074b4a612a8f6ec61872e Mon Sep 17 00:00:00 2001 From: anc95 <1481988258@qq.com> Date: Sun, 16 Mar 2025 14:08:53 +0800 Subject: [PATCH 4/5] test --- src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 04c2cb6f..629a4c4c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,6 +2,6 @@ import { run } from "probot"; import log from "./log.js"; import { robot } from "./bot.js"; -log.info("Starting probot"); +log.info("Starting probot test"); run(robot) \ No newline at end of file From 574346454d15163e44aeed1c4edc7d9efa6471f6 Mon Sep 17 00:00:00 2001 From: anc95 <1481988258@qq.com> Date: Sun, 16 Mar 2025 14:14:31 +0800 Subject: [PATCH 5/5] fix: include patterns --- action/index.cjs | 5 +++-- src/bot.ts | 5 +++-- src/index.ts | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/action/index.cjs b/action/index.cjs index ab009179..896311dc 100644 --- a/action/index.cjs +++ b/action/index.cjs @@ -150472,16 +150472,17 @@ const robot = (app) => { loglevel_1.default.debug('includePatterns:', includePatterns); changedFiles = changedFiles?.filter((file) => { const url = new URL(file.contents_url); + const pathname = decodeURIComponent(url.pathname); // if includePatterns is not empty, only include files that match the pattern if (includePatterns.length) { - return matchPatterns(includePatterns, url.pathname); + return matchPatterns(includePatterns, pathname); } if (ignoreList.includes(file.filename)) { return false; } // if ignorePatterns is not empty, ignore files that match the pattern if (ignorePatterns.length) { - return !matchPatterns(ignorePatterns, url.pathname); + return !matchPatterns(ignorePatterns, pathname); } return true; }); diff --git a/src/bot.ts b/src/bot.ts index a557761b..6c1b043f 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -115,9 +115,10 @@ export const robot = (app: Probot) => { changedFiles = changedFiles?.filter( (file) => { const url = new URL(file.contents_url) + const pathname = decodeURIComponent(url.pathname) // if includePatterns is not empty, only include files that match the pattern if (includePatterns.length) { - return matchPatterns(includePatterns, url.pathname) + return matchPatterns(includePatterns, pathname) } if (ignoreList.includes(file.filename)) { @@ -126,7 +127,7 @@ export const robot = (app: Probot) => { // if ignorePatterns is not empty, ignore files that match the pattern if (ignorePatterns.length) { - return !matchPatterns(ignorePatterns, url.pathname) + return !matchPatterns(ignorePatterns, pathname) } return true diff --git a/src/index.ts b/src/index.ts index 629a4c4c..04c2cb6f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,6 +2,6 @@ import { run } from "probot"; import log from "./log.js"; import { robot } from "./bot.js"; -log.info("Starting probot test"); +log.info("Starting probot"); run(robot) \ No newline at end of file