Composio CLI Docker E2E 测试体系:在纯净 Debian 容器中验证编译版 composio 二进制的完整实践
【免费下载链接】composioComposio powers 1000+ toolkits, tool search, context management, authentication, and a sandboxed workbench to help you build AI agents that turn intent into action.项目地址: https://gitcode.com/GitHub_Trending/co/composio
本文围绕仓库内 Docker CLI E2E 参考文档 展开,系统讲解 Composio 仓库如何把bun build --compile编译出的独立composio二进制放进 scratch Debian 容器做端到端验证:从测试套件目录约定、Dockerfile 多阶段构建、e2e()/runCmd测试 API,到pnpm test:e2e:cli的完整验证流程。读完后你可以理解这套 E2E 体系的隔离模型与输出契约,并能为 CLI 新增一个可运行的 E2E 套件。
整体架构:为什么用 scratch Debian 容器跑 CLI
CLI E2E 测试的核心思路是:不在开发机上直接跑二进制,而是把编译好的独立composio可执行文件放进一个尽可能干净的环境执行。架构文档 列出了这套体系的关键属性:
- 每个测试套件(suite)位于
ts/e2e-tests/cli/<suite-name>/目录下; - 每个套件包含
e2e.test.ts和package.json两个核心文件; - 每次命令调用都运行在一个全新的容器中,避免状态串扰;
- 容器内运行时 shell 是 POSIX
sh,而非 bash; HOME=/tmp,因此任何认证状态和 API 状态必须来自环境变量或命令内自行创建的文件(例如whoami套件依赖COMPOSIO_USER_API_KEY环境变量);- stdout 不是 TTY,因此 CLI 的piped-mode(管道模式)输出规则生效——CLI 会抑制所有装饰性输出(彩色、spinner 等),只输出机器可读的数据,测试正是验证这一契约。
CLI E2E README 进一步补充:二进制通过bun build --compile在 Docker 镜像构建阶段编译,产出一个无运行时依赖的自包含可执行文件;测试用runCmd在容器内执行 shell 命令,并对退出码、stdout、stderr 做断言。例如composio version > out.txt这类重定向场景,验证的就是“管道下只有干净数据”这条契约。
当前仓库中实际存在的套件包括:
| 套件 | 验证内容 | 所需环境变量 |
|---|---|---|
| upgrade | composio upgrade能替换正在运行的 Linux 可执行文件 | 无 |
| version | composio version的输出与退出码 | 无 |
| whoami | composio whoami打印 API key | COMPOSIO_USER_API_KEY |
隔离工具是Docker,CLI 版本解析为当前 monorepo 构建(cli: ['current'])。
套件模板:每个 suite 的标准 package.json
参考文档 给出了新增套件时的package.json模板:
{ "name": "@e2e-tests/cli-<suite-name>", "version": "0.0.0", "private": true, "type": "module", "scripts": { "typecheck": "tsc --noEmit", "test:e2e": "bun test e2e.test.ts", "test:e2e:cli": "bun test e2e.test.ts" }, "devDependencies": { "@e2e-tests/utils": "workspace:*" } }对照仓库中的真实套件,version 套件的 package.json 与 upgrade 套件的 package.json 与模板完全一致:包名为@e2e-tests/cli-version/@e2e-tests/cli-upgrade,唯一依赖是 workspace 内的@e2e-tests/utils。
这个@e2e-tests/cli-*命名不是随意的——仓库根目录 package.json 中定义了聚合命令:
"test:e2e:cli": "turbo test:e2e:cli --filter='@e2e-tests/cli-*'"也就是说,所有 CLI 套件靠包名前缀被 Turbo 一次性筛出并执行;这也是为什么新增套件必须遵守模板里的包名规范。
镜像构建剖析:Dockerfile.cli 的多阶段设计
整个 E2E 体系的镜像由 Dockerfile.cli 构建,它是参考文档中“scratch Debian 容器”说法的具体落地。构建分两个阶段:
阶段一:builder(node:${NODE_VERSION}-slim)
通过 mise 安装
bun和pnpm(版本由 mise.toml/mise.lock 固定),Node 则留在基础镜像上;先拷贝
pnpm-lock.yaml以利用层缓存,再拷贝 workspace 配置文件与ts/packages/源码,执行pnpm install --frozen-lockfile(有意不用--mount=type=cache,注释说明会导致跨构建的原生绑定问题);编译 CLI 二进制:
bun build ./src/bin.ts \ --env DEBUG_OVERRIDE_* \ --compile \ --production \ --outfile /out/composio构建
composio run的伴生模块:bun scripts/build-companion-modules.ts /out --host-only。注释里给出了两处体积优化的具体依据——--host-only让打包的 codex-acp 二进制只保留当前镜像平台(全部平台会多约 870MB、多约 2 分钟构建时间,而镜像永远执行不了那些平台);构建完成后立即rm -rf /out/acp-adapters,因为 E2E 测试不会调用 ACP 子代理,保留它们会多约 224MB,且删除与生成在同一层,保证完全不进最终镜像。预创建
/tmp/.composio目录,用于绕过 Bun issue #7967。
阶段二:最终运行环境(debian:bookworm-slim)
FROM debian:bookworm-slim ENV PATH="/usr/local/bin:/bin" ENV HOME="/tmp"- 二进制和
composio run伴生模块一起拷入/usr/local/bin/,二者必须保持同级(伴生模块从dirname(process.execPath)解析,否则 CLI 会认为安装损坏并进入 GitHub self-repair 路径); - CLI 缓存目录
/tmp/.composio一并拷贝; CMD ["/bin/sh"],与文档中“运行时 shell 是 POSIX sh”的属性对应。
HOME=/tmp这一行正是参考文档强调的“认证和 API 状态必须来自环境变量或命令 setup”的根因——容器里没有用户目录可依赖,测试必须自己构造状态(如 version 测试 中用mkdir -p .composio && printf ... > .composio/update-check.json伪造更新检查结果,再配合HOME="$PWD"让 CLI 读到它)。
编写测试:e2e()、runCmd 与版本套件实战
测试代码的入口是@e2e-tests/utils(源码在 ts/e2e-tests/_utils/src)导出的e2e()。从 e2e.ts 的源码看,它做了三件事:校验传入的import.meta.url必须是file://URL;从调用者文件位置自动推断套件工作目录和套件名(inferCwd把调用者目录相对仓库根目录规范化为正斜杠路径);最后交给runE2E执行。所以测试文件里无需手工声明自己是谁、住在哪个目录。
version 套件 是一个完整的参考实现:
e2e(import.meta.url, { versions: { cli: ['current'], }, defineTests: ({ runCmd }) => { beforeAll(async () => { versionResult = await runCmd('composio version'); // 伪造“存在 99.0.0 新版本”的本地更新检查结果 updateAvailableResult = await runCmd( `mkdir -p .composio && printf '%s' '{"lastChecked":"2099-01-01T00:00:00.000Z","latestVersion":"99.0.0"}' > .composio/update-check.json && HOME="$PWD" composio version --check` ); // 捕获容器内生成的文件 redirectedResult = await runCmd({ command: 'composio version > out.txt', files: ['out.txt'], }); }, TIMEOUTS.FIXTURE); // 断言退出码、stdout 快照、stderr 为空、out.txt 内容…… }, });它验证了四个场景:composio version的干净输出(经sanitizeOutput去 ANSI、规范化换行、去首尾空白后应恰好等于 ts/packages/cli/package.json 中的版本号)、--check检测到新版本时输出机器可读 JSON(updateAvailable: true)、未知发布状态时不谎报“已是最新”(checkStatus: 'unknown')、以及 stdout 重定向到文件后终端无输出而out.txt内容正确。
几个值得注意的工具细节:
- 文件捕获:
runCmd({ command, files: ['out.txt'] })会在执行后把容器内文件拷出,作为result.files映射返回,专门用于断言“CLI 写盘”的行为(见 utils README 的 “runCmd with File Capture” 一节)。 - 超时常量:
TIMEOUTS定义在 const.ts,其中DEFAULT: 5_000、FIXTURE: 120_000、LLM_SHORT: 30_000、LLM_LONG: 60_000。CLI 套件的beforeAll统一使用TIMEOUTS.FIXTURE,因为它要串行执行多次容器命令。 - CLI 版本解析:
WELL_KNOWN_CLI_VERSIONS = ['current'](const.ts),current解析为ts/packages/cli/package.json中的版本,也可通过COMPOSIO_E2E_CLI_VERSION环境变量或config.versions.cli覆盖。 - 环境变量校验:传给
E2EConfig.env的变量若在启动时值为undefined,测试会 fail-fast 并列出缺失变量名,避免凭据缺失导致的静默失败。
验证与运行:从仓库根到单个套件
参考文档给出的验证方式有两层:
全量运行(仓库根目录):
pnpm test:e2e:cli该命令经 Turbo 用--filter='@e2e-tests/cli-*'命中所有 CLI 套件并执行各自的test:e2e:cli脚本(即bun test e2e.test.ts)。
迭代单个套件时聚焦运行:参考文档建议“使用聚焦的 Turbo filter”;CLI README 给出了等价的直接进入套件目录的方式:
cd ts/e2e-tests/cli/version && pnpm test:e2e:cli cd ts/e2e-tests/cli/whoami && pnpm test:e2e:cli cd ts/e2e-tests/cli/upgrade && pnpm test:e2e:cli前置条件是本地已安装 Docker(镜像构建与容器执行都依赖它);whoami套件还需要在环境中提供COMPOSIO_USER_API_KEY。每次运行会生成结构化的DEBUG.log(按运行时版本分组,记录容器名、命令、耗时、退出码与 stdout/stderr 全量输出),便于排查容器内命令失败的原因。
小结与关键路径
这套体系的设计取舍可以概括为三点:用 scratch 容器排除本机环境噪声(POSIX sh、HOME=/tmp、每次命令全新容器);用 piped-mode 输出契约保证测试断言的机器可读性;用包名规范 + Turbo filter 让套件数量增长时聚合命令自动扩展。新增一个 CLI E2E 套件时,只需按@e2e-tests/cli-<suite-name>模板建目录、写e2e.test.ts、复用Dockerfile.cli,即可自动纳入pnpm test:e2e:cli。
关键文件索引:
- 架构与套件模板:.agents/skills/cli-e2e/references/docker-cli-e2e.md
- 套件总览与运行说明:ts/e2e-tests/cli/README.md
- 镜像构建:ts/e2e-tests/_utils/Dockerfile.cli
- 测试框架实现:ts/e2e-tests/_utils/src/e2e.ts、ts/e2e-tests/_utils/src/const.ts
- 工具 API 文档:ts/e2e-tests/_utils/README.md
- 参考实现:ts/e2e-tests/cli/version/e2e.test.ts
- 聚合命令:package.json 中的
test:e2e:cli
【免费下载链接】composioComposio powers 1000+ toolkits, tool search, context management, authentication, and a sandboxed workbench to help you build AI agents that turn intent into action.项目地址: https://gitcode.com/GitHub_Trending/co/composio
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考