Codex CLI 接入 CI/CD 流水线:GitHub Actions 自动化测试生成与代码审查实战
Codex CLI 的真正生产力爆发点不是单人使用,而是集成到 CI/CD 流水线后的团队级自动化。本文演示四个经过验证的生产工作流:PR 自动代码审查、新代码自动生成测试、依赖升级后的回归分析,以及在服务器上触发大规模代码迁移任务。
一、CI 环境准备
1. 安全存储 API Key
在 GitHub 仓库设置中添加 Secret:
- 进入仓库 → Settings → Secrets and variables → Actions
- 点击「New repository secret」
- Name:
OPENAI_API_KEY,Value:你的 API Key
对于组织级共用,推荐在 Organization Secrets 中统一管理,避免每个仓库单独配置。
2. 为 CI 创建专用 API Key
不要在 CI 中复用个人 API Key:
- 在 OpenAI Platform 创建独立的 Project API Key,专用于 CI
- 设置用量限制(Usage Limits),防止失控消费
- CI Key 只应有 model inference 权限,不应有 admin 权限
3. 在 AGENTS.md 中声明 CI 专用规则
# 在项目 AGENTS.md 中添加 CI 专用约束
## CI 模式规则(当 CI=true 环境变量存在时)
- 只输出具体的代码变更和命令,不输出解释性文字
- 测试生成必须遵循现有测试文件的命名约定
- 不允许修改除测试文件以外的任何文件
- 生成的测试必须能通过 pytest 零配置运行二、工作流一:PR 自动代码审查
每当 PR 被创建或更新时,Codex 自动分析差异并以评论形式输出审查报告。
创建 .github/workflows/codex-review.yml:
name: Codex PR Code Review
on:
pull_request:
types: [opened, synchronize]
paths:
- 'app/**/*.py' # 只在后端代码变更时触发
- 'tests/**/*.py'
jobs:
code-review:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write # 需要写 PR 评论的权限
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # 获取完整历史,用于生成正确的 diff
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
- name: Install Codex CLI
run: npm install -g @openai/codex
- name: Get PR diff
id: diff
run: |
git diff origin/${{ github.base_ref }}...HEAD \
-- 'app/**/*.py' 'tests/**/*.py' > /tmp/pr.diff
echo "diff_size=$(wc -l < /tmp/pr.diff)" >> $GITHUB_OUTPUT
- name: Skip if diff is too large
if: steps.diff.outputs.diff_size > 1000
run: |
echo "PR diff too large (>1000 lines), skipping Codex review to control cost."
exit 0
- name: Run Codex code review
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
CI: "true"
run: |
cat /tmp/pr.diff | codex \
--approval-mode suggest \
--sandbox read-only \
--output-format json \
"审查以下 Git diff,重点关注:
1. 潜在的 bug 和逻辑错误
2. 安全漏洞(SQL注入、XSS、不安全的密钥处理)
3. 性能问题(N+1查询、缺失索引、不必要的全表扫描)
4. 代码规范违反(参考 AGENTS.md)
5. 缺失的错误处理
输出格式:按问题严重程度分级(Critical/High/Medium/Low),
每个问题注明文件名和行号,给出具体修复建议。
如果没有发现问题,输出:LGTM" \
> /tmp/review.txt
- name: Post review comment
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const review = fs.readFileSync('/tmp/review.txt', 'utf8');
if (review.trim() === 'LGTM') {
await github.rest.pulls.createReview({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number,
event: 'APPROVE',
body: '✅ Codex 审查通过,未发现问题。',
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `## 🤖 Codex 代码审查报告\n\n${review}\n\n---\n*由 Codex CLI 自动生成,仅供参考,最终决策以人工审查为准。*`,
});
}三、工作流二:新代码自动生成单元测试
检测新增的函数,自动为没有对应测试的函数生成测试文件。
创建 .github/workflows/codex-generate-tests.yml:
name: Codex Generate Missing Tests
on:
push:
branches: [main, develop]
paths:
- 'app/services/**/*.py' # 只监控 Service 层(必须有测试的层)
jobs:
generate-tests:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/setup-node@v4
with:
node-version: '22'
- run: npm install -g @openai/codex
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: pip install -r requirements.txt
- name: Detect new functions without tests
id: detect
run: |
# 获取本次提交新增的 Python 函数(简化版检测)
git diff HEAD~1 --unified=0 -- 'app/services/**/*.py' \
| grep '^+.*def ' \
| grep -v '^+++' \
| sed 's/^+//' > /tmp/new_functions.txt
echo "Found $(wc -l < /tmp/new_functions.txt) new function(s)" echo "has_new=$([ -s /tmp/new_functions.txt ] && echo true || echo false)" \ >> $GITHUB_OUTPUT
- name: Generate tests with Codex
if: steps.detect.outputs.has_new == 'true'
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
CI: "true"
run: |
# 获取变更的文件列表
CHANGED_FILES=$(git diff HEAD~1 --name-only -- 'app/services/**/*.py')
for file in $CHANGED_FILES; do
module=$(basename "$file" .py)
test_file="tests/services/test_${module}.py"
echo "Generating tests for: $file → $test_file"
codex \
--approval-mode auto-edit \
--sandbox workspace-write \
"分析 ${file} 中本次新增的函数(参考 /tmp/new_functions.txt),
为每个新函数生成完整的 pytest 单元测试,写入 ${test_file}。
规则:
- 如果 ${test_file} 已存在,只在末尾追加新测试,不修改已有测试
- 每个函数至少生成3个测试:正常路径、边界条件、异常路径
- 使用 pytest-asyncio 处理异步函数
- 数据库操作使用 AsyncMock,不连接真实数据库
- 测试数据使用 factory_boy 工厂类(参考 tests/factories.py 中的现有工厂)
只修改测试文件,不修改被测试的源文件。"
done
- name: Run generated tests to verify they pass
run: |
pytest tests/services/ -v --tb=short -x 2>&1 | tee /tmp/test_results.txt
- name: Create PR with generated tests
if: success()
run: |
git config user.name "Codex Bot"
git config user.email "codex-bot@yourcompany.com"
BRANCH="codex/auto-tests-$(date +%Y%m%d-%H%M%S)"
git checkout -b $BRANCH
git add tests/
git commit -m "test: 自动生成 $(date +%Y-%m-%d) 新增函数的单元测试 [skip ci]"
git push origin $BRANCH
gh pr create \
--title "🤖 自动生成缺失的单元测试" \
--body "$(cat /tmp/test_results.txt)" \
--base main \
--head $BRANCH \
--label "automated,tests"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}四、工作流三:依赖升级影响分析
当 Dependabot 提交依赖升级 PR 时,Codex 自动分析升级的破坏性变更并给出影响评估:
name: Codex Dependency Impact Analysis
on:
pull_request:
paths:
- 'requirements*.txt'
- 'package*.json'
- 'Pipfile'
- 'pyproject.toml'
jobs:
impact-analysis:
if: github.actor == 'dependabot[bot]'
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: '22'
- run: npm install -g @openai/codex
- name: Analyze dependency changes
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: |
# 获取依赖变更内容
git diff origin/main...HEAD -- requirements*.txt package*.json \
> /tmp/dep_changes.txt
codex \
--approval-mode suggest \
--sandbox read-only \
"分析以下依赖版本变更(/tmp/dep_changes.txt),然后扫描本项目代码库:
1. 列出升级的包名和版本号
2. 根据 CHANGELOG 或已知破坏性变更,分析是否存在 Breaking Change
3. 搜索项目代码中使用了这些包的哪些 API
4. 判断这些 API 在新版本中是否有变化
5. 给出升级风险评级:Low/Medium/High
6. 如果风险为 Medium 或 High,列出需要修改的文件和具体位置
最终输出一份简洁的中文影响评估报告。" \
> /tmp/impact_report.txt
- name: Comment impact report on PR
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const report = fs.readFileSync('/tmp/impact_report.txt', 'utf8');
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `## 🔍 Codex 依赖升级影响分析\n\n${report}`,
});五、成本控制策略
在 CI 中使用 Codex 会产生 API 费用,以下是控制成本的关键措施:
| 策略 | 实现方式 | 节省比例 |
|---|---|---|
| 跳过大 diff | diff 超过阈值(如 500 行)时跳过 Codex | 节省 ~30% |
| 路径过滤 | 只在核心代码路径变更时触发 | 节省 ~50% |
| 限制触发分支 | 只在 main/develop 分支或包含特定标签的 PR 上运行 | 节省 ~40% |
| 设置 API 用量上限 | 在 OpenAI Platform 设置每日/每月用量 Alert | 防止失控 |
| 使用较小模型 | CI 场景使用 gpt-5-codex-mini(假设有),精度略低但成本更低 | 节省 ~60% |
| 缓存结果 | 相同 diff 的审查结果缓存 24 小时 | 避免重复调用 |
# 在 workflow 中加入成本控制
- name: Check diff size before running Codex
id: check-size
run: |
LINES=$(git diff origin/${{ github.base_ref }}...HEAD | wc -l)
echo "diff_lines=$LINES" >> $GITHUB_OUTPUT
if [ "$LINES" -gt 800 ]; then
echo "skip=true" >> $GITHUB_OUTPUT
echo "::warning::Diff too large ($LINES lines), skipping Codex to control API cost."
fi
- name: Run Codex (conditional)
if: steps.check-size.outputs.skip != 'true'
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: |
codex ...六、在香港VPS上运行长时任务
对于耗时超过 GitHub Actions 6 小时限制的大规模迁移任务(如全量代码迁移、大型重构),推荐在 VPS 上直接运行,配合 tmux 保持会话:
# 在 VPS 上启动持久 tmux 会话
tmux new-session -d -s codex-migration
# 在 tmux 中运行大型迁移任务
tmux send-keys -t codex-migration \
'cd ~/my-project && codex --approval-mode full-auto \
--sandbox workspace-write \
"将项目中所有 datetime.utcnow() 替换为 datetime.now(timezone.utc),
这是 Python 3.12 的弃用警告修复,需要修改所有涉及文件并更新对应测试"' \
Enter
# 从任何地方查看任务进度
tmux attach-session -t codex-migration
# 任务完成后查看变更摘要
git diff --stat HEAD七、总结
将 Codex CLI 集成到 CI/CD 流水线,是将 AI 编程能力从个人工具升级为团队基础设施的关键一步。PR 自动审查、测试自动生成、依赖影响分析三个工作流可以直接落地,为团队节省大量重复性的人工工作。