」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > Better - 人工智慧驅動的程式碼審查器 GitHub Action

Better - 人工智慧驅動的程式碼審查器 GitHub Action

發佈於2024-11-08
瀏覽:384

代码审查对于维护标准和强调项目中代码的最佳实践始终至关重要。这不是一篇关于开发人员应该如何审查代码的文章,更多的是关于将一​​部分代码委托给 AI。

正如 Michael Lynch 在他的文章“如何像人类一样进行代码审查”中提到的那样——我们应该让计算机处理代码审查的无聊部分。虽然迈克尔强调格式化工具,但我想更进一步,让人工智能来解决这个问题。我的意思是,为什么不利用行业中人工智能的繁荣呢?

现在我并不是说应该使用人工智能来代替格式化工具和 linter。相反,它是用来捕捉人类可能错过的琐碎的东西。

这就是为什么我决定创建一个 github 操作,该操作的代码会审查拉取请求差异并使用 AI 生成建议。让我带您了解一下。

?笔记

  • 此 GitHub 操作现已在 GitHub 市场上提供。
  • 这是一个 javascript 操作 - 了解有关创建 javascript github 操作的更多信息。

获取差异

为了与 github API 交互,我使用了 octokit,它是一种 SDK 或客户端库,用于以惯用的方式与 github API 交互。

为了获得提出的拉取请求的差异,您需要传递带有值 application/vnd.github.diff 的 Accept 标头以及所需的参数。

async function getPullRequestDetails(octokit, { mode }) {
    let AcceptFormat = "application/vnd.github.raw json";

    if (mode === "diff") AcceptFormat = "application/vnd.github.diff";
    if (mode === "json") AcceptFormat = "application/vnd.github.raw json";

    return await octokit.rest.pulls.get({
        owner: github.context.repo.owner,
        repo: github.context.repo.repo,
        pull_number: github.context.payload.pull_request.number,
        headers: {
            accept: AcceptFormat,
        },
    });
}

如果您根本不熟悉 github actions,这里有 Victoria Lo 的 github actions 101 系列,这是一个很好的开始。

一旦获得差异,我就会解析它并删除不需要的更改,然后以如下所示的模式返回它:

/** using zod */
schema = z.object({
    path: z.string(),
    position: z.number(),
    line: z.number(),
    change: z.object({
        type: z.string(),
        add: z.boolean(),
        ln: z.number(),
        content: z.string(),
        relativePosition: z.number(),
    }),
    previously: z.string().optional(),
    suggestions: z.string().optional(),
})

忽略文件

忽略文件非常简单。用户输入列表需要以分号分隔的 glob 模式字符串。然后对其进行解析,与默认的忽略文件列表连接并进行重复数据删除。

**/*.md; **/*.env; **/*.lock;
const filesToIgnoreList = [
    ...new Set(
        filesToIgnore
            .split(";")
            .map(file => file.trim())
            .filter(file => file !== "")
            .concat(FILES_IGNORED_BY_DEFAULT)
    ),
];

然后使用忽略的文件列表来删除引用这些忽略的文件的差异更改。这为您提供了一个仅包含您想要的更改的原始有效负载。

生成建议

解析差异后获得原始有效负载后,我将其传递给平台 API。这是 OpenAI API 的实现。

async function useOpenAI({ rawComments, openAI, rules, modelName, pullRequestContext }) {
    const result = await openAI.beta.chat.completions.parse({
        model: getModelName(modelName, "openai"),
        messages: [
            {
                role: "system",
                content: COMMON_SYSTEM_PROMPT,
            },
            {
                role: "user",
                content: getUserPrompt(rules, rawComments, pullRequestContext),
            },
        ],
        response_format: zodResponseFormat(diffPayloadSchema, "json_diff_response"),
    });

    const { message } = result.choices[0];

    if (message.refusal) {
        throw new Error(`the model refused to generate suggestions - ${message.refusal}`);
    }

    return message.parsed;
}

您可能会注意到 API 实现中响应格式的使用。这是许多 LLM 平台提供的功能,它允许您告诉模型以特定模式/格式生成响应。在这种情况下,它特别有用,因为我不希望模型产生幻觉并为拉取请求中的错误文件或位置生成建议,或者向响应负载添加新属性。

系统提示为模型提供了更多关于如何进行代码审查以及需要记住的事项的背景信息。你可以在这里查看系统提示 github.com/murtuzaalisurti/better.

用户提示包含拉取请求的实际差异、规则和上下文。这就是代码审查的开始。

此 github 操作支持 OpenAI 和 Anthropic 模型。以下是它如何实现 Anthropic API:

async function useAnthropic({ rawComments, anthropic, rules, modelName, pullRequestContext }) {
    const { definitions } = zodToJsonSchema(diffPayloadSchema, "diffPayloadSchema");
    const result = await anthropic.messages.create({
        max_tokens: 8192,
        model: getModelName(modelName, "anthropic"),
        system: COMMON_SYSTEM_PROMPT,
        tools: [
            {
                name: "structuredOutput",
                description: "Structured Output",
                input_schema: definitions["diffPayloadSchema"],
            },
        ],
        tool_choice: {
            type: "tool",
            name: "structuredOutput",
        },
        messages: [
            {
                role: "user",
                content: getUserPrompt(rules, rawComments, pullRequestContext),
            },
        ],
    });

    let parsed = null;
    for (const block of result.content) {
        if (block.type === "tool_use") {
            parsed = block.input;
            break;
        }
    }

    return parsed;
}

添加评论

最后,在检索到建议后,我会对它们进行清理并将其传递给 github API 以添加评论作为审核的一部分。

我选择以下方式添加评论,因为通过创建新评论,您可以一次性添加所有评论,而不是一次添加一条评论。逐条添加评论也可能会触发速率限制,因为添加评论会触发通知,而您不希望向用户发送垃圾邮件通知。

function filterPositionsNotPresentInRawPayload(rawComments, comments) {
    return comments.filter(comment =>
        rawComments.some(rawComment => rawComment.path === comment.path && rawComment.line === comment.line)
    );
}

async function addReviewComments(suggestions, octokit, rawComments, modelName) {
    const { info } = log({ withTimestamp: true }); // eslint-disable-line no-use-before-define
    const comments = filterPositionsNotPresentInRawPayload(rawComments, extractComments().comments(suggestions));

    try {
        await octokit.rest.pulls.createReview({
            owner: github.context.repo.owner,
            repo: github.context.repo.repo,
            pull_number: github.context.payload.pull_request.number,
            body: `Code Review by ${modelName}`,
            event: "COMMENT",
            comments,
        });
    } catch (error) {
        info(`Failed to add review comments: ${JSON.stringify(comments, null, 2)}`);
        throw error;
    }
}

结论

我想让 github 操作保持开放性并开放集成,这就是为什么您可以使用您选择的任何模型 (请参阅支持的模型列表),或者您可以微调和构建您自己的自定义模型位于受支持的基本模型之上,并将其与此 github 操作一起使用。

如果您遇到任何代币问题或速率限制,您可能需要参考相应平台的文档来升级模型限制。

所以,你还在等什么?如果您在 github 上有存储库,请立即尝试该操作 - 它位于 github 操作市场上。

Better - An AI powered Code Reviewer GitHub Action 穆尔图扎阿利苏尔蒂 / 更好的

由 AI 提供支持的代码审阅者 github 操作,可随时在您的工作流程中使用。

更好的

由 AI 提供支持的代码审查程序 github 操作,可在您的工作流程中使用。

为什么要使用它?

  • 标准化您的代码审查流程
  • 更快地获得反馈
  • 识别导致错误代码的模式
  • 常见问题检测
  • 识别安全漏洞
  • 第二意见
  • 让人类专注于更复杂的任务

用法

1.创建工作流程

在存储库的 .github/workflows 文件夹中创建一个工作流文件(如果不存在则创建),其中包含以下内容:

name: Code Review
on
    pull_request:
        types: [opened, reopened, synchronize, ready_for_review]
        branches:
            - main # change this to your target branch
    workflow_dispatch: # Allows you to run the workflow manually from the Actions tab

permissions: # necessary permissions
    pull-requests: write
    contents: read

jobs:
    your-job-name:
        runs-on: ubuntu-latest
        name: your-job-name
        steps:
            - name: step-name
              id: step-id
              uses: murtuzaalisurti/better@v2 # this is
进入全屏模式 退出全屏模式
在 GitHub 上查看
版本聲明 本文轉載於:https://dev.to/murtuzaalisurti/better-an-ai-powered-code-reviewer-github-action-2n28?1如有侵犯,請聯絡[email protected]刪除
最新教學 更多>
  • 如何高效地在一個事務中插入數據到多個MySQL表?
    如何高效地在一個事務中插入數據到多個MySQL表?
    mySQL插入到多個表中,該數據可能會產生意外的結果。雖然似乎有多個查詢可以解決問題,但將從用戶表的自動信息ID與配置文件表的手動用戶ID相關聯提出了挑戰。 使用Transactions和last_insert_id() 插入用戶(用戶名,密碼)值('test','tes...
    程式設計 發佈於2025-05-08
  • 如何從Google API中檢索最新的jQuery庫?
    如何從Google API中檢索最新的jQuery庫?
    從Google APIS 問題中提供的jQuery URL是版本1.2.6。對於檢索最新版本,以前有一種使用特定版本編號的替代方法,它是使用以下語法:獲取最新版本:未壓縮)While these legacy URLs still remain in use, it is recommended ...
    程式設計 發佈於2025-05-08
  • 圖片在Chrome中為何仍有邊框? `border: none;`無效解決方案
    圖片在Chrome中為何仍有邊框? `border: none;`無效解決方案
    在chrome 中刪除一個頻繁的問題時,在與Chrome and IE9中的圖像一起工作時,遇到了一個頻繁的問題。和“邊境:無;”在CSS中。要解決此問題,請考慮以下方法: Chrome具有忽略“ border:none; none;”的已知錯誤,風格。要解決此問題,請使用以下CSS ID塊創建帶...
    程式設計 發佈於2025-05-08
  • 如何從PHP中的數組中提取隨機元素?
    如何從PHP中的數組中提取隨機元素?
    從陣列中的隨機選擇,可以輕鬆從數組中獲取隨機項目。考慮以下數組:; 從此數組中檢索一個隨機項目,利用array_rand( array_rand()函數從數組返回一個隨機鍵。通過將$項目數組索引使用此鍵,我們可以從數組中訪問一個隨機元素。這種方法為選擇隨機項目提供了一種直接且可靠的方法。
    程式設計 發佈於2025-05-08
  • 如何使用組在MySQL中旋轉數據?
    如何使用組在MySQL中旋轉數據?
    在關係數據庫中使用mySQL組使用mySQL組進行查詢結果,在關係數據庫中使用MySQL組,轉移數據的數據是指重新排列的行和列的重排以增強數據可視化。在這裡,我們面對一個共同的挑戰:使用組的組將數據從基於行的基於列的轉換為基於列。 Let's consider the following ...
    程式設計 發佈於2025-05-08
  • 如何使用“ JSON”軟件包解析JSON陣列?
    如何使用“ JSON”軟件包解析JSON陣列?
    parsing JSON與JSON軟件包 QUALDALS:考慮以下go代碼:字符串 } func main(){ datajson:=`[“ 1”,“ 2”,“ 3”]`` arr:= jsontype {} 摘要:= = json.unmarshal([] byte(...
    程式設計 發佈於2025-05-08
  • 在Python中如何創建動態變量?
    在Python中如何創建動態變量?
    在Python 中,動態創建變量的功能可以是一種強大的工具,尤其是在使用複雜的數據結構或算法時,Dynamic Variable Creation的動態變量創建。 Python提供了幾種創造性的方法來實現這一目標。 利用dictionaries 一種有效的方法是利用字典。字典允許您動態創建密鑰並...
    程式設計 發佈於2025-05-08
  • 將圖片浮動到底部右側並環繞文字的技巧
    將圖片浮動到底部右側並環繞文字的技巧
    在Web設計中圍繞在Web設計中,有時可以將圖像浮動到頁面右下角,從而使文本圍繞它纏繞。這可以在有效地展示圖像的同時創建一個吸引人的視覺效果。 css位置在右下角,使用css float and clear properties: img { 浮點:對; ...
    程式設計 發佈於2025-05-08
  • Go語言如何動態發現導出包類型?
    Go語言如何動態發現導出包類型?
    與反射軟件包中的有限類型的發現能力相反,本文探索了替代方法,探索了在Runruntime。 go import( “ FMT” “去/進口商” ) func main(){ pkg,err:= incorter.default()。導入(“ time”) 如果er...
    程式設計 發佈於2025-05-08
  • 解決Spring Security 4.1及以上版本CORS問題指南
    解決Spring Security 4.1及以上版本CORS問題指南
    彈簧安全性cors filter:故障排除常見問題 在將Spring Security集成到現有項目中時,您可能會遇到與CORS相關的錯誤,如果像“訪問Control-allo-allow-Origin”之類的標頭,則無法設置在響應中。為了解決此問題,您可以實現自定義過濾器,例如代碼段中的MyFi...
    程式設計 發佈於2025-05-08
  • PHP SimpleXML解析帶命名空間冒號的XML方法
    PHP SimpleXML解析帶命名空間冒號的XML方法
    在php 很少,請使用該限制很大,很少有很高。例如:這種技術可確保可以通過遍歷XML樹和使用兒童()方法()方法的XML樹和切換名稱空間來訪問名稱空間內的元素。
    程式設計 發佈於2025-05-08
  • Python中嵌套函數與閉包的區別是什麼
    Python中嵌套函數與閉包的區別是什麼
    嵌套函數與python 在python中的嵌套函數不被考慮閉合,因為它們不符合以下要求:不訪問局部範圍scliables to incling scliables在封裝範圍外執行範圍的局部範圍。 make_printer(msg): DEF打印機(): 打印(味精) ...
    程式設計 發佈於2025-05-08
  • 如何使用Python的請求和假用戶代理繞過網站塊?
    如何使用Python的請求和假用戶代理繞過網站塊?
    如何使用Python的請求模擬瀏覽器行為,以及偽造的用戶代理提供了一個用戶 - 代理標頭一個有效方法是提供有效的用戶式header,以提供有效的用戶 - 設置,該標題可以通過browser和Acterner Systems the equestersystermery和操作系統。通過模仿像Chro...
    程式設計 發佈於2025-05-08
  • 為什麼HTML無法打印頁碼及解決方案
    為什麼HTML無法打印頁碼及解決方案
    無法在html頁面上打印頁碼? @page規則在@Media內部和外部都無濟於事。 HTML:Customization:@page { margin: 10%; @top-center { font-family: sans-serif; font-weight: ...
    程式設計 發佈於2025-05-08
  • 在PHP中如何高效檢測空數組?
    在PHP中如何高效檢測空數組?
    在PHP 中檢查一個空數組可以通過各種方法在PHP中確定一個空數組。如果需要驗證任何數組元素的存在,則PHP的鬆散鍵入允許對數組本身進行直接評估:一種更嚴格的方法涉及使用count()函數: if(count(count($ playerList)=== 0){ //列表為空。 } 對...
    程式設計 發佈於2025-05-08

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3