跳转到内容

CI/CD 与发布流程:GitHub Actions 驱动的自动化管线

CI/CD 与发布流程:GitHub Actions 驱动的自动化管线

学习目标

本章要解决什么问题:一个包含 20+ 独立包的 Monorepo 如何高效运行测试、Lint 和发布,而不浪费 CI 资源?

读者将学到:

  • 变更检测驱动的 CI 管线设计
  • 独立包的发布流程
  • SHA 固定的 GitHub Actions 安全实践

前置知识

本章是 LangChain 特有的工程实践,不涉及通用知识原理。

项目实践

变更检测驱动的 CI

核心 CI workflow(check_diffs.yml)通过分析 Git 变更,只运行受影响包的测试和 Lint

实现方式

  1. Ana06/get-changed-files 获取变更文件列表
  2. 运行 .github/scripts/check_diff.py 分析哪些包被影响
  3. 输出 JSON 矩阵(lint/test/extended-tests 等),CI 只运行对应包的 job

效果:修改 libs/partners/openai/ 中的一个文件,不会触发 libs/partners/anthropic/ 的测试。

主 CI 工作流

check_diffs.yml 作为调度器,调用子 workflow:

子 Workflow职责
_lint.ymlRuff Lint 检查
_test.yml单元测试
_test_pydantic.ymlPydantic 兼容性测试
_compile_integration_test.yml集成测试编译检查
vcr_tests.ymlVCR HTTP 录制回放测试

并发控制

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

同一 PR 的多次 push 只保留最新的 CI 运行,取消冗余的中间任务。

独立包发布流程

发布 workflow(_release.yml)支持每个包独立发版:

# 手动触发,选择要发布的包
on:
workflow_dispatch:
inputs:
working-directory:
type: choice
options:
- core
- langchain
- langchain_v1
- text-splitters
- standard-tests
- model-profiles
- anthropic
- openai
- ...
release-version:
type: string
default: "0.1.0"

发布流程

  1. 选择目标包(通过 working-directory 下拉菜单)
  2. 输入新版本号
  3. Workflow 自动:
    • 更新 pyproject.toml 中的版本号
    • 构建 wheel/sdist
    • 发布到 PyPI
    • 创建 Git tag

命名映射:某些目录名与 PyPI 包名不一致:

  • langchainlangchain-classic
  • langchain_v1langchain
  • standard-testslangchain-tests

PR 标题 Lint

pr_lint.yml 强制 PR 标题遵循 Conventional Commits 格式,确保每个提交都可机器解析:

  • type 必须是小写字母开头的预定义值(feat/fix/docs/style/refactor/perf/test/build/ci/chore/revert/release/hotfix)
  • scope 必须是预定义列表中的值(core/langchain/各 partner 名等)
  • Breaking changes 使用 ! 后缀

其他 CI 辅助流程

Workflow职责
auto-label-by-package.yml根据变更包自动添加 PR 标签
pr_labeler.yml自动为 PR 分类标记
require_issue_link.yml要求 PR 描述关联 Issue
block_fork_main_prs.yml阻止 Fork 向 main 分支创建 PR
bump_uv_pin.yml自动更新 uv 版本锁定
check_agents_sync.yml检查 Agent 相关文件同步状态
middleware_evals.yml中间件评估测试
codspeed.yml性能基准测试
reopen_on_assignment.ymlIssue 被分配时自动重新打开
close_unchecked_issues.yml关闭未检查的 Issue
tag-external-issues.yml标记外部 Issue

SHA 固定的 Actions

所有 GitHub Actions 使用 SHA 固定而非 tag/branch 引用:

uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
uses: Ana06/get-changed-files@25f79e676e7ea1868813e21465014798211fad8c # v2.3.0

安全意义:SHA 是不可变的,即使攻击者获取了 Action 仓库的写入权限,也无法将 SHA 指向恶意代码。

问题与规避

变更检测的准确性

问题check_diff.py 可能漏掉间接影响(如 Core API 变更影响所有 Partner)。

对策:脚本通过分析依赖关系,将 Core 的变更传播到所有依赖包。修改 libs/core/ 会触发所有 partner 包的测试。

发布流程的人为错误

问题:手动输入版本号可能出错。

对策:发布 workflow 要求明确输入版本号,并自动生成 commit message:release(scope): x.y.z。CI 的 pr_lint 确保格式正确。

Pre-release 依赖解析

问题:发布 prelease 版本时,transitive prerelease 依赖可能无法正确解析。

对策:发布 workflow 提供 allow-prereleases 选项,传递 --prerelease=allow 给 wheel-install 步骤。

设计取舍

变更检测 vs 全量运行

方案优势代价
变更检测大幅减少 CI 时间和资源需要维护检测脚本、可能漏掉间接影响
全量运行不会遗漏任何测试每次 PR 都运行所有测试,CI 时间过长

LangChain 选择变更检测,因为 20+ 独立包全量运行可能耗时数十分钟。通过依赖传播分析,Core 变更仍能触发所有下游测试。

SHA 固定 vs Tag 引用

方案优势代价
SHA 固定不可变、防供应链攻击需要手动更新 SHA、PR 难以判断版本新旧
Tag 引用自动跟随最新版本攻击者可替换 tag 指向恶意代码

LangChain 选择 SHA 固定 + 注释标注版本(如 # v6),兼顾安全性与可读性。

参考来源