”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > Better - 人工智能驱动的代码审查器 GitHub Action

Better - 人工智能驱动的代码审查器 GitHub Action

发布于2024-11-08
浏览:178

代码审查对于维护标准和强调项目中代码的最佳实践始终至关重要。这不是一篇关于开发人员应该如何审查代码的文章,更多的是关于将一​​部分代码委托给 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]删除
最新教程 更多>
  • 在UTF8 MySQL表中正确将Latin1字符转换为UTF8的方法
    在UTF8 MySQL表中正确将Latin1字符转换为UTF8的方法
    在UTF8表中将latin1字符转换为utf8 ,您遇到了一个问题,其中含义的字符(例如,“jáuòiñe”)在utf8 table tabled tablesset中被extect(例如,“致电。为了解决此问题,您正在尝试使用“ mb_convert_encoding”和“ iconv”转换受...
    编程 发布于2025-06-27
  • 哪种方法更有效地用于点 - 填点检测:射线跟踪或matplotlib \的路径contains_points?
    哪种方法更有效地用于点 - 填点检测:射线跟踪或matplotlib \的路径contains_points?
    在Python Matplotlib's path.contains_points FunctionMatplotlib's path.contains_points function employs a path object to represent the polygon.它...
    编程 发布于2025-06-27
  • 如何使用组在MySQL中旋转数据?
    如何使用组在MySQL中旋转数据?
    在关系数据库中使用mySQL组使用mySQL组进行查询结果,在关系数据库中使用MySQL组,转移数据的数据是指重新排列的行和列的重排以增强数据可视化。在这里,我们面对一个共同的挑战:使用组的组将数据从基于行的基于列的转换为基于列。 Let's consider the following ...
    编程 发布于2025-06-27
  • 在程序退出之前,我需要在C ++中明确删除堆的堆分配吗?
    在程序退出之前,我需要在C ++中明确删除堆的堆分配吗?
    在C中的显式删除 在C中的动态内存分配时,开发人员通常会想知道是否需要手动调用“ delete”操作员在heap-exprogal exit exit上。本文深入研究了这个主题。 在C主函数中,使用了动态分配变量(HEAP内存)的指针。当应用程序退出时,此内存是否会自动发布?通常,是。但是,即使在这...
    编程 发布于2025-06-27
  • PHP与C++函数重载处理的区别
    PHP与C++函数重载处理的区别
    作为经验丰富的C开发人员脱离谜题,您可能会遇到功能超载的概念。这个概念虽然在C中普遍,但在PHP中构成了独特的挑战。让我们深入研究PHP功能过载的复杂性,并探索其提供的可能性。在PHP中理解php的方法在PHP中,函数超载的概念(如C等语言)不存在。函数签名仅由其名称定义,而与他们的参数列表无关。...
    编程 发布于2025-06-27
  • 对象拟合:IE和Edge中的封面失败,如何修复?
    对象拟合:IE和Edge中的封面失败,如何修复?
    To resolve this issue, we employ a clever CSS solution that solves the problem:position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%)...
    编程 发布于2025-06-27
  • `console.log`显示修改后对象值异常的原因
    `console.log`显示修改后对象值异常的原因
    foo = [{id:1},{id:2},{id:3},{id:4},{id:id:5},],]; console.log('foo1',foo,foo.length); foo.splice(2,1); console.log('foo2', foo, foo....
    编程 发布于2025-06-27
  • 如何使用Python有效地以相反顺序读取大型文件?
    如何使用Python有效地以相反顺序读取大型文件?
    在python 反向行读取器生成器 == ord('\ n'): 缓冲区=缓冲区[:-1] 剩余_size- = buf_size lines = buffer.split('\ n'....
    编程 发布于2025-06-27
  • 如何避免Go语言切片时的内存泄漏?
    如何避免Go语言切片时的内存泄漏?
    ,a [j:] ...虽然通常有效,但如果使用指针,可能会导致内存泄漏。这是因为原始的备份阵列保持完整,这意味着新切片外部指针引用的任何对象仍然可能占据内存。 copy(a [i:] 对于k,n:= len(a)-j i,len(a); k
    编程 发布于2025-06-27
  • 为什么使用Firefox后退按钮时JavaScript执行停止?
    为什么使用Firefox后退按钮时JavaScript执行停止?
    导航历史记录问题:JavaScript使用Firefox Back Back 此行为是由浏览器缓存JavaScript资源引起的。要解决此问题并确保在后续页面访问中执行脚本,Firefox用户应设置一个空功能。 警报'); }; alert('inline Alert')...
    编程 发布于2025-06-27
  • MySQL中如何高效地根据两个条件INSERT或UPDATE行?
    MySQL中如何高效地根据两个条件INSERT或UPDATE行?
    在两个条件下插入或更新或更新 solution:的答案在于mysql的插入中...在重复键更新语法上。如果不存在匹配行或更新现有行,则此功能强大的功能可以通过插入新行来进行有效的数据操作。如果违反了唯一的密钥约束。实现所需的行为,该表必须具有唯一的键定义(在这种情况下为'名称'...
    编程 发布于2025-06-27
  • Java中假唤醒真的会发生吗?
    Java中假唤醒真的会发生吗?
    在Java中的浪费唤醒:真实性或神话?在Java同步中伪装唤醒的概念已经是讨论的主题。尽管存在这种行为的潜力,但问题仍然存在:它们实际上是在实践中发生的吗? Linux的唤醒机制根据Wikipedia关于伪造唤醒的文章,linux实现了pthread_cond_wait()功能的Linux实现,利用...
    编程 发布于2025-06-27
  • 在Java中使用for-to-loop和迭代器进行收集遍历之间是否存在性能差异?
    在Java中使用for-to-loop和迭代器进行收集遍历之间是否存在性能差异?
    For Each Loop vs. Iterator: Efficiency in Collection TraversalIntroductionWhen traversing a collection in Java, the choice arises between using a for-...
    编程 发布于2025-06-27
  • 如何从PHP中的数组中提取随机元素?
    如何从PHP中的数组中提取随机元素?
    从阵列中的随机选择,可以轻松从数组中获取随机项目。考虑以下数组:; 从此数组中检索一个随机项目,利用array_rand( array_rand()函数从数组返回一个随机键。通过将$项目数组索引使用此键,我们可以从数组中访问一个随机元素。这种方法为选择随机项目提供了一种直接且可靠的方法。
    编程 发布于2025-06-27
  • 如何将MySQL数据库添加到Visual Studio 2012中的数据源对话框中?
    如何将MySQL数据库添加到Visual Studio 2012中的数据源对话框中?
    在Visual Studio 2012 尽管已安装了MySQL Connector v.6.5.4,但无法将MySQL数据库添加到实体框架的“ DataSource对话框”中。为了解决这一问题,至关重要的是要了解MySQL连接器v.6.5.5及以后的6.6.x版本将提供MySQL的官方Visual...
    编程 发布于2025-06-27

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3