4.3CI/CD流水线格式校验


4.3 CI/CD 流水线格式校验

CI 是最终防线

编辑器保存时格式化和 Git pre-commit hooks 共同构成了前两层防线。但它们都有各自的漏洞:编辑器格式化依赖个人配置,Git hooks 可以被 git commit --no-verify 绕过。

CI/CD 流水线中的 Prettier 检查是不可绕过的最终防线。无论代码通过什么路径进入仓库(正常提交、强制推送、网页编辑、第三方 bot),CI 都会检查它。

GitHub Actions 配置

在 GitHub Actions 中添加 Prettier 检查步骤:

# .github/workflows/ci.yml name: CI on: [push, pull_request] jobs: format-check: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: "20" cache: "npm" - run: npm ci - run: npx prettier --check .

这个工作流在每次 push 和 PR 时运行。prettier --check . 检查所有文件,如果有任何文件格式不符合,退出码为 1,CI 任务失败。

GitLab CI 配置

# .gitlab-ci.yml format_check: image: node:20 script: - npm ci - npx prettier --check . cache: key: npm-deps paths: - node_modules/

处理 CI 失败

当 Prettier 检查失败时,CI 会输出未格式化文件的列表。开发者看到后,在本机运行:

npx prettier --write . git add . git commit --amend git push

如果项目用了 lint-staged,且失败是因为某个 PR 中的文件未格式化,只需要修改那些特定文件,不需要全量格式化:

npx prettier --write src/affected-file.js git add src/affected-file.js git commit --amend --no-verify # 只修改已提交的文件,不需要再跑 hooks git push

优化 CI 性能

对于大项目,prettier --check . 可能比较慢——每个文件都需要解析和检查。以下是几个优化手段:

只检查变更文件。在 PR 场景中,只检查 PR 中修改的文件,而不是全量文件。

- name: Get changed files id: changed uses: tj-actions/changed-files@v42 with: files: | *.{js,jsx,ts,tsx,css,json,md,yml} - name: Check formatting if: steps.changed.outputs.any_changed == 'true' run: npx prettier --check ${{ steps.changed.outputs.all_changed_files }}

缓存 node_modules。每次 CI 都重新安装依赖会浪费时间。使用缓存机制(GitHub Actions 的 actions/cache,GitLab CI 的 cache 关键字)来缓存 node_modules

并行化。如果仓库特别大,可以把文件按类型或目录分组,用多个 job 并行检查:

jobs: check-js: steps: - run: npx prettier --check "src/**/*.{js,jsx,ts,tsx}" check-other: steps: - run: npx prettier --check "**/*.{css,json,md,yml}"

CI 中的 Prettier 版本锁定

CI 环境中的 Prettier 版本必须与开发者本机的版本一致,否则可能出现"本机格式化通过但 CI 报错"的情况。

通过 npm ci(而不是 npm install)安装依赖,确保 CI 环境使用 package-lock.json 中锁定的精确版本。不要在 CI 中使用 npx prettier 而不先运行 npm ci——npx 可能会下载最新版本,跟 lock 文件中的版本不一致。

图 4-4:CI 中 Prettier 检查流程

常见失败原因

CI 里 Prettier 检查失败,原因通常集中在几类:

本机与 CI 的 Prettier 版本不一致。本机用 npm install 装了新版本,CI 用 npm ci 按锁文件装旧版本,两边输出可能不同。先确认 package-lock.json 已提交,且 CI 用 npm ci 而不是 npm install

配置文件没有提交.prettierrc.prettierignore.gitignore 误伤,导致 CI 拿到的是默认配置。检查这两份文件是否在版本控制里。

换行符差异。Windows 开发者提交的代码带 CRLF,Linux CI 按 LF 检查,导致全文件 diff。统一用 .editorconfiggit config core.autocrlf 解决。

自动生成文件被检查package-lock.json、构建产物、类型声明等自动生成的文件,格式通常由生成工具决定。把它们加入 .prettierignore,避免 CI 反复报错。

机器人提交与 PR 场景

仓库里除了人工提交,还有依赖机器人(自动升级依赖的工具)产生的提交。这类提交经常不经过 pre-commit hook,格式也没人维护,CI 检查就会挂掉。

处理办法有两类。一类是在 CI 里对机器人提交自动修复并回写:CI 失败后运行一个自动修复任务,执行格式化并提交结果,再触发一次检查,用 GitHub Actions 的 workflow_run 或 GitLab CI 的 pipeline trigger 都能实现。另一类是对特定作者跳过格式检查——不推荐,等于在防线上开了口子,格式问题会越积越多。

Monorepo 与多包仓库

Monorepo 里每个包可能都有自己的 .prettierrc。CI 检查时要注意根目录配置与子包配置的关系:Prettier 按文件所在目录向上查找配置文件,所以不同包用不同配置是正常的。全量检查命令 npx prettier --check . 会为每个文件找到正确的配置,不用额外处理。

但如果某次重构改了根目录的共享配置,可能引发大量包的格式变化。建议这类变更单独提交,避免和功能改动混在一起,让 diff 可审查。

图 4-5:CI 阶段分层与格式校验前置

图 4-5:CI 阶段分层与格式校验前置

这种分层设计节省 CI 资源——格式问题导致的失败在最早的阶段就被发现和阻断,不会浪费后续测试和构建的计算时间。

特殊场景:只格式化而不断开 CI

某些项目在初始化 Prettier 时,可能大量文件还未格式化,此时开启 CI 检查会阻断所有 PR。一个过渡方案是:CI 中用 --write 而不是 --check,并提交格式化结果。

- name: Format and commit run: | npx prettier --write . git config user.name "ci-bot" git config user.email "ci-bot@example.com" git add . git diff --cached --quiet || git commit -m "style: auto-format with Prettier"

这种方式让 CI bot 自动提交格式化结果,不阻断开发者的 PR。等全量代码都格式化完毕后,再把 CI 切换为 --check 模式。

与其他 CI 检查的顺序

Prettier 检查通常应该排在 CI 流水线的前面——它运行速度快、失败信息明确、修复方法简单。如果 Prettier 检查都不过,更耗时的测试和构建也不需要跑了。

jobs: lint: # Prettier + ESLint 检查,先跑 steps: - run: npx prettier --check . - run: npx eslint src/ test: needs: lint # lint 通过后才跑测试 steps: - run: npm test build: needs: test # 测试通过后才构建 steps: - run: npm run build

这种分层设计节省了 CI 资源——格式问题导致的失败在最早的阶段就被发现和阻断,不会浪费后续测试和构建的计算时间。

CI 检查是 Prettier "无感自动化"的第三层,也是最后一层。它不依赖任何人的自觉性或配置正确性——只要代码进了仓库,CI 就会检查。三层保障叠加在一起,格式不一致的问题在工程上几乎不可能发生。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U