localci 发布:在本地运行 GitHub Actions 作业再推送
Show HN: localci, run your GitHub Actions jobs locally before you push
localci 是一个在本地运行现有 .github/workflows 的工具,无需新配置,只跑与当前机器 OS 匹配的作业,跳过 actions/checkout 等 setup 步骤。
等待 GitHub 接收你的推送、排队一个 runner 并从冷缓存重新构建一切,这很慢。有时 GitHub 干脆宕机了。localci 在你自己的机器上运行你现有的 .github/workflows/ci.yml,只需几秒钟,而且你的构建缓存仍然是热的。
- 无需新配置。它读取你已经拥有的工作流。
- 你的操作系统,你的任务。它运行那些
runs-on与你机器(Linux、macOS 或 Windows)匹配的任务,并告诉你哪些任务需要其他操作系统。 - 真实的步骤。Shell 步骤、矩阵、
needs、输出、GITHUB_ENV、if:条件和services:(作为 Docker 容器)的行为与在 GitHub 上一致。诸如actions/checkout之类的 setup 操作会被跳过,因为你的机器已经有 checkout 和这些工具了。 - 为 agent 而打造。一条命令就能教会 Claude Code、Codex 和其他 agent 在推送前运行你 CI 中正确的子集。
- 极小。一个静态二进制文件,下载不到 800 KB,安装不到 2 秒。
数字
在 Horizon 上测量,这是一个公开的 Rust 工作区,带有 Linux、macOS 和 Windows CI 矩阵,测量时间为 2026 年 10 月 10 日和 11 日。
等待 GitHub 与本地检查对比
| 时间 | |
|---|---|
| 一次 GitHub CI 运行,从推送到结果(18 次运行的中位数) | 27 分钟 |
用 localci run 运行相同的 Linux 任务,一个接一个 |
15 到 23 分钟 |
用 localci run --fast 运行相同的改动 |
2 分 16 秒 |
再次运行 localci run --fast,没有任何改动 |
0 秒 |
一个失败的 CI 测试,在推送前被 localci run repo-checks 发现 |
4 秒 |
| 在 PR 上用 Copilot 进行一轮代码审查,外加一次推送 | 约 5 分钟 |
| 一轮本地审查(该 skill 的 Copilot CLI 提示),不推送 | 1 到 4 分钟 |
它在一个 pull request 上节省了什么。没有 localci 时,每次推送都会启动一次约 62 runner-minutes 的完整 CI 运行,而一轮修复要等它完成。在最近 40 个已合并的 Horizon PR 中:
| 审查轮数 | CI 运行次数 | Runner 时间 | |
|---|---|---|---|
| 小型 PR(5 个文件或更少),中位数 | 1 | 1 | 63 分钟 |
| 大型 PR(超过 10 个文件),中位数 | 5 | 5 | 307 分钟 |
| 使用 localci 和该 skill 的 PR 循环的大型 PR(估算) | 1 到 2 | 1 到 2 | 60 到 125 分钟 |
有了 PR 循环,你在本地审查和测试,直到两者都干净,GitHub 上的审查就变成了最终检查,而不是你反复迭代的地方。对于一个大型 PR,这大约意味着少等 1½ 小时,以及少用 3 到 4 小时的 runner 时间。大型 PR 那一行是估算;下面的行是实测的。
真实的 PR,随着循环的改进
| PR | 新增内容 | GitHub 上的审查轮数 | CI 运行次数 | 从打开到就绪 |
|---|---|---|---|---|
| #1461 | 每次推送前运行 localci,修复直接推送而不运行 CI | 4(1 次有发现) | 4 次推送运行 2 次 | 9 分钟后首次批准 |
| #1466 | PR 前进行一次通用本地审查 | 5 | 5 次推送启动了 4 次 | 42 分钟 |
| #1471 | 一次要求具体失败输入的本地审查,并将 GitHub 的审查作为最终检查 | 1 | 1 | 12 分钟 |
作为对比,在 localci 之前,Horizon 小型 PR 的中位数从打开到合并需要 24 分钟,包含一轮审查和一次 63 runner-minutes 的 CI 运行。
快速开始
macOS 和 Linux
curl -fsSL https://raw.githubusercontent.com/peters/localci/main/install.sh | shWindows (PowerShell)
irm https://raw.githubusercontent.com/peters/localci/main/install.ps1 | iex
不想把脚本直接管道进你的 shell?从 Releases 下载二进制文件:Linux x64 和 arm64(静态)、macOS Apple silicon 和 Intel,以及 Windows x64。安装了 Rust 的话,你也可以在约 10 秒内自行构建:cargo install --locked --git https://github.com/peters/localci。
然后,在任何带有 GitHub Actions 的仓库中:
localci list # every job and matrix leg, and which run here localci run # run them
为你的 agent 做引导
localci skill install
这会把一个 skill 放入 ~/.claude/skills、~/.codex/skills 和 ~/.agents/skills(针对你拥有的每个 agent)。从那时起,只需问:
在推送前本地运行 CI。
智能体会查看计划和你的 diff,建议哪些作业和步骤值得运行,只询问你一次,然后运行它们,并且只读取失败步骤的日志。它知道本地运行只是快速的预检查,并非真正的 GitHub 结果。
日常使用
localci plan # what would run, step by step, without running it localci run clippy # one job, by id localci run "linux x64 libs" # one matrix leg, by name localci run --matrix shard=libs # legs with that matrix value localci run --skip-setup # leave out apt-get, brew and installer steps localci run --skip "slow tests" # leave out steps by name or command localci run --only lint # run only matching steps localci run -k # keep going after a failing job localci run -w release # another workflow file localci check # can localci handle every workflow here?
添加 --json -q 以获得机器可读的报告。每个步骤的日志都会被保留,并在最后打印路径。
快速模式(0.1.0 新增)
localci run --fast
--fast 同时是三件事:
--affected:当某个步骤的输入自你的分支离开默认分支以来没有变化时,跳过构建和测试步骤(Cargo、npm、dotnet、Go、Gradle、Swift)。localci 无法读取其命令的步骤始终会运行。--cache:在相同输入上复用已经通过的步骤,包括其输出。--parallel 0:同时运行相互独立的作业(2 到 4 个,取决于 CPU 数量)。
在 Horizon 上,一次文档和 CI 变更从 23 分钟的完整 Linux 运行缩短到使用 --fast 的 136 秒,而在没有变更的第二次运行中缩短到 0 秒。localci plan --affected 展示了每个步骤为何运行或不运行。在推送以供审查之前,先在不带 --fast 的情况下运行一次。
在本地跳过,在 GitHub 上保留
有些步骤永远不应该在你的笔记本电脑上运行,比如 sudo apt-get install 或部署作业。用普通的 GitHub 条件标记它们。localci 会设置 LOCALCI,而在 GitHub 上它是空的,因此 GitHub 会继续运行它们:
jobs: deploy: if: ${{ !vars.LOCALCI }} # jobs: use vars ... test: steps: - name: Install system packages if: ${{ !env.LOCALCI }} # steps: env or vars run: sudo apt-get install -y libssl-dev
服务
带有 services: 的作业(PostgreSQL、Redis 等)会获得真实的 Docker 容器,包括其健康检查和端口映射,并在作业结束时移除。如果你自己已经运行了这些服务,请添加 --no-services。设置 LOCALCI_DOCKER=podman 以使用 Podman。
对比
act 是这方面知名的工具,wrkflw 则是一个较新的工具。两者都试图复现 GitHub runner:默认情况下,它们在容器中运行每个作业,并运行 uses: actions。当你想测试工作流本身时,这是正确的选择。
localci 回答的是另一个问题:“我的变更能通过 CI 吗?”因此它做出相反的选择:
| act / wrkflw(默认) | localci | |
|---|---|---|
| 步骤在哪里运行 | 一个模仿 runner 镜像的容器 | 你的机器,在你的检出目录中 |
| 构建缓存 | 通常是冷的:被忽略的构建输出留在容器之外 | 你温暖的 target/、node_modules/ 等 |
uses: actions |
运行它们 | 跳过它们;你的机器已经有这些工具 |
| 未变更的步骤 | 再次运行 | --fast 将它们排除或复用结果 |
| 智能体 | 不是重点 | 以 JSON 表示的计划、一个 skill,以及仅失败步骤的日志 |
act 也可以直接在宿主机上运行(-P ubuntu-latest=-self-hosted)。剩下的区别在于 localci 省略了什么,以及它被设计为由智能体驱动。
当 localci 不适合时
- 你的 CI 主要是市场 actions。如果真正的工作发生在
uses:步骤中(例如docker/build-push-action或部署 action),localci 会跳过它。请使用 act 或 GitHub。 - 你需要精确的 runner 镜像。localci 使用你的工具和版本。某个步骤可能在这里通过,却在 GitHub 上失败,因为工具不同。
- 针对其他操作系统的作业。它只运行与你的机器匹配的作业。请改在那种机器上运行。
- 可复用工作流和
container:作业。它不会运行它们。 - GitHub 上的结果。它不会发布检查或状态。GitHub CI 仍是最终依据。
发现了与 GitHub 的差异?
每个 bug 都会变成 tests/cases/ 中的一个小文件夹:一个工作流及其应给出的结果。无需 Rust 代码。参见该流程,并请提交 issue 或 pull request。
许可证
MIT
来源:Hacker News · github.com
