Dagger 项目贡献者开发指南:用 Dagger 自身构建 Dagger 开发环境
【免费下载链接】daggerAutomation engine to build, test and ship any codebase. Runs locally, in CI, or directly in the cloud项目地址: https://gitcode.com/GitHub_Trending/da/dagger
本文基于 Dagger 仓库根目录的 CONTRIBUTING.md,系统讲解如何为 Dagger 贡献代码的完整流程:从初始环境搭建(安装 Dagger 稳定版、Changie、Fork 仓库)到日常开发(playground 联调、集成测试、Lint、本地文档服务),再到 Pull Request 提交与评审的规范。读完本文,你将能够复现 Dagger 维护者的"自举式"开发工作流——用 Dagger 来开发 Dagger,掌握dagger api call engine-dev ...、dagger check ...等核心开发命令,并理解这些命令背后对应的仓库源码(engine-dev、test-split等开发模块)。
如何找到值得贡献的问题
官方给出的最自然的贡献起点是:先把自己的工作场景放到 Dagger 上跑一遍。你在真实使用中遇到的任何问题都可以成为贡献素材,例如:
- 一个文档没有回答清楚的问题(文档缺口);
- 一个工具链里的 bug;
- 一个缺失的功能或"毛糙的边缘体验"(rough edge)。
选定问题后,按自己的难度承受力挑选合适的条目着手。贡献过程中随时可以提问,维护者明确表示乐于协助;但有一条原则值得记住:贡献体量越大,越应该尽早与维护者沟通,确认方向正确,避免把精力花在最终不会被合并的方案上。如果计划向各语言 SDK(TypeScript、Go、Python、Elixir、Java、PHP、Rust 等)本身提贡献,仓库中另有专门面向 SDK 的贡献说明 sdk/CONTRIBUTING.md,应先阅读该文档。
初始环境搭建
1. 加入社区
Dagger 官方将社区协作视为项目的核心特性之一,强烈建议先加入其 Discord 服务器。持续的反馈和鼓励不仅能帮你节省大量排障时间,也是保持长期贡献动机的关键。
2. 安装 Dagger:Dogfooding
开发 Dagger 所用的工具——"不出所料"——就是 Dagger 本身(官方原话:To develop Dagger, we use - surprise! - Dagger.)。因此第一步是安装最新的稳定版发行,如果你手上有旧版本,务必先升级。安装脚本可直接参考仓库内的 install.sh。之所以必须使用稳定版而非本地开发版来启动开发,是因为本地构建过程需要一个"底座"引擎来执行构建编排,这个底座由--x-release机制固定到一个已知可用的构建(见下文hack/build解析)。
3. 安装 Changie
Changie 是一个简单的 Release Note 管理工具。凡是涉及用户可感知变更(user-facing changes)的贡献,都需要用它生成发布说明条目。请安装最新版 Changie,后续在准备 PR 时使用changie new生成条目文件。仓库根目录 dagger.toml 中登记了 changelog 模块(.dagger/modules/changelog),且 engine-dev 模块的源码 在打包构建源时会专门排除!.changes目录——说明 changie 生成的.changes条目是仓库内被显式管理的一类文件。
4. Git 配置
在 GitHub 上找到
dagger/dagger仓库并点击Fork;克隆你的 fork:
git clone git@github.com:$YOUR_GITHUB_USER/dagger.git添加上游仓库为新的 remote:
git remote add upstream git@github.com:dagger/dagger.git
贡献工作流
官方把工作流概括为六个阶段:认领 issue → 沟通 → 开发 → 准备 PR → 提交 PR → 评审。
1. 认领 issue
在 GitHub Issues 中找到(或自行报告)一个 issue,它可能是 bug、缺失功能、缺失文档或体验毛刺。以评论方式声明你打算贡献解决方案;如果已有人在做,务必与其协调,避免重复劳动。
2. 尽早沟通
对于较大的贡献,先公开你的计划与设计方案,主动征求维护者反馈——可以在 issue 里讨论,也可以在 Discord。官方强调 "Communicate early and often":这既节省你的时间,也节省维护者的时间。
3. 本地开发与手动验证
交互式 playground
在本地开发环境里,跑一条命令即可得到一个集成度完整、可交互的"全组件"调试沙箱:
dagger api call engine-dev playground terminal这条命令会依次完成:
- 构建 Dagger 引擎,并把核心 SDKs 打包进镜像内部;
- 以 Dagger 服务的方式运行开发版引擎(即dagger-in-dagger,用 Dagger 跑 Dagger);
- 构建 Dagger CLI;
- 启动一个临时容器,容器内安装好 CLI,并把引擎作为 sidecar 提供;
- 打开交互式终端。
从源码结构看,这个能力的实现位于 engine-dev 模块。其New构造函数(main.go#L19-L66)会:
- 通过
vcsInfo从工作区 Git 中解析 HEAD commit 与 dirty 状态,并把它们作为标量(而非整个 Workspace 对象)注入构建对象——源码注释解释了原因:避免 Workspace 对象污染内容寻址的缓存键,使构建结果能在引擎重启后存活; - 按排除法收集构建所需源码(
core、engine、util、dagql、cmd、sdk、modules、.dagger、.changes等目录),排除sdk/**/examples等无关内容; - 支持
subnetNumber参数(默认 89),NetworkCidr()据此生成10.<N>.0.0/16网段,IncrementSubnet()则用于"允许嵌套 Dagger 引擎"时错开网络——这正好解释了 playground 中 dagger-in-dagger 能嵌套运行的网络前提。
仓库内置的 dev 脚本链
仓库hack/目录还保留了不依赖工作区新特性的传统脚本入口,可作为开发环境的另一条通路:
- hack/build:从本地代码构建引擎与 CLI,并在宿主的 Docker 运行时中启动引擎。它通过
--x-release固定到一个特定的 main 提交来驱动构建。源码注释说明了两个原因:一是保证宿主机器上装的是什么版本都能跑 v1.0 工作区;二是它会自动 provision 一个dagger-engine-<commit>容器,从而构建不会运行在即将被它替换的那个引擎上(避免自举悖论)。该脚本还会把历史的_EXPERIMENTAL_*环境变量映射为模块参数:容器名(默认dagger-engine.dev)、镜像名(默认localhost/dagger-engine.dev)、宿主平台(按uname解析)、GPU 支持、额外 hosts、Cloud token 等,最终执行dagger --x-release ... api call dev deploy ... --output ./bin; - hack/dev:先调用
hack/build构建并启动开发环境,再通过hack/with-dev在环境中执行指定命令。它会先探测当前 Docker context 的DOCKER_HOST(注释说明原因是dagger shell无法获取该信息),并从仓库根目录执行构建以便发现dagger.toml工作区; - hack/with-dev:设置开发环境的关键环境变量后
exec目标命令,包括_EXPERIMENTAL_DAGGER_CLI_BIN(指向./bin/dagger)、DAGGER_ENGINE=container://dagger-engine.dev(指定使用本地构建的容器引擎)、_DAGGER_TESTS_ENGINE_TAR(测试用引擎 tar 包),并把./bin加入PATH。
也就是说,无论走 playground 还是hack/dev,最终形态都是:本地源码构建的 CLI + 本地源码构建的引擎容器,二者配合完成迭代。
4. 集成测试
开发模块提供了几种不同粒度的测试入口:
跑全部核心测试:
dagger check test-split:*这里
test-split对应 dagger.toml 中登记的.dagger/modules/test-split模块,其职责是把核心测试拆分为可并行执行的批次;跑当前可用的核心测试:
dagger api call engine-dev tests跑某个具体的核心测试(例如
TestModule套件中的TestNamespacing):dagger api call engine-dev test --pkg="./core/integration" --run="^TestNamespacing$"跑 SDK 测试:
dagger check *sdk:*test*
从源码看,engine-dev test的完整参数面比文档示例更丰富。test.go 中Test方法(L22-L79)支持:
| 参数 | 含义 |
|---|---|
run | 只运行匹配该正则的测试 |
skip | 跳过匹配该正则的测试 |
pkg | 包路径,默认./... |
failfast | 首个失败即中止 |
parallel | 并行度,默认为 CPU 数 |
timeout | 整体超时 |
race | 开启竞态检测 |
count | 重复次数,默认 1 |
envFile | 通过Secret传入的测试环境变量文件 |
testVerbose | 详细输出 |
update | 更新 golden 文件 |
ebpfProgs | 测试期间在引擎中启用的 eBPF 程序列表 |
另外该方法标注了+cache="session"缓存策略(会话级),而Tests(列出所有核心测试)则委托给 Go 工具链模块执行。pkg="./core/integration"指向的正是仓库中庞大的核心集成测试目录(如 core/integration 下的module_test.go等 515 个 Go 测试文件所在树),TestModule即其中定义的一个测试套件。
5. Lint
运行全部 linter:
dagger check *:lint这一 glob 语义与 dagger.toml 中modules.golang.settings的lint字段呼应——该字段显式列出了需要 lint 的 Go 模块路径(.、engine/distconsts、modules/daggerverse、sdk/go以及各.dagger/modules/*开发模块),并排除了docs-dev/docusaurus等第三方生成目录。也就是说,dagger check *:lint实际执行的是按工作区配置分发到各语言/工具模块的 lint 检查(Go 之外还有 markdownlint、shellcheck、PsScriptAnalyzer 等,均在dagger.toml的模块表中登记)。
6. 本地文档服务器
如需本地预览文档站点:
dagger api call docs server updocs模块对应 dagger.toml 中的.dagger/modules/docs-dev,其下还包含一个 docusaurus 子模块(.dagger/modules/docs-dev/docusaurus,见as-sdk模块列表),文档源文件位于 docs/ 目录(含current_docs、versioned_docs等)。
4. 准备你的 Pull Request
提交 PR 之前,官方给出一份必须逐项完成的 checklist:
- 生成产物并提交:运行
dagger generate生成 API 文档、客户端绑定(client bindings)及其他生成文件,并把产物一并纳入 git commit。dagger.toml中modules.golang.settings.generate指明了生成输出路径(如docs/current_docs/reference/cli),这解释了为什么生成文件会出现在仓库中、为何必须随源码一起提交; - 跑全量 linter:
dagger check *:lint,全部通过; - 用户可感知变更添加 release note:运行
changie new并按提示填写,把生成的条目文件加入 commit(对应.changes目录,最终汇入 CHANGELOG.md); - 理解许可协议:所有贡献均以 Apache License 2.0(Apache-2.0)作出,见仓库根目录 LICENSE,确认你愿意并有能力遵守协议条款;
- DCO 签署:每个 commit 必须附带 Developer Certificate of Origin,做法是使用
git commit -s。Signed-off-by行必须与作者的真实姓名一致; - 提交信息规范:commit message 要有用、准确、简洁。
5. 提交 PR 与评审流程
- 把特性分支推送到你的 GitHub fork;
- 向
dagger/dagger仓库发起新的 Pull Request; - 维护者会评审 PR 并可能建议修改。如需改动,修改后推送到你的分支即可;
- 若与
main分支产生冲突:将你的分支 rebase 到最新的main上,然后 force-push(不熟悉 rebase 可自行查阅任意在线教程); - 一切就绪后,由维护者合并你的改动。
小结:Dagger 贡献工作流全景
把上述要素串起来,Dagger 的贡献工作流可以概括为一张命令地图:
| 阶段 | 命令 / 动作 | 仓库依据 |
|---|---|---|
| 环境底座 | 安装稳定版 Dagger、Changie | install.sh |
| 本地开发沙箱 | dagger api call engine-dev playground terminal | engine-dev 模块 |
| 脚本式开发环境 | hack/dev/hack/build/hack/with-dev | hack/build、hack/with-dev |
| 核心测试 | dagger check test-split:*、dagger api call engine-dev test --pkg=... --run=... | test.go |
| SDK 测试 | dagger check *sdk:*test* | dagger.toml |
| Lint | dagger check *:lint | dagger.toml中golang.settings.lint |
| 文档预览 | dagger api call docs server up | .dagger/modules/docs-dev |
| 生成产物 | dagger generate并纳入 commit | golang.settings.generate |
| 发布说明 | changie new,产物加入 commit | .dagger/modules/changelog |
| 合规 | Apache-2.0、git commit -s(DCO) | LICENSE |
值得强调的是整套工作流的"自举"性质:Dagger 用固定版本的稳定引擎(--x-release钉住的构建)作为底座,在 DAG 上构建"引擎 + CLI + 各语言 SDK",再用构建产物反过来替换底座继续开发——构建永远不运行在它即将替换的那个引擎上(见 hack/build 注释)。理解这一点,是理解 Dagger 仓库中大量.dagger/modules/*开发模块(engine-dev、cli-dev、docs-dev、各*-client-dev等)存在意义的关键。
【免费下载链接】daggerAutomation engine to build, test and ship any codebase. Runs locally, in CI, or directly in the cloud项目地址: https://gitcode.com/GitHub_Trending/da/dagger
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考