把项目做成像 frp 那样的多平台 Release

Mole 项目已经开源,打算把仓库在 GitHub Release 页面中发布各个平台的安装包/二进制(像 frp 那样),已经完成脚本,可参考.github/workflows/release.yml,这个用来记录实现过程与遇到的坑,便于自己回顾。


大致流程

  1. 查阅 GitHub Actions、goreleaser、actions/create-release、actions/upload-release-asset 等资料。
  2. 在仓库中写一个 matrix workflow,在 Windows / macOS / Ubuntu runner 上分别构建并打包。
  3. 修复构建中出现的依赖与环境差异问题。
  4. 将构建产物上传为 Release asset(先查找/创建 release,再上传各平台包)。
  5. 调试并保证上传在 Release 页面能看到各平台包。

今天遇到并解决的主要问题(按流程顺序)

  1. Ubuntu 图形库版本不一致

    • 问题:教程写的是 libwebkit2gtk 4.0,但在新版 Ubuntu runner 上只能安装 4.1。
    • 处理:在 CI 的 apt 安装里兼容 4.0 和 4.1(尝试 4.1,或用 || 逻辑兼容两种包名)。
  2. wails3 安装地址写错导致安装失败

    • 问题:go install 用错了模块路径,安装一直失败。
    • 处理:修正为官方地址(例如 github.com/wailsapp/wails/v3/cmd/wails3@latest),并确保 GOPATH/bin 在 PATH 中。
  3. wails3 的 -platform / -o 参数在我的环境不可用

    • 问题:官方文档的参数在实际运行时报错或不生效(不能指定输出名)。
    • 处理:不完全依赖 CLI 的跨平台参数,在对应 runner 上运行构建命令并从 bin/ 下输出文件打包;如有必要向 upstream 提交 issue。
  4. macOS 的平台特有代码需要 build tag,而不是运行时判断

    • 问题:以前用 runtime.GOOS 在运行时判断,但某些符号在编译期就需要区分,需用 build tags 来包含 macOS 特有实现。
    • 处理:添加带 build tags 的文件来实现平台相关逻辑(避免运行时缺失符号)。
  5. 需要提前解压 resources/bin.zip(资源嵌入问题)

    • 场景:为避免本地误报或便于管理,部分资源以 zip 放在 resources/bin.zip,构建时需存在这些文件以便嵌入到二进制。
    • 处理:在 workflow 中先解压到 resources/bin(使用 || true 容错),保证构建可以访问这些资源。
  6. Windows runner 在 bash 环境下没有 zip,并且 PowerShell 与 bash 命令差异

    • 问题:在 Windows 上执行 zipcommand not found,并且有些调试命令(如 ls -lh)在 PowerShell 不可用。
    • 处理:把打包和调试脚本分为 Windows(使用 PowerShell 与 Compress-Archive)和非 Windows(bash + zip/tar)两套逻辑;Windows 的调试用 Get-Item / Get-ChildItem
  7. 构建产物在 Actions 可见但不出现在 Release 页面(缺少上传到 Release 的步骤)

    • 问题:actions/upload-artifact 会把文件保存在 Actions 界面,但不会显示在仓库的 Release 页面。
    • 处理:新增步骤——先创建或查找对应 tag 的 release(可创建为 draft),然后在每个 matrix job 中用 actions/upload-release-asset 上传各自平台的包到该 release 的 upload_url。
  8. 上传时出现 Validation Failed(already_exists)与权限问题

    • 问题:当 Release 已有同名 asset 时,API 会返回 already_exists。另外要确保 workflow 有写入 Release 的权限。
    • 处理:在上传前用 API 列出 release 的 assets,若存在同名则先删除(用 actions/github-script 调用 API 删除),再上传;在 workflow 中设置 permissions: contents: write 确保有权限。

其他细节与注意点

  • 使用 actions/github-script 时:脚本中不要再次 require('@actions/core') 等,因为该 action 会注入 coregithubcontext 等变量,重复声明会报错。
  • 在每个 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”这三点做稳,琐碎但可复用,记录下来方便以后回顾与改进。