mcpField
D
devops-pipeline

devops-pipeline

github.com/luongnv89云与 DevOps14185 次安装4 天前更新
代码仓库

关于 devops-pipeline

devops-pipeline 是为项目配置质量门禁的技能,将检查分配到本地钩子和 GitHub Actions。它优先在本地运行快速检查,并将多版本、依赖密钥或部署等任务留给 CI。

主要功能

  1. 01将检查分配到 pre-commit、pre-push 和 CI
  2. 02配置格式、Lint、类型、安全与测试检查
  3. 03为 CLI 命令添加端到端测试
  4. 04创建精简的 GitHub Actions 工作流
  5. 05安装前验证并试运行钩子
  6. 06报告失败而不绕过检查

适用场景

  1. 01为软件仓库设置质量门禁
  2. 02将 CLI 端到端测试加入 pre-push
  3. 03减少本地钩子与 CI 的重复检查

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/luongnv89/skills --skill devops-pipeline

安装后在 Claude Code 中输入/devops-pipeline确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

docs/
README.md
evals/
evals.json
references/
cli-e2e.md
final-report.md
github-actions.md
precommit-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。 如果目标文件已存在,请按以下流程合并:
    1. 将文件复制为 <file>.bak。
    2. 准备合并后的内容。保留用户定义的钩子、作业和固定的 rev: 值。
    3. 向用户展示 <file>.bak 与合并后内容之间的差异。
    4. 如果用户确认,则写入合并后的文件。如果用户拒绝,则保持原文件不变,并记录此次合并已被拒绝。
    5. 在用户确认写入结果之前,保留 <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。

按以下顺序验证配置、试运行,然后安装钩子:

  1. 运行 pre-commit validate-config .pre-commit-config.yaml。如果退出状态非零,请报告错误并停止,不要安装任何钩子。
  2. 运行 pre-commit run --all-files。此试运行会执行提交阶段的钩子,但不会安装钩子。将每个失败的钩子 ID 记录为一项发现。
  3. 在 git rev-parse --git-path hooks 输出的目录中检查 pre-commit 和 pre-push(该目录不一定是 .git/hooks)。如果其中任一文件已存在,且不包含 File generated by pre-commit,请告知用户该文件将被移至 <hook>.legacy。
  4. 运行 pre-commit install。
  5. 运行 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 只运行以下四类任务:

  1. 绕过防护——针对拉取请求的差异重新运行两个钩子阶段,耗时以秒计,而不是以分钟计。这是唯一一次与 pre-commit 有意重叠的情况,因为 --no-verify 会让本地检查变成可选项。
  2. 版本矩阵——唯一确实需要多个运行器的通道。
  3. 依赖密钥的任务——需要使用笔记本电脑不应持有的令牌进行扫描和上传。
  4. 部署 / 发布——合并到默认分支时运行。

完整的绕过防护如下:

  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. 验证流水线
  1. 运行 pre-commit run --all-files。预期结果:退出码为 0。
  2. 运行 pre-commit run --all-files --hook-stage pre-push。预期结果:退出码为 0。第一条命令不会运行推送阶段的钩子(完整测试套件、E2E)。
  3. 如果项目是 CLI 工具,运行 bash scripts/e2e_test.sh。预期结果:退出码为 0。
  4. 如果命令以非零值退出,请将失败的钩子 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/TSPrettierESLinttscnpm auditJest/Vitest
PythonRuff/BlackRuffmypyBandit + detect-secretspytest
Gogofmtgolangci-lint内置gosecgo test
RustrustfmtClippy内置cargo-auditcargo test
Javagoogle-java-formatCheckstyle-SpotBugsmvn test

这些检查分别属于哪条通道,已由上文的检查路由表固定——不要在此重新划分检查项。

预期输出

运行此技能后,仓库应包含:

  1. .pre-commit-config.yaml — 在 pre-commit 阶段进行格式化、代码检查、类型检查和快速单元测试;在 pre-push 阶段运行完整测试套件、覆盖率阈值检查和端到端测试。
  2. .github/workflows/ci.yml — CI 仅承担第 3 步中的四项职责:按差异范围执行绕过检查、版本矩阵、依赖密钥的工作、部署。不得包含独立的代码检查、格式化、类型检查或测试步骤,以免与钩子重复。
  3. scripts/e2e_test.sh(仅 CLI 项目)— 可执行脚本,用于测试每个 CLI 命令和子命令。
  4. 最终报告,格式参见 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)、各通道没有重复检查

资源

评论

支持 Markdown