Go generate 使用相对路径时为什么在 CI 找不到脚本
来源:17golang原创
时间:2026-11-14 02:23:58 199浏览 收藏
go generate 中生成器的工作目录是包含该指令的包源码目录,不是 CI 启动命令时的仓库根目录。例如指令放在 internal/catalog/generate.go,脚本位于根目录 scripts 下,那么应按 internal/catalog 计算相对路径。另需区分“脚本文件找不到”和“sh、python 等解释器不在 PATH”,两者修复方式不同。
官方文档:https://pkg.go.dev/cmd/go#hdr-Generate_Go_files_by_processing_source
先明确工具行为:从根目录启动也不会统一生成目录
go generate 扫描源码中的生成指令,显式执行对应命令。它不会因为 Go build 或 Go test 被调用就自动运行。这是工具既有的工作方式,不是一次新版本更改。
在 CI 中从仓库根目录执行 go generate ./...,只决定要选哪些包;每个包里的生成命令仍以各自源码目录为工作目录。若多个包共享同一个指令文本,相同的 ../ 层数不一定能指向同一文件。这也是“本地手工执行脚本成功,CI 生成失败”的常见解释方向。
适用场景:共享脚本与包内生成入口
以一个示例仓库为例,根目录有 go.mod 和 scripts/catalog-gen.sh,包目录 internal/catalog 中有 generate.go。脚本负责生成该包的 catalog_generated.go。这份布局没有要求 CI 使用固定绝对目录,因此可以在不同检出位置运行。
如果在 generate.go 写 sh scripts/catalog-gen.sh,解释器收到的是相对 internal/catalog 的路径,它会寻找该包下的 scripts 子目录。CI 再次 cd 到根目录,并不会改变生成器随后采用的工作目录。
快速试用:把脚本路径写成相对包目录
在 internal/catalog/generate.go 放置下面的包声明和指令。指令本身必须位于独立行,不能为了说明而拆成多行。
package catalog // 生成入口位于 internal/catalog;脚本参数以这个目录为基准。 //go:generate sh ../../scripts/catalog-gen.sh .
其中 ../../scripts 回到仓库根目录再进入 scripts;最后的点号是传给脚本的输出参数,此时代表 internal/catalog。脚本内容可以写成:
#!/bin/sh
# 本脚本要求工作目录为 internal/catalog,输出目录由第一个参数指定。
set -eu
target_dir="${1:?missing output directory}"
test -f ../../go.mod
test -d "$target_dir"
# 直接写入确定内容;正式项目可在这里调用自己的生成器。
cat > "$target_dir/catalog_generated.go"
这份脚本刻意约定从包目录执行,并检查预期的 go.mod 位置。它适合固定深度的包;如果包将来移动,指令和脚本中的相对基准都要一起调整。通过 sh 调用脚本不要求脚本本身有执行位,但需要 CI 提供兼容的 sh,且脚本文件可读取。

# 在仓库根目录执行指定包的生成,并显示实际执行的指令 go generate -x ./internal/catalog
按脚本定义,预期生成位置为 internal/catalog/catalog_generated.go;这里没有在本地执行示例或展示真实 CI 日志。诊断时应同时观察命令所选包、脚本收到的参数和实际产物位置。
和根目录脚本对比:同一个文件不等于同一个入口契约
| 入口 | 路径基准 | 需要约定 |
|---|---|---|
| 根目录手工执行 sh scripts/... | 当前shell目录 | 先进入哪个目录 |
| 包内 go:generate | 该包源码目录 | 脚本相对路径和输出参数 |
| 脚本主动切换目录 | 脚本切换后的目录 | 输入输出路径是否也随之变化 |
需要让脚本同时支持多个入口时,可明确传入输入与输出位置,或者由脚本自己定位所需目录。不要一边改变脚本工作目录,一边仍把点号当成调用方目录。也不建议把个人机器的绝对路径写进生成指令。
采用前要确认:入口、解释器和脚本参数分别排查
先看错误报告的是哪个文件。若提示可执行命令不在 PATH,检查 CI 是否安装了解释器或生成器;若解释器报告 cannot open 某个脚本,检查的是脚本路径及检出内容。直接执行脚本时报权限或解释器相关错误,还要查看文件执行位、首行解释器路径及换行格式。
go generate 不会自动提供完整 shell 语法。通配、管道和重定向不能直接按交互 shell 的方式写在指令尾部期待它解释;需要这些能力时,显式选择 shell,或将逻辑留在脚本内。环境变量替换也有工具自身的处理规则,嵌套 shell 时不应凭引号外观猜测最终参数。

最后检查脚本、模板及生成器源码是否真正提交并检出。开发机上被忽略的文件不会自动出现在 CI;仅调整 working-directory 无法补回缺失文件。生成步骤也应放在需要生成产物的构建步骤之前,而不是假定 build 会代为执行。
在 CI 设置 working-directory 为仓库根目录还有作用吗?
有,它影响命令启动及包路径解析,但不替代生成器按包目录运行的规则。
为什么同一指令在另一个包里失效?
包所在深度不同,相对脚本路径就不同。共享脚本需要明确支持哪些调用目录。
本地有生成器,CI 没有怎么办?
在 CI 明确准备生成工具及版本,或采用仓库可获得的生成器入口;不要依赖个人环境中碰巧存在的 PATH。
-
502 收藏
-
502 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
214 收藏
-
498 收藏
-
245 收藏
-
418 收藏
-
322 收藏
-
481 收藏
-
328 收藏
-
407 收藏
-
482 收藏
-
298 收藏
-
391 收藏
-
247 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习