把项目做成像 frp 那样的多平台 Release
Mole 项目已经开源,打算把仓库在 GitHub Release 页面中发布各个平台的安装包/二进制(像 frp 那样),已经完成脚本,可参考.github/workflows/release.yml,这个用来记录实现过程与遇到的坑,便于自己回顾。
大致流程
- 查阅 GitHub Actions、goreleaser、actions/create-release、actions/upload-release-asset 等资料。
- 在仓库中写一个 matrix workflow,在 Windows / macOS / Ubuntu runner 上分别构建并打包。
- 修复构建中出现的依赖与环境差异问题。
- 将构建产物上传为 Release asset(先查找/创建 release,再上传各平台包)。
- 调试并保证上传在 Release 页面能看到各平台包。
今天遇到并解决的主要问题(按流程顺序)
Ubuntu 图形库版本不一致
- 问题:教程写的是 libwebkit2gtk 4.0,但在新版 Ubuntu runner 上只能安装 4.1。
- 处理:在 CI 的 apt 安装里兼容 4.0 和 4.1(尝试 4.1,或用
||逻辑兼容两种包名)。
wails3 安装地址写错导致安装失败
- 问题:
go install用错了模块路径,安装一直失败。 - 处理:修正为官方地址(例如
github.com/wailsapp/wails/v3/cmd/wails3@latest),并确保GOPATH/bin在 PATH 中。
- 问题:
wails3 的
-platform/-o参数在我的环境不可用- 问题:官方文档的参数在实际运行时报错或不生效(不能指定输出名)。
- 处理:不完全依赖 CLI 的跨平台参数,在对应 runner 上运行构建命令并从
bin/下输出文件打包;如有必要向 upstream 提交 issue。
macOS 的平台特有代码需要 build tag,而不是运行时判断
- 问题:以前用
runtime.GOOS在运行时判断,但某些符号在编译期就需要区分,需用 build tags 来包含 macOS 特有实现。 - 处理:添加带 build tags 的文件来实现平台相关逻辑(避免运行时缺失符号)。
- 问题:以前用
需要提前解压
resources/bin.zip(资源嵌入问题)- 场景:为避免本地误报或便于管理,部分资源以 zip 放在
resources/bin.zip,构建时需存在这些文件以便嵌入到二进制。 - 处理:在 workflow 中先解压到
resources/bin(使用|| true容错),保证构建可以访问这些资源。
- 场景:为避免本地误报或便于管理,部分资源以 zip 放在
Windows runner 在 bash 环境下没有
zip,并且 PowerShell 与 bash 命令差异- 问题:在 Windows 上执行
zip报command not found,并且有些调试命令(如ls -lh)在 PowerShell 不可用。 - 处理:把打包和调试脚本分为 Windows(使用 PowerShell 与
Compress-Archive)和非 Windows(bash +zip/tar)两套逻辑;Windows 的调试用Get-Item/Get-ChildItem。
- 问题:在 Windows 上执行
构建产物在 Actions 可见但不出现在 Release 页面(缺少上传到 Release 的步骤)
- 问题:
actions/upload-artifact会把文件保存在 Actions 界面,但不会显示在仓库的 Release 页面。 - 处理:新增步骤——先创建或查找对应 tag 的 release(可创建为 draft),然后在每个 matrix job 中用
actions/upload-release-asset上传各自平台的包到该 release 的 upload_url。
- 问题:
上传时出现
Validation Failed(already_exists)与权限问题- 问题:当 Release 已有同名 asset 时,API 会返回
already_exists。另外要确保 workflow 有写入 Release 的权限。 - 处理:在上传前用 API 列出 release 的 assets,若存在同名则先删除(用
actions/github-script调用 API 删除),再上传;在 workflow 中设置permissions: contents: write确保有权限。
- 问题:当 Release 已有同名 asset 时,API 会返回
其他细节与注意点
- 使用
actions/github-script时:脚本中不要再次require('@actions/core')等,因为该 action 会注入core、github、context等变量,重复声明会报错。 - 在每个 job 打包后加一个 debug 步骤(输出 PKG_PATH/PKG_NAME 并列出文件),确认文件路径与上传步骤一致。
upload-release-asset必须使用 create-release 返回的upload_url,并确保asset_path指向实际存在的文件。- Windows 的 PowerShell 步骤要用
pwsh壳,文件路径与环境变量写法与 bash 不同。 - 为了未来改名更方便,把包名模板抽成变量(例如 PROJECT_NAME、VERSION、platform),构建脚本按变量生成包名,这样以后改名只要改一处模板。
Github Action 要点
- create-release job:查找是否已有该 tag 的 release;若没有就创建为 draft(便于编辑),输出 upload_url 和 release_id。
- build matrix job:各自 runner 上构建 -> 检测
bin/下的输出 -> 生成包(命名包含项目名、平台、版本)-> Windows 用 PowerShell 打包,非 Windows 用 zip/tar -> 上传前删除同名 asset(如存在)-> 上传到同一 release。 - 示例包名格式(当前):
mole_darwin_arm64_v1.0.0.zip(PROJECT_NAME 固定为mole,VERSION 用${{ github.ref_name }})。
后续可优化方向
- 若希望更多自动化特性(checksum、签名、Homebrew、snap、自动发布),考虑使用 goreleaser(对 Go 项目支持完善)。
- 保留 debug 步骤直到 workflow 稳定,再删除以节省日志与时间。
- 若担心覆盖历史 assets,可改包名策略(例如把版本放在前或加时间戳),或者在上传时保留旧资产并上传新名字。
- 如果 Wails CLI 在不同版本行为不同,关注 upstream issue 或官方示例,必要时固定 CLI 版本并在 CI 中使用该版本以避免不可预期改变。
小结
把 CI 做成能在 Release 页面自动产出多平台包并不简单:需要处理构建工具差异、runner 环境差异(依赖/压缩工具/PowerShell vs bash)、Release API 的并发与重名问题。今天的重点是把“分平台打包、单次创建/复用 release、上传前处理同名 asset”这三点做稳,琐碎但可复用,记录下来方便以后回顾与改进。