bors-ng

bors-ng

GitHub自动化合并机器人 确保主分支稳定性

bors-ng是一个GitHub应用,实现持续测试工作流以确保主分支稳定。它集成GitHub拉取请求和CI工具,自动化测试和合并流程。通过分批测试和智能合并策略,bors-ng提高代码合并效率并保证主分支质量,适用于注重代码质量管理的开源和企业项目。

GitHub持续集成自动化测试合并队列代码审查Github开源项目

弃用通知:虽然我仍会合并提供的错误修复,但不会接受新功能。 如果你想实现类似的工作流程,请使用GitHub的内置合并队列。更多信息请参见TMIB 76

GitHub拉取请求的合并机器人

Bors-NG实现了一个持续测试工作流程,确保主分支永不中断。 它将GitHub拉取请求与类似GitHub Actions的工具集成,以运行你的测试。

其他资源:

但GitHub的受保护分支不是已经做到这一点了吗?

大多数CI系统,如Jenkins和GitHub Actions,都会在每个分支被推送和每个拉取请求被打开时运行测试套件,如果测试失败,GitHub可以阻止拉取请求。要理解为什么这还不足以保持主分支始终可用,请想象以下情况:

  • 拉取请求 #1:将bifurcate()重命名为bifurcateCrab()

    更改这个函数的名称,以及当前主分支中所有调用它的地方。我考虑过将它作为Crab的方法而不是Sword的方法,但那样就会变成bifurcateWithSword(),这似乎并没有什么改进。

  • 拉取请求 #2:在着陆后除了之前外还要调用bifurcate()

    增加另一个对bifurcate()的调用,以确保即使我们跳过预着陆程序也能完成。

当这两个拉取请求都在待处理列表中开放时,它们都将与主分支一起测试。假设它们都通过了,GitHub会愉快地显示大绿色合并按钮。一旦它们都被合并,主分支就会变红(找不到方法bifurcate())。

除了测试要求外,GitHub还可以设置为阻止与主分支不"最新"的拉取请求,这意味着像这样的问题不会出现。这解决了问题,通过要求主分支只包含已通过测试的代码快照,但它需要维护者手动:

  1. "更新拉取请求",将它们合并到主分支而不改变主分支本身
  2. 等待测试套件完成
  3. 完成后合并拉取请求,这是一个简单的操作,由于步骤1,不会破坏测试套件

而且必须对每个拉取请求一次一个地进行。

这与bors自动化的过程类似,但效率较低。bors不是直接合并,而是将已审核的拉取请求添加到一个"合并队列"中,这些请求通过将主分支复制到暂存分支并合并到其中来测试。当确定暂存的状态(通过或失败)时,bors以评论的形式报告结果,如果通过则将暂存合并到主分支。然后继续处理下一个。 基于测试通常在r+后会通过的假设,bors实际上是批量测试它们(如果批次失败则进行二分法)。

请注意,bors不是你的CI系统的替代品。它只是实现了这个工作流程。

它是如何工作的

Bors是一个[GitHub应用程序],所以(假设你已经设置好了GitHub Actions),设置bors需要三个步骤:

  1. 在GitHub中将应用添加到你的仓库。点击这里使用公开托管的实例。

  2. 提交一个包含以下内容的bors.toml文件:

    status = ["ci"]
    
  3. 设置一个同名的工作流步骤。例如:

    ci-success:
      name: ci
      if: ${{ success() }}
      needs:
        - exfmt
        - test
      runs-on: ubuntu-latest
      steps:
        - name: CI succeeded
          run: exit 0
    

要使用它,你需要停止点击大绿色合并按钮,而是在任何你认为不错的拉取请求上留下包含以下内容的评论:

bors r+

随着提交被审核,bors将它们归入一个批次队列。如果一切顺利,只会有两个批次;一个正在运行,另一个正在等待运行(并不断累积更多的拉取请求,直到有机会运行)。

要运行一个批次,bors创建一个合并提交,将主分支与构成该批次的所有拉取请求合并。然而,它不会立即推送合并提交,而是将其推送到staging分支。它们看起来像这样:

Merge #5 #7 #8

5: 将`bifurcate()`重命名为`bifurcateCrab()`
7: 在`onland`事件处理程序中调用`bifurcate()`
8: 修复`drive()`中的崩溃

如果构建通过,主分支会快进到与暂存分支相匹配。由于主分支包含刚刚测试过的完全相同的内容,逐位相同,它就不会被破坏。(至少,不会以自动化测试能够检测到的方式被破坏)

如果构建失败,bors将采用一种称为"二分法"的策略。即,它将批次分成两个批次,并将它们推送到队列中。在这个例子中,第一个批次看起来像这样:

Merge #5 #7

5: 将`bifurcate()`重命名为`bifurcateCrab()`
7: 在`onland`事件处理程序中调用`bifurcate()`

这个批次仍然会失败,因为第二个补丁插入了对第一个补丁删除的函数的调用。结果,它会再次被二分。

第二个批次仍然会通过。

Merge #8

8: 修复`drive()`中的崩溃

这个批次会成功,导致它被合并到主分支,剩下前两个仍在待处理列表中。

Merge #5

5: 将`bifurcate()`重命名为`bifurcateCrab()`

这个会通过,因为与之冲突的PR(#7)在队列中排在它后面。

合并 #7

7: 在 onland 事件处理程序中调用 bifurcate()

当一个批次无法被二分(因为它只包含一个PR)时,它会被踢回给创建者以便修复。

注意,如果你想的话,可以在仪表板页面上观看这个过程的运行。

为了方便,你也可以运行 bors try,它会像 r+ 一样启动构建,但即使成功也不会真正推送到主分支。为了帮助区分,r+ 合并提交会进入 staging,而 try 构建会进入 trying

原始的bors使用了一个更简单的系统(它一次只测试一个PR)。 一次一个的策略是O(N),其中N是拉取请求的总数。 批处理策略是O(E log N),其中N仍然是拉取请求的总数,E是失败的拉取请求数。

如何在本地机器上运行

如果你使用带有Docker的macOS或Linux命令行, ./script/setup && ./script/server 将设置一个本地实例, 使用模拟的GitHub实例,并通过Docker引入所有底层依赖。 Web服务器最终会在 http://localhost:8000/ 上运行。 你可以通过运行 repl 而不是 server 来在与Web服务器相同的上下文中运行Elixir REPL。要运行测试,请运行 test 而不是 server

如果你登录,它会以"space"用户身份登录你。 不会有任何仓库,space也不会有管理员权限。 你可以使用User模型来给space管理员权限, 并使用WebhookControllerGitHub ServerMock来创建仓库。

在没有Docker的情况下设置,比如在Windows家庭版上

在你的笔记本电脑上运行Bors主要需要:

  • 熟悉命令行
  • Elixir,带有完整的OTP安装(esl-erlang包就足够了)
  • PostgreSQL;它的配置在config/dev.exs中
  • 标准C编译工具,因为bors的一些依赖使用NIFs
  • Git客户端,你可能已经有了,用于下载这个仓库
  • NodeJS,用于执行资产编译

我使用Portable PostgreSQL, Elixir、Git和NodeJS的Chocolatey包, 以及来自Microsoft的Visual C++构建工具。

然后你可以使用mix来运行它:

$ mix ecto.create
$ mix ecto.migrate
$ mix phx.server

如果你想使用MySQL,添加-r标志:

$ mix ecto.create -r BorsNG.Database.RepoMysql

它将在模拟的GitHub API环境下运行。

要运行测试,执行:

$ mix test
$ mix dogma
$ mix dialyzer

如何设置你自己的真实实例

步骤1:注册一个新的GitHub App

第一步是在GitHub网站上注册一个新的GitHub App

App设置

GitHub App名称描述主页URL不相关,不过我建议将主页指向仪表板页面。

用户授权回调URL应该设置为<仪表板URL>/auth/github/callback

设置URL留空。

webhook URL应该设置为<仪表板URL>/webhook/github

webhook密钥应该是一个随机生成的字符串。mix phx.gen.secret命令非常适合这个用途。记住这个值,以便在bors配置中指定相同的值(你也可以稍后编辑这个值,如果需要的话)。

所需的GitHub App权限

权限摘要

对于以下每个部分,设置以下整体部分权限并勾选以下webhook事件复选框。bors-ng需要这些权限的解释如下。

  • 仓库元数据:只读(无选择)
    • 仓库(仓库创建、删除、公开或私有化)
  • 仓库管理:无访问权限
  • 提交状态:读写
    • 状态(从API更新的提交状态)
  • 部署:无访问权限
  • Issues:读写
    • Issue评论(Issue评论创建、编辑或删除)
  • Pages:无访问权限
  • 拉取请求:读写
    • 拉取请求(拉取请求打开、关闭、重新打开、编辑、分配、取消分配、请求审查、取消审查请求、标记、取消标记或同步)
    • 拉取请求审查(拉取请求审查提交、编辑或驳回)
    • 拉取请求审查评论(拉取请求差异评论创建、编辑或删除)
  • 仓库内容:读写
    • (无复选框)
  • 单个文件:无访问权限
  • 仓库项目:无访问权限
  • 组织成员:只读
    • 团队(团队创建、删除、编辑、添加到/从仓库移除)
    • 成员(协作者添加到、从仓库移除或更改权限)
    • 成员资格(团队成员资格添加或移除)
    • 组织(用户被邀请、添加到或从组织移除)
  • 组织项目:无访问权限
  • 检查:读写
    • 检查运行(从API创建的检查运行)
    • 检查套件(从API创建的检查套件)

权限解释

存储库元数据将为只读。必须设置为接收存储库事件,以便在存储库被删除时自动从我们的数据库中移除条目。

提交状态必须设置为读写以报告测试状态(这是旧版本)。还必须获取状态事件以便与通过GitHub报告状态的CI系统集成。

问题必须设置为读写,因为拉取请求也是问题。必须启用问题评论事件以获取"bors r+"评论。如果问题设置为只读,存储库最终会出现同时被标记为已合并和已打开的拉取请求。

拉取请求必须设置为读写以能够发布拉取请求评论。还必须接收拉取请求事件以保持仪表板正常工作,并且必须获取拉取请求审查拉取请求审查评论事件以获取这些类型的评论。

存储库内容必须设置为读写以能够创建合并提交。

检查必须设置为读写以报告测试状态(这是新版本)。还必须获取检查运行事件以与通过GitHub报告状态的CI系统集成。

组织成员必须设置为只读以同步存储库贡献者和bors审核员。

点击"创建"按钮后

GitHub将向您的webhook端点发送"ping"通知。由于bors尚未实际运行,这将失败。这是预期的。

您需要从GitHub App获取以下值来配置bors-ng:

  • 私钥(生成一个并下载文件)
  • OAuth凭据
  • ID(显示在右侧栏的应用程序logo和"所有者"下方)

内部应用?

GitHub Apps可以设置为"内部"或"外部"。 当应用程序设置为内部时, 只有它所属的组织/用户才允许安装它。

这个设置可以在首次创建应用程序时选择,也可以之后在以下URL之一更改(开关位于页面底部):

  • 如果应用程序属于组织:https://github.com/organizations/<组织>/settings/apps/<应用程序名称>/advanced
  • 如果应用程序属于用户:https://github.com/settings/apps/<应用程序名称>/advanced

如果"外部"应用程序安装在任何外部存储库上, 则"设为内部"按钮将呈灰色。

步骤2:设置服务器

bors-ng是用Elixir编程语言编写的, 它使用PostgreSQL作为后端数据库。 无论您计划在哪台机器上运行它,都需要安装这两个。

bors-ng是基于Phoenix Web框架构建的,他们已经有有关如何部署phoenix应用程序的文档。您部署的位置将决定仪表板URL,这在前面的步骤中是必需的,所以在设置GitHub App之前需要做出这个决定。

您需要编辑配置文件,添加一些bors特定的变量。

Heroku上部署(以及其他12因素风格的系统)

存储库中的配置文件已经设置为从环境中提取所需的信息,因此您可以通过设置正确的环境变量并将应用程序从此存储库部署到Heroku来配置bors:

您可以使用Heroku的一键部署系统:

在Heroku上部署

或者您可以手动操作:

注意GITHUB_INTEGRATION_ID现在在GitHub上称为App ID。

$ heroku create --buildpack "https://github.com/HashNuke/heroku-buildpack-elixir.git" bors-app
$ heroku buildpacks:add https://github.com/gjaldon/heroku-buildpack-phoenix-static.git
$ heroku addons:create heroku-postgresql:hobby-dev
$ heroku config:set \
    MIX_ENV=prod \
    POOL_SIZE=18 \
    PUBLIC_HOST=bors-app.herokuapp.com \
    ALLOW_PRIVATE_REPOS=true \
    COMMAND_TRIGGER=bors \
    SECRET_KEY_BASE=<SECRET1> \
    GITHUB_CLIENT_ID=<OAUTH_CLIENT_ID> \
    GITHUB_CLIENT_SECRET=<OAUTH_CLIENT_SECRET> \
    GITHUB_INTEGRATION_ID=<ISS> \
    GITHUB_INTEGRATION_PEM=`base64 -w0 priv.pem` \
    GITHUB_WEBHOOK_SECRET=<SECRET2> \
    [BORS_LOG_LEVEL=<debug|info|warn|...>]
$ git push heroku master
$ heroku run POOL_SIZE=1 mix ecto.migrate

警告:bors-ng将一些短期状态存储在web dyno内(它使用休眠进程来实现延迟,具体来说)。 它可以在重启后恢复信息,但无法与Heroku的复制系统正常工作。 如果您需要的吞吐量超过一个dyno所能提供的,应该使用允许Erlang集群工作的系统进行部署。

使用Docker部署(和兼容的容器编排系统)

当前master分支的预构建Docker镜像可在Docker Hub上获得(作为bors-ng:latest)。

项目根目录中的Dockerfile可用于自行构建镜像。 它依赖于Docker 17.05中引入的多阶段构建, 以生成不包含Erlang、Elixir和NodeJS开发工具的精简镜像。

大多数重要的配置选项应该在运行时使用环境变量设置,与Heroku说明类似。 所有相同的建议都适用,还有一些额外的注意事项:

  • ELIXIR_VERSION 可以作为构建时参数设置。其默认值在 Dockerfile 中定义。

  • ALLOW_PRIVATE_REPOS 必须在构建和运行时都设置才能生效。默认设置为 true

  • DATABASE_URL 必须包含数据库端口,因为它将在容器启动时用于等待数据库可达。格式在此处有文档说明。要在 Docker 镜像中使用 MySQL,请使用 mysql 方案 URL:-e DATABASE_URL="mysql://root:<secret>@db:3306/bors_ng",并与 BORS_DATABASE=mysql 一起使用。

  • DATABASE_TIMEOUT 可以设置为高于默认值 15_000(毫秒)。对于成员数量非常多的仓库,这可能是必要的。

  • DATABASE_PREPARE_MODE 可以设置为 unnamed 以禁用预处理语句,在使用事务/语句池(如 pgbouncer)时这是必要的。默认设置为 named

  • BORS_DATABASE 可以设置为 mysql 以将 Docker 容器切换到 MySQL。

  • 除非 DATABASE_AUTO_MIGRATE 环境变量设置为 false,否则数据库架构将在容器启动时自动创建和迁移。如果数据库状态由外部管理,或者您使用的数据库无法安全处理并发架构更改(如较旧的 MariaDB/MySQL 版本),请进行该更改。

  • 可以使用 migrate 发布命令从容器手动应用数据库迁移。示例:docker run borsng/bors-ng:latest /app/bors/bin/bors migrate。 不幸的是,其他 mix 任务不可用,因为它们无法从编译的发布版本运行。

  • PORT 环境变量默认设置为 4000

  • GITHUB_URL_ROOT_APIGITHUB_URL_ROOT_HTML 应该允许您将 bors-ng 连接到 GitHub Enterprise 实例。 注意:我从未实际使用过 GitHub Enterprise,所以我只是在猜测这里需要什么。

  • BORS_LOG_LEVEL 允许您在运行时为 bors-ng 设置日志级别。 允许的值是常用的 Elixir Logger 级别,例如 infodebugwarn 等。 如果未设置,默认为 info

    docker create --name bors --restart=unless-stopped
    -e PUBLIC_HOST=app.bors.tech
    -e SECRET_KEY_BASE=<secret>
    -e GITHUB_CLIENT_ID=<secret>
    -e GITHUB_CLIENT_SECRET=<secret>
    -e GITHUB_INTEGRATION_ID=<secret>
    -e GITHUB_INTEGRATION_PEM=<secret>
    -e GITHUB_WEBHOOK_SECRET=<secret>
    -e DATABASE_URL="postgresql://postgres:<secret>@db:5432/bors_ng"
    -e DATABASE_USE_SSL=false
    -e DATABASE_AUTO_MIGRATE=true
    -e COMMAND_TRIGGER=bors
    [-e BORS_LOG_LEVEL=<debug|info|warn|...>]
    borsng/bors-ng docker start bors

在自己的集群上部署

您可以通过修改 config/prod.secret.exs 来完成配置。

可选步骤 3:将自己设为管理员

bors-ng 为"管理员"用户提供了许多特殊功能,包括诊断和无需成为审阅者即可打开仓库仪表板的能力。

然而,没有用于添加管理员的 UI;您必须自己进入 Postgres 来完成此操作。有两种方法可以做到这一点:

您可以从 iex 提示符下进行操作,如下所示:

shell$ iex -S mix # 或 `heroku run bash -c "POOL_SIZE=1 iex -S mix"`
iex> me = BorsNG.Database.Repo.get_by! BorsNG.Database.User, login: "<your login>"
iex> BorsNG.Database.Repo.update! BorsNG.Database.User.changeset(me, %{is_admin: true})

您可以从 PostgreSQL 提示符下进行操作,如下所示:

postgres=# \c bors_dev -- 或 bors_prod
bors_dev=# update users set is_admin = true where login = '<your login>';

版权许可

bors-ng 根据 Apache 许可证 2.0 版获得许可。 它应该包含在源代码分发的 LICENSE-APACHE 文件中。 如果缺失,可以在 http://www.apache.org/licenses/LICENSE-2.0 找到。

编辑推荐精选

即梦AI

即梦AI

一站式AI创作平台

提供 AI 驱动的图片、视频生成及数字人等功能,助力创意创作

扣子-AI办公

扣子-AI办公

AI办公助手,复杂任务高效处理

AI办公助手,复杂任务高效处理。办公效率低?扣子空间AI助手支持播客生成、PPT制作、网页开发及报告写作,覆盖科研、商业、舆情等领域的专家Agent 7x24小时响应,生活工作无缝切换,提升50%效率!

Keevx

Keevx

AI数字人视频创作平台

Keevx 一款开箱即用的AI数字人视频创作平台,广泛适用于电商广告、企业培训与社媒宣传,让全球企业与个人创作者无需拍摄剪辑,就能快速生成多语言、高质量的专业视频。

TRAE编程

TRAE编程

AI辅助编程,代码自动修复

Trae是一种自适应的集成开发环境(IDE),通过自动化和多元协作改变开发流程。利用Trae,团队能够更快速、精确地编写和部署代码,从而提高编程效率和项目交付速度。Trae具备上下文感知和代码自动完成功能,是提升开发效率的理想工具。

AI工具TraeAI IDE协作生产力转型热门
蛙蛙写作

蛙蛙写作

AI小说写作助手,一站式润色、改写、扩写

蛙蛙写作—国内先进的AI写作平台,涵盖小说、学术、社交媒体等多场景。提供续写、改写、润色等功能,助力创作者高效优化写作流程。界面简洁,功能全面,适合各类写作者提升内容品质和工作效率。

AI辅助写作AI工具蛙蛙写作AI写作工具学术助手办公助手营销助手AI助手
问小白

问小白

全能AI智能助手,随时解答生活与工作的多样问题

问小白,由元石科技研发的AI智能助手,快速准确地解答各种生活和工作问题,包括但不限于搜索、规划和社交互动,帮助用户在日常生活中提高效率,轻松管理个人事务。

热门AI助手AI对话AI工具聊天机器人
Transly

Transly

实时语音翻译/同声传译工具

Transly是一个多场景的AI大语言模型驱动的同声传译、专业翻译助手,它拥有超精准的音频识别翻译能力,几乎零延迟的使用体验和支持多国语言可以让你带它走遍全球,无论你是留学生、商务人士、韩剧美剧爱好者,还是出国游玩、多国会议、跨国追星等等,都可以满足你所有需要同传的场景需求,线上线下通用,扫除语言障碍,让全世界的语言交流不再有国界。

讯飞智文

讯飞智文

一键生成PPT和Word,让学习生活更轻松

讯飞智文是一个利用 AI 技术的项目,能够帮助用户生成 PPT 以及各类文档。无论是商业领域的市场分析报告、年度目标制定,还是学生群体的职业生涯规划、实习避坑指南,亦或是活动策划、旅游攻略等内容,它都能提供支持,帮助用户精准表达,轻松呈现各种信息。

AI办公办公工具AI工具讯飞智文AI在线生成PPTAI撰写助手多语种文档生成AI自动配图热门
讯飞星火

讯飞星火

深度推理能力全新升级,全面对标OpenAI o1

科大讯飞的星火大模型,支持语言理解、知识问答和文本创作等多功能,适用于多种文件和业务场景,提升办公和日常生活的效率。讯飞星火是一个提供丰富智能服务的平台,涵盖科技资讯、图像创作、写作辅助、编程解答、科研文献解读等功能,能为不同需求的用户提供便捷高效的帮助,助力用户轻松获取信息、解决问题,满足多样化使用场景。

热门AI开发模型训练AI工具讯飞星火大模型智能问答内容创作多语种支持智慧生活
Spark-TTS

Spark-TTS

一种基于大语言模型的高效单流解耦语音令牌文本到语音合成模型

Spark-TTS 是一个基于 PyTorch 的开源文本到语音合成项目,由多个知名机构联合参与。该项目提供了高效的 LLM(大语言模型)驱动的语音合成方案,支持语音克隆和语音创建功能,可通过命令行界面(CLI)和 Web UI 两种方式使用。用户可以根据需求调整语音的性别、音高、速度等参数,生成高质量的语音。该项目适用于多种场景,如有声读物制作、智能语音助手开发等。

下拉加载更多