CI中golangci-lint失败八成是环境配置未对齐:.golangci.yml须放go.mod目录、用空格缩进;GO111MODULE必须显式设为on;Go版本建议固定为1.21.10以上;golangci-lint版本需锁死(如v1.54.2);输出格式CI必须用--out-format=github-actions。

CI 中跑 golangci-lint 失败,八成不是代码问题,而是配置没对齐 —— 特别是 .golangci.yml 位置、go version、golangci-lint 版本这三项,错一个就白跑。
为什么本地不报错,CI 却失败?
最常见三类环境差异:
-
GO111MODULE:CI 默认可能为off,导致go list -deps找不到模块,报package xxx is not in GOROOT;必须显式设为on -
go version:staticcheck在 Go 1.20 以下对泛型支持不稳定,可能 panic 或漏报;CI 脚本里要用actions/setup-go@v6固定版本(如1.21.10) -
golangci-lint版本漂移:用latest或没锁版本,某天升级后规则行为突变(比如SA1019从 warning 变 error);必须写死版本号,例如v1.54.2
如何让 CI 只检查新改动的代码?
全量扫描既慢又掩盖问题,PR 场景下应聚焦变更。但别用 git ls-files -m | xargs golangci-lint run —— 空输入时 xargs 直接退出非零码,CI 就挂了。
- 推荐用
--new-from-rev:CI 系统通常会传入基线 commit(如$BASE_SHA),命令写成golangci-lint run --new-from-rev=$BASE_SHA - 避免依赖
HEAD~1:合并 PR 时 base 分支可能已更新,HEAD~1指向的不是你期望的 diff 基线 - 注意前提:工作区必须干净,且
$BASE_SHA必须可达(GitHub Actions 的pull_request事件中,github.base_ref+github.event.pull_request.base.sha可构造可靠基线)
CI 中该不该启用 --fix?
不该。CI 是验证环节,不是修改环节。
立即学习“go语言免费学习笔记(深入)”;
-
--fix会自动重排 import、补空行、删未使用变量等,触发文件内容变更 - 一旦改了源码,就会引起二次构建(尤其在 push 触发流水中),形成循环
- 格式修复应该由 pre-commit hook 或 IDE 自动完成,CI 只负责“断言”结果是否符合规范
- 如果真想自动修正,应在 PR 流水线末尾加个独立 job,只在
pull_request且event.action == 'opened'时运行--fix并提交 bot commit,而非混进 lint job
输出格式怎么配才真正有用?
日志里刷几十行错误没意义,关键是要让开发者一眼看到哪行、什么问题、怎么改。
- GitHub Actions 必须用
--out-format=github-actions:它会把每条 issue 转成 GitHub Annotation,直接标在 PR 文件 diff 行旁 - 别信默认格式 ——
text或json在 CI 日志里根本没法快速定位 - 如果同时对接其他平台(如 GitLab),不要在
.golangci.yml里硬编码out-format,而是在 CI 脚本里通过args参数传入,保持配置文件通用 - 本地开发可配
--fix+--out-format=colored-line-number,CI 则禁用--fix、强制--out-format=github-actions
最容易被忽略的是:.golangci.yml 必须放在 go.mod 所在目录,而不是仓库根或 .github/workflows 下;缩进必须是空格,不能是 Tab;IDE 缓存旧配置后不会自动 reload,改完得手动触发 “Reload golangci-lint config”。


















