go项目github actions需配置setup-go指定版本、缓存go.mod/go.sum、分离竞态测试、交叉编译清理dist、用action-gh-release推送到releases,并设置goprivate处理私有模块。

Go项目怎么写 GitHub Actions 的 .yml 文件
Go 项目 CI 最常用的是 GitHub Actions,关键不是“能不能跑”,而是“要不要缓存模块”“测试要不要并发”“交叉编译要不要开”。默认模板容易漏掉 go mod download 缓存和 GOPATH 隔离,导致每次重下依赖、耗时翻倍。
- 必须加
actions/setup-go,且指定go-version(如'1.21'),别用stable——它不更新,CI 会卡在旧版 - 用
cache步骤缓存$HOME/go/pkg/mod,key 建议含go.sumhash,否则go.mod没变但go.sum变了也会误命中 -
go test -race要单独开一个 job,别和单元测试混跑——竞态检测本身慢,还可能掩盖真实失败 - 避免在 CI 中执行
go install到全局,改用go build -o ./bin/app输出到项目内,路径可控、无权限风险
Go 编译产物怎么自动推送到 GitHub Releases
手动打包上传二进制太原始,GitHub Actions 能自动完成,但容易卡在“没权限”或“文件名重复”。核心是用 softprops/action-gh-release,它只认 ./dist/* 下的文件,且要求 GITHUB_TOKEN 有 packages: write 权限(默认 workflow token 已带)。
- 交叉编译前先清理:用
rm -rf ./dist,否则上次残留文件会被一起发上去 - 跨平台构建要用
GOOS/GOARCH组合,比如GOOS=linux GOARCH=amd64 go build,别漏掉GOARM(ARMv7 需要) - 二进制文件名建议带
${{ matrix.goos }}-${{ matrix.goarch }},否则 Windows 和 Linux 版本都叫app,release 页面会覆盖 - 打 tag 必须用
git push --tags触发on: push: tags,别用 GitHub 页面手动建 tag——它不触发 workflow
go test 在 CI 里总超时或挂起怎么办
本地秒过,CI 里跑一半卡住,八成是测试里起了没关的 goroutine 或 HTTP server。Go 的 testing 包默认不设超时,而 CI runner 通常限制单 job 时长(GitHub 是 6 小时,但你等不起)。
- 所有
go test命令必须加-timeout 60s,别信“我这测试很快”——网络抖动、磁盘慢都会放大延迟 - HTTP 测试务必用
httptest.NewUnstartedServer+srv.Start+defer srv.Close,别直接http.ListenAndServe - 数据库测试用
testcontainers-go或内存 SQLite(file::memory:),别连真实 DB;若必须连,加-short跳过集成测试 - 检查是否用了
time.Sleep模拟等待——全换成sync.WaitGroup或channel,否则 CI 环境调度更不可控
私有模块(go.dev / gitlab)怎么让 CI 正确拉取
公司内部模块或 GitLab 私仓,在本地 go get 没问题,CI 却报 module not found,根本原因是 GOPROXY 默认只走公共代理,不走私有源,也不读 ~/.netrc。
- 在 workflow 开头加
go env -w GOPRIVATE=*.corp.example.com,gitlab.example.com,让 Go 跳过 proxy 直连 - GitLab 私仓需配
git config --global url."https://oauth2:${{ secrets.GITLAB_TOKEN }}@gitlab.example.com".insteadOf "https://gitlab.example.com" - 如果用 SSH 克隆(
git@gitlab...),CI runner 必须预装 SSH key,且known_hosts已录入,否则卡在 host verify - 别在
go.mod里硬写replace指向本地路径——CI 没那个目录,直接 fail
Go 的 CI/CD 不难,难点在环境隔离和权限链路:模块拉取、测试清理、二进制命名、token 作用域,每个环节断一环,整个流水线就静默失败。最常被忽略的是 go.sum 变更没触发缓存失效,以及 release 文件名没区分平台导致覆盖。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











