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

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

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

代码审查对于维护标准和强调项目中代码的最佳实践始终至关重要。这不是一篇关于开发人员应该如何审查代码的文章,更多的是关于将一​​部分代码委托给 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]删除
最新教程 更多>
  • 尽管出现“页面已移动”错误,如何使用 cURL 检索页面内容?
    尽管出现“页面已移动”错误,如何使用 cURL 检索页面内容?
    使用 cURL 检索页面内容在此上下文中,您试图使用 cURL 抓取 Google 搜索结果页面的内容。尽管尝试设置用户代理和各种选项,但您仍无法成功检索页面内容。重定向或“页面移动”错误继续困扰着您。据信该问题可能源于查询字符串中特殊字符的编码。为了缓解这种情况,需要更改 PHP 代码。方法如下:...
    编程 发布于2024-11-09
  • 如何使用 JPA 和 Hibernate 以 UTC 格式存储日期/时间?
    如何使用 JPA 和 Hibernate 以 UTC 格式存储日期/时间?
    使用 JPA 和 Hibernate 在 UTC 时区存储日期/时间在 JPA/ 中处理日期和时间时担心时区差异休眠应用程序?本文探讨了如何在 UTC (GMT) 时区有效存储和检索时态数据,确保跨不同时区进行一致且准确的处理。考虑下面带注释的 JPA 实体:public class Event {...
    编程 发布于2024-11-09
  • 如何使用 CSS 创建动态扩展的文本输入字段?
    如何使用 CSS 创建动态扩展的文本输入字段?
    通过 CSS 增强文本输入响应能力制作 Web 表单时,控制文本输入字段的大小至关重要。 CSS 提供了一种简单的方法来定义其初始尺寸。但是,如果您希望输入随着用户键入而动态扩展并达到最大宽度,该怎么办?本文深入研究了仅 CSS 和基于 HTML 的技术来实现此行为。CSS 和内容可编辑利用 CSS...
    编程 发布于2024-11-09
  • 关于 Javascript Promise 的有趣事实
    关于 Javascript Promise 的有趣事实
    Promise 始终是异步的 Promise 的回调总是在同步代码之后执行 const promise = Promise.resolve(); promise.then(() => console.log('async')); console.log('sync'); ...
    编程 发布于2024-11-09
  • LightFlow:Go 的任务编排框架
    LightFlow:Go 的任务编排框架
    我开发了 LightFlow,一个任务编排框架,旨在简化 Go 中复杂工作流程的管理。它专注于执行时序并减少对外部配置文件的需求。 主要特点: 独立上下文:每个步骤都通过独立上下文链接,仅允许访问相关数据。 可合并流程:您可以灵活组合任务流程,以便在不同流程中重复使用。 检查点恢复:...
    编程 发布于2024-11-09
  • 使用 HTML、CSS 和 JavaScript 构建简单的链接检查器工具
    使用 HTML、CSS 和 JavaScript 构建简单的链接检查器工具
    使用 HTML、CSS 和 JavaScript 构建简单的链接检查器工具 作为...
    编程 发布于2024-11-09
  • ## 为什么 GetSystemTimeAdjustment 并不总是反映 Windows 7 上的真实时间调整?
    ## 为什么 GetSystemTimeAdjustment 并不总是反映 Windows 7 上的真实时间调整?
    Windows 7 计时函数:了解 GetSystemTimeAdjustment正如您所观察到的,在 Windows 7 上使用 GetSystemTimeAdjustment 函数的结果可能会令人费解。为了更好地理解,让我们解决您的问题:问题1:假设的正确性您的假设总体上是正确的。如果系统时间定...
    编程 发布于2024-11-09
  • 掌握 JavaScript:初学者的基本技巧
    掌握 JavaScript:初学者的基本技巧
    JavaScript 是一种多功能且功能强大的编程语言,构成了现代 Web 开发的支柱。如果您是 JavaScript 新手,这里有一些基本技巧可帮助您掌握其概念并开始构建交互式 Web 应用程序: 1. 了解基础知识: 变量和数据类型:了解变量、它们的类型(数字、字符串、布尔值、对...
    编程 发布于2024-11-09
  • 如何在 Python 中安全地存储用户凭据而不损害数据隐私?
    如何在 Python 中安全地存储用户凭据而不损害数据隐私?
    在 Python 中保护用户凭证在 Python 中,存储用户名和密码等敏感信息需要仔细考虑。在编写定期从第三方服务检索数据等任务的脚本时,您需要一种可靠且安全的方法来存储凭据而不损害数据隐私。一个选择是利用 Python 密钥环库,它与操作系统加密集成机制。在 Windows 中,密钥环采用 Cr...
    编程 发布于2024-11-09
  • 在 Go 中何时使用限制为切片类型的切片参数与通用切片参数?
    在 Go 中何时使用限制为切片类型的切片参数与通用切片参数?
    泛型切片参数:理解区别在 Go 中,泛型编程引入了类型参数,允许函数对不同类型进行操作。感兴趣的一个领域是限制为切片类型的切片参数和通用切片参数之间的区别。限制为切片类型的切片参数考虑使用 slices.Grow 函数第一个参数受 ~[]E 约束。这意味着该参数的类型必须是元素类型为 E 的切片类型...
    编程 发布于2024-11-09
  • 简单DIY心率监测器+心电图显示器
    简单DIY心率监测器+心电图显示器
    目标 这个迷你项目/教程的目标是用最少的组件制作一个超级简单的心率监视器和滚动心电图显示。 要求: Python 音频接口 1/4寸线/吉他线/乐器线(只需通过音频接口接入电脑即可) 快速背景 心脏的肌肉产生电信号。其中一些信号可以在皮肤表面检测到。 我们可以使用表面电极拾取这些信号。问题是,这些...
    编程 发布于2024-11-09
  • 生态倡议地图:CSS(第 2 部分)
    生态倡议地图:CSS(第 2 部分)
    Introducción En este tutorial, aprenderás cómo mejorar la apariencia visual de tu página HTML aplicando estilos CSS de manera gradual. A lo l...
    编程 发布于2024-11-09
  • 如何使全局变量可跨多个 JavaScript 文件访问?
    如何使全局变量可跨多个 JavaScript 文件访问?
    跨多个 JavaScript 文件访问全局变量当使用分布在多个文件中的 JavaScript 代码时,共享数据的需求变得显而易见。实现此目的的一种方法是使用全局变量。用户遇到一个问题,外部 JavaScript 文件 (helpers.js) 中定义的全局变量在调用它的 HTML 文件中仍然无法访问...
    编程 发布于2024-11-09
  • 如何配置 PHP 上传大文件(最多 100MB)?
    如何配置 PHP 上传大文件(最多 100MB)?
    配置 PHP 进行大文件上传上传大文件可能具有挑战性,但使用正确的方法可以处理最多 100 MB 的上传PHP 配置。本文探讨了 php.ini 文件中启用此类大文件传输所需的更改。要调整的主要设置与文件上传大小限制和请求处理时间相关:upload_max_filesize: 该值指定允许上传的最大...
    编程 发布于2024-11-09
  • 如何针对 2000 万个温度读数优化对大型 MySQL 数据库的批量插入?
    如何针对 2000 万个温度读数优化对大型 MySQL 数据库的批量插入?
    大规模MySql数据库插入的批量插入优化当面临高效地将大量记录插入MySql数据库的任务时,考虑优化技术至关重要加快该过程。在此线程中,用户遇到了将 2000 万个温度读数插入表中需要很长时间的情况。该代码使用单行 INSERT 语句,虽然简单,但对于批量操作来说并不是最佳选择。为了解决这一挑战,提...
    编程 发布于2024-11-09

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

Copyright© 2022 湘ICP备2022001581号-3