gitlab ci流水线不触发90%因only/rules配置错误,应改用rules限定分支、变更目录及mr事件,并确保go111module=on、模块路径正确、临时目录权限适配、覆盖率报告格式匹配。

git push 后单元测试没跑?检查 .gitlab-ci.yml 的 only 和 rules 配置
CI 流水线不触发,90% 是因为 only 或 rules 写错了。GitLab 默认只对 master 或 main 分支生效,新功能分支(如 feat/login)默认被忽略。
常见错误写法:only: - master —— 这会彻底屏蔽所有非 master 分支的 pipeline。
正确做法(推荐用 rules):
test_job:
stage: test
script: go test ./...
rules:
- if: '$CI_PIPELINE_SOURCE == "push"'
changes:
- internal/**/*
- cmd/**/*
- if: '$CI_COMMIT_TAG'
-
changes限定只在相关目录变更时触发,避免每次改 README 都跑全量测试 - 不要依赖
only: - branches,它无法感知 PR 合并前的预检;rules支持if: $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME,更适合 feature 分支开发流 - 如果用 GitHub Actions,对应的是
on.push.branches+on.pull_request.branches两段配置,不能只写一个
go test 在 CI 中失败但本地通过?注意 GOPATH 和模块路径差异
本地 go test 成功不代表 CI 环境也能过。GitLab Runner 默认以干净容器启动,没有 $GOPATH 缓存,且 Go 模块路径解析行为更严格。
典型报错:cannot find package "git-who/internal/tally" in any of...
原因和解法:
- 确保项目根目录有
go.mod,且GO111MODULE=on已设(GitLab CI 默认开启,但自建 Runner 可能未设) - 不要用相对路径 import,比如
import "./internal/tally"—— 这在模块模式下非法,必须用模块名,如import "git-who/internal/tally" - CI 中执行
go test前加一句go mod download,避免因网络波动导致依赖拉取超时失败 - 单元测试里硬编码的临时路径(如
/tmp/test-repo)在 CI 容器中可能无写权限,改用os.MkdirTemp("", "test-*")
feature 分支合并前如何强制跑集成测试?用 merge request pipeline + needs
光跑单元测试不够,git-who 这类 CLI 工具必须验证命令行交互、Git 仓库行为等真实场景。集成测试要放在 MR(Merge Request)阶段跑,而不是等合入 main 后才执行。
关键配置点:
- 在
.gitlab-ci.yml里定义integration_job,并设置rules:匹配 MR:
integration_job:
stage: test
script: rake test:integration
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- 用
needs:显式声明依赖关系,例如让集成测试等单元测试通过后再跑,避免浪费资源:
needs: ["test_job"]
- MR pipeline 默认不共享缓存和 artifacts,若集成测试需复用构建产物(如编译好的
git-who二进制),得加artifacts: [bin/git-who]并在集成 job 中用dependencies:拉取
测试覆盖率没进报告?别只信本地 go tool cover 输出
CI 中生成的覆盖率报告常为空或数值异常低,问题往往出在「覆盖范围」和「报告合并」上。
真实痛点:
-
go test -coverprofile=c.out默认只覆盖当前包,./...才递归所有子包 —— 但 CI 脚本里常漏掉... - 多个 job(如 unit / integration)各自生成
c.out,不合并就只有单个包数据 - GitLab 内置覆盖率解析器只认
^total:s*([0-9.]+)%$格式,而go tool cover -func输出是表格,得用go tool cover -func=c.out | tail -1提取最后一行
建议 pipeline 片段:
coverage_job:
stage: coverage
script:
- go tool cover -func=coverage/c.out | tail -1 > coverage.txt
coverage: '/total:\s*([0-9.]+)%/'
注意:这个正则只匹配标准输出末尾的 total 行,如果中间有 log 冲突,覆盖率会被 GitLab 忽略——所以务必把 go test 的 -v 关掉,或重定向 stderr。
分支开发中真正卡住团队的,从来不是“要不要测”,而是“测了但不知道信不信”。CI 配置一旦脱离实际分支策略和模块结构,测试就变成仪式性动作。尤其当 go test 在本地和 CI 表现不一致时,第一反应不该是改测试逻辑,而是确认环境变量、模块路径、临时目录权限这三件事是否对齐。











