关于 devops-pipeline
devops-pipeline 是为项目配置质量门禁的技能,将检查分配到本地钩子和 GitHub Actions。它优先在本地运行快速检查,并将多版本、依赖密钥或部署等任务留给 CI。
主要功能
- 01将检查分配到 pre-commit、pre-push 和 CI
- 02配置格式、Lint、类型、安全与测试检查
- 03为 CLI 命令添加端到端测试
- 04创建精简的 GitHub Actions 工作流
- 05安装前验证并试运行钩子
- 06报告失败而不绕过检查
适用场景
- 01为软件仓库设置质量门禁
- 02将 CLI 端到端测试加入 pre-push
- 03减少本地钩子与 CI 的重复检查
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ luongnv89/ skills --skill devops-pipeline安装后在 Claude Code 中输入/devops-pipeline确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
docs/README.mdevals/evals.jsonreferences/cli-e2e.mdfinal-report.mdgithub-actions.mdprecommit-configs.md详细介绍
DevOps 流水线
根据项目类型实施全面的 DevOps 质量门禁,并采用左移理念:尽可能多地通过 pre-commit 在本地运行检查,让开发者快速获得反馈,而 CI 充当安全网,而不是主要门禁。
核心原则:凡是能在开发者机器上运行的检查,都应在本地运行。GitHub Actions 只运行笔记本电脑确实无法完成的任务——版本矩阵测试、依赖密钥的扫描、覆盖率发布、部署——再加上一项成本低廉的作业,用来确认钩子没有被绕过。
检查路由表
每项检查必须且只能归入一个通道。此表是唯一事实来源:工作流第 2 和第 3 步、参考文件以及本技能生成的任何配置都必须与之保持一致。
| 通道 | 时间预算 | 在此运行的内容 |
|---|---|---|
pre-commit 阶段(每次提交) | < 10s,仅检查变更文件 | 格式化、lint、类型检查、离线安全扫描、快速单元测试、编译/导入检查 |
pre-push 阶段(每次推送) | < 60s,检查整个仓库 | 完整测试套件、CLI E2E、覆盖率阈值、耗时较长的 lint 规则集 |
| GitHub Actions | 按分钟计费 | 版本矩阵、依赖密钥的扫描、覆盖率上传、部署/发布、绕过防护 |
如果某项检查适合更早的通道,就不得在后续通道重复执行。CI 在每次推送时重新运行整套钩子,正是本技能要避免的问题。
为控制 Agent 的上下文预算,本 SKILL 保持模板简短,并链接到 references/*.md,其中包含特定语言的配置、工作流模板和 CLI E2E 脚本。
编辑前同步仓库(必须执行)
在现有仓库中创建、更新或删除文件之前,先将当前分支与远程同步:
branch="$(git rev-parse --abbrev-ref HEAD)"
git fetch origin
git pull --rebase origin "$branch"
如果工作区不干净,先暂存更改,再同步,最后恢复:
git stash push -u -m "pre-sync"
branch="$(git rev-parse --abbrev-ref HEAD)"
git fetch origin && git pull --rebase origin "$branch"
git stash pop
如果缺少 origin、无法拉取,或 rebase/暂存时发生冲突,请停止并先询问用户。
安全准则
此技能会向他人的仓库写入配置并安装 git 钩子。请遵守以下所有要求:
- 绝不覆盖现有的
.pre-commit-config.yaml或.github/workflows/*.yml。 如果目标文件已存在,请按以下流程合并:- 将文件复制为
<file>.bak。 - 准备合并后的内容。保留用户定义的钩子、作业和固定的
rev:值。 - 向用户展示
<file>.bak与合并后内容之间的差异。 - 如果用户确认,则写入合并后的文件。如果用户拒绝,则保持原文件不变,并记录此次合并已被拒绝。
- 在用户确认写入结果之前,保留
<file>.bak。
- 将文件复制为
- 写入任何新文件前,先向用户展示。 将新的
.pre-commit-config.yaml或工作流作为差异呈现。不得写入用户尚未查看过的文件。 - 安装钩子前先验证并试运行。 第 2 步应在
pre-commit install之前运行pre-commit validate-config和pre-commit run --all-files,以便在不阻止任何提交的情况下发现问题。 - 安装前检查是否已有 git 钩子。
pre-commit install会将外部钩子移至.git/hooks/<hook>.legacy并以迁移模式运行,从而保留该钩子。绝不要传入-f/--overwrite,因为这会悄然移除该钩子。如果用户希望删除外部钩子,必须先取得明确确认。 - 绝不代表用户运行
git commit --no-verify或git push --no-verify。 钩子失败是需要报告的问题,而不是需要绕开的障碍。 - 呈现失败,不要压制失败。 不要将钩子 id 添加到
SKIP、放宽 lint 规则或降低覆盖率阈值来让运行变绿。报告失败并由用户决定如何处理。 - 不要猜测,应停止操作:如果无法检测出技术栈、缺少
pre-commit或缺少origin,请参阅“边缘情况”中的相应说明。
工作流
1. 分析项目
检测项目特征:
# Check for package files and configs
ls -la package.json pyproject.toml Cargo.toml go.mod pom.xml build.gradle *.csproj 2>/dev/null
ls -la .eslintrc* .prettierrc* tsconfig.json mypy.ini setup.cfg ruff.toml 2>/dev/null
ls -la .pre-commit-config.yaml .github/workflows/*.yml 2>/dev/null
识别:
- 语言:JS/TS、Python、Go、Rust、Java、C# 等。
- 框架:React、Next.js、Django、FastAPI 等。
- 构建系统:npm、yarn、pnpm、pip、poetry、cargo、go、maven、gradle
- 现有工具:已配置的代码检查器、格式化工具、类型检查器
- 这是一个 CLI 工具吗?——如果是,请列出所有命令/子命令(检查 README、
--help、click/argparse/cobra源码),以构建 E2E 测试套件
如果没有匹配的软件包清单,请在第 2 步之前询问用户使用的语言和构建系统。第 1 步完成的条件是:已记录语言、构建系统、现有工具、现有配置文件,以及 CLI 状态(包括命令列表)。
2. 配置 Pre-commit 钩子(尽可能扩大本地覆盖范围)
如果没有 pre-commit,请显示安装命令并停止——参见边缘情况。不要自动安装。
pip install pre-commit # or brew install pre-commit
如果 pre-commit 可用,请针对检测到的技术栈编写 .pre-commit-config.yaml。如果文件已存在,请使用 Safety Rails 合并流程。按语言划分的配置请参阅 references/precommit-configs.md。
pre-commit 阶段——每次提交时运行,在变更文件上耗时不超过 10 秒:
- 格式检查(Prettier、Black/Ruff、gofmt、rustfmt)
- 代码检查(ESLint、Ruff、golangci-lint、Clippy)
- 类型检查(tsc、mypy)
- 可离线运行的安全扫描(Bandit、cargo-audit、gosec、
detect-secrets) - 快速单元测试
- 构建/编译验证(尽早捕获导入错误和编译失败)
pre-push 阶段——每次执行 git push 时运行,耗时不超过 60 秒:
- 完整测试套件(单元测试 + 集成测试)
- 每个 CLI 命令的端到端测试(见下文)
- 覆盖率阈值检查
- 耗时较长的代码检查(完整的 golangci-lint 规则集)
仅在 GitHub Actions 中运行——笔记本电脑无法完成的任务:
- 矩阵版本测试(多个 Node/Python/Go 版本)
- 基于密钥的扫描(Snyk、需要令牌的 SAST 工具)
- 部署/发布工作流
- 将覆盖率上传到外部服务
- 需要干净 VM 的易失败或对环境敏感的测试
使用现代阶段名称。 pre-commit 3.2 将 commit 重命名为 pre-commit,将 push 重命名为 pre-push;旧名称在 4.x 中会发出弃用警告,并计划移除。始终使用新名称;对于仍使用旧名称的现有配置,请运行 pre-commit migrate-config。
CLI 端到端测试
如果项目是 CLI 工具,请创建 scripts/e2e_test.sh,逐一测试每个命令/子命令,以验证 CLI 能够端到端运行(而不只是成功编译)。将其接入 pre-push 阶段的 pre-commit。
命令发现模式、脚本模板和 pre-commit 钩子代码片段请参阅 references/cli-e2e.md。
按以下顺序验证配置、试运行,然后安装钩子:
- 运行
pre-commit validate-config .pre-commit-config.yaml。如果退出状态非零,请报告错误并停止,不要安装任何钩子。 - 运行
pre-commit run --all-files。此试运行会执行提交阶段的钩子,但不会安装钩子。将每个失败的钩子 ID 记录为一项发现。 - 在
git rev-parse --git-path hooks输出的目录中检查pre-commit和pre-push(该目录不一定是.git/hooks)。如果其中任一文件已存在,且不包含File generated by pre-commit,请告知用户该文件将被移至<hook>.legacy。 - 运行
pre-commit install。 - 运行
pre-commit install --hook-type pre-push。仅运行pre-commit install不会安装 pre-push 钩子。
git commit --no-verify 和 git push --no-verify 会跳过所有钩子,本地无法阻止这种情况。第 3 步中的 CI 绕过防护可确保这些门禁仍然有效——精简 CI 时不要移除它。
3. 创建 GitHub Actions 工作流(精简 CI)
如果不存在工作流,请编写 .github/workflows/ci.yml。如果已存在,请使用 Safety Rails 合并流程,并在差异中将每个与钩子重复的现有步骤列为建议删除项。只有用户确认后,才能删除步骤。保持 CI 精简:钩子已经在本地运行了所有检查,因此 CI 只需覆盖路由表中的第三条通道,再加上一项防护。工作流模板请参阅 references/github-actions.md。
CI 只运行以下四类任务:
- 绕过防护——针对拉取请求的差异重新运行两个钩子阶段,耗时以秒计,而不是以分钟计。这是唯一一次与 pre-commit 有意重叠的情况,因为
--no-verify会让本地检查变成可选项。 - 版本矩阵——唯一确实需要多个运行器的通道。
- 依赖密钥的任务——需要使用笔记本电脑不应持有的令牌进行扫描和上传。
- 部署 / 发布——合并到默认分支时运行。
完整的绕过防护如下:
hooks:
name: Verify hooks were not bypassed
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
# ... set up the project toolchain and Python here ...
- name: Run both hook stages over the PR diff
run: |
pip install pre-commit
base="${{ github.event.pull_request.base.sha }}"
pre-commit run --from-ref "$base" --to-ref HEAD
pre-commit run --hook-stage pre-push --from-ref "$base" --to-ref HEAD
以下四个细节至关重要;缺少任何一个,任务首次运行时都会失败:
- 两条
pre-commit run命令。 第一条只执行提交阶段的钩子——完整测试套件和 CLI E2E 测试在pre-push阶段运行,没有第二条命令就会被静默跳过。pre-commit/[email protected]也有这个盲点,因此请直接调用 CLI。 fetch-depth: 0。actions/checkout默认以深度 1 克隆,因此找不到基准 SHA,--from-ref会因无效对象而失败。if: github.event_name == 'pull_request'。 对于push事件,分支首次推送时github.event.before全为零;强制推送后,该值也会过期。- 同一任务中的项目工具链。 声明为
language: system的钩子会调用npm、mypy、go或cargo。
不要让矩阵进入高频路径:仅在推送到默认分支或推送发布标签时运行,不要在每次 PR 提交时运行。每次推送都运行三版本矩阵,会让费用增加三倍,而本地钩子已经提供了相同信号。
4. 验证流水线
- 运行
pre-commit run --all-files。预期结果:退出码为 0。 - 运行
pre-commit run --all-files --hook-stage pre-push。预期结果:退出码为 0。第一条命令不会运行推送阶段的钩子(完整测试套件、E2E)。 - 如果项目是 CLI 工具,运行
bash scripts/e2e_test.sh。预期结果:退出码为 0。 - 如果命令以非零值退出,请将失败的钩子 ID 及其输出记录为一项发现。不要修改配置、添加
SKIP,也不要降低阈值来让它通过。
当每条命令的退出码都已记录时,步骤 4 即完成。此处不运行步骤 3 中的工作流;它会在下一次拉取请求中首次于 GitHub 上运行。
编写最终报告
在最后一份 Step Completion Report 之后,按照 references/final-report.md 输出最终报告:先写 Result:(COMPLETE、PARTIAL — reason 或 BLOCKED — reason),然后写 Evidence:(仅列出已运行的命令及其退出码)、Uncertainty:(始终注明未运行的 CI 工作流),最后写 Decision:(待审批事项,或 No approval needed.)。仅审计运行也使用相同的报告。
按语言选择工具
| 语言 | 格式化工具 | 代码检查工具 | 类型检查 | 安全 | 测试 |
|---|---|---|---|---|---|
| JS/TS | Prettier | ESLint | tsc | npm audit | Jest/Vitest |
| Python | Ruff/Black | Ruff | mypy | Bandit + detect-secrets | pytest |
| Go | gofmt | golangci-lint | 内置 | gosec | go test |
| Rust | rustfmt | Clippy | 内置 | cargo-audit | cargo test |
| Java | google-java-format | Checkstyle | - | SpotBugs | mvn test |
这些检查分别属于哪条通道,已由上文的检查路由表固定——不要在此重新划分检查项。
预期输出
运行此技能后,仓库应包含:
.pre-commit-config.yaml— 在pre-commit阶段进行格式化、代码检查、类型检查和快速单元测试;在pre-push阶段运行完整测试套件、覆盖率阈值检查和端到端测试。.github/workflows/ci.yml— CI 仅承担第 3 步中的四项职责:按差异范围执行绕过检查、版本矩阵、依赖密钥的工作、部署。不得包含独立的代码检查、格式化、类型检查或测试步骤,以免与钩子重复。scripts/e2e_test.sh(仅 CLI 项目)— 可执行脚本,用于测试每个 CLI 命令和子命令。- 最终报告,格式参见 references/final-report.md。
Python 项目的 .pre-commit-config.yaml 片段示例:
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.4.4
hooks:
- id: ruff
stages: [pre-commit]
- id: ruff-format
stages: [pre-commit]
- repo: local
hooks:
- id: mypy
name: mypy type check
entry: mypy src/
language: system
stages: [pre-commit]
- id: pytest-fast
name: fast unit tests
entry: pytest tests/unit -x -q
language: system
stages: [pre-commit]
- id: pytest-full
name: full test suite
entry: pytest --cov=src --cov-report=xml
language: system
stages: [pre-push]
验收标准
满足以下所有条件即表示运行通过:
- 仓库根目录中存在
.pre-commit-config.yaml,且其中至少包含一个针对检测到的主要语言的钩子(格式化工具、代码检查工具或类型检查工具)。 - 每项检查恰好归属检查路由表中的一个阶段:
.pre-commit-config.yaml中的钩子id不得出现在绕过检查以外的工作流run:步骤中;任何可在笔记本电脑上运行的检查都不得仅在 CI 中运行。 - 钩子的
stages:使用现代名称(pre-commit、pre-push、manual);生成的配置不得使用已弃用的commit或push。 - 已安装两种钩子类型:
pre-commit install和pre-commit install --hook-type pre-push。 - 至少存在一个
.github/workflows/*.yml文件,且该文件仅承担第 3 步中的四项 CI 职责。 - CI 与 pre-commit 唯一重叠之处是绕过检查;该检查按差异范围执行(
--from-ref/--to-ref),且会运行两个阶段。 -
pre-commit run --all-files和pre-commit run --all-files --hook-stage pre-push均成功(若失败,必须明确告知用户,不得自动隐藏)。 - 对于 CLI 项目,端到端测试脚本已按照语言参考文件接入
pre-push阶段。 - 最终报告通过 references/final-report.md 中的四项读者检查:结果写在第一行,已验证事实与假设分开,每项说明均注明对应命令或文件,并指出下一步需要作出的决定。未收到用户反馈时,不得确认人工理解已达成。
边缘情况
- 未检测到包管理器:生成钩子前询问用户使用的语言和构建系统;绝不默默猜测。
- 未安装 Pre-commit:显示安装命令(
pip install pre-commit或brew install pre-commit)并停止;不得自动安装或生成配置文件。 - 已存在
.pre-commit-config.yaml:将新钩子合并到现有文件,而不是覆盖;保留用户定义的钩子和固定的 rev。 - 包含多种语言的 Monorepo:生成单个配置文件,并按语言设置钩子区块和
files:路径过滤器,使钩子仅在相关子目录中运行。本地language: system条目也必须指定软件包目录(npm --prefix frontend、pytest backend/tests)——files:仅用于筛选会触发钩子的文件,不会改变当前工作目录。 - 没有
origin远程仓库:停止并询问用户是否接受仅本地、不与仓库同步的设置;不得自动继续。 - 测试耗时超过 60 秒:将其降至下一个阶段——从
pre-commit降至pre-push,或从pre-push降至 CI,并在钩子注释中记录原因,让后续读者知道这是测量所得,而非猜测。 - 使用已弃用阶段名称的旧配置:先运行
pre-commit migrate-config,再合并新钩子,避免文件处于部分迁移状态。 - 团队使用
--no-verify绕过钩子:本地门禁无法阻止此行为。保留 CI 绕过检查,并报告绕过率,而不是添加更多钩子。 - 仅支持 Windows 的仓库:替换为兼容 PowerShell 的钩子条目,并标出任何 Unix 专用命令。
步骤完成报告
每完成一个主要步骤后,按以下格式输出状态报告:
◆ [Step Name] ([step N of M] — [context])
··································································
[Check 1]: √ pass
[Check 2]: √ pass (note if relevant)
[Check 3]: × fail — [reason]
[Check 4]: √ pass
[Criteria]: √ N/M met
____________________________
Result: PASS | FAIL | PARTIAL
根据步骤实际验证的内容调整检查项名称。通过使用 √,失败使用 ×,添加简要说明使用 —。“Criteria”行总结符合了多少项验收标准。“Result”行给出总体结论。
各阶段专属检查项
阶段:项目分析 — 检查项:项目检测、现有工具扫描、CLI 检测、命令枚举
阶段:Pre-commit 配置 — 检查项:Pre-commit 设置、已安装提交阶段钩子、已安装推送阶段钩子、使用现代阶段名称、已创建 E2E 脚本(如果是 CLI)
阶段:GitHub Actions 设置 — 检查项:GitHub Actions 配置、CI 仅限四项职责、绕过防护同时运行两个阶段、矩阵未纳入每次提交路径
阶段:流水线验证 — 检查项:提交阶段钩子通过、推送阶段钩子通过、E2E 测试通过(如果是 CLI)、各通道没有重复检查
资源
- references/precommit-configs.md — 各语言的 pre-commit 配置,包含
pre-push测试和 E2E 钩子 - references/github-actions.md — GitHub Actions 模板:绕过防护、矩阵、部署
- references/cli-e2e.md — CLI 命令发现、E2E 脚本模板及其
pre-push钩子 - references/final-report.md — 最终报告内容、状态规则、示例和读者检查