Wails 実践講座 #6 CI/CD 自動リリース — GitHub Actions で 3 プラットフォーム配信
第 1 部の最後の記事です。#5 で署名・公証を習得したので、この全過程を自動化します。目標は明確です。Git タグ一つをプッシュすると、macOS・Windows・Linux の 3 プラットフォームの署名済みリリースが自動で作られることです。手で 3 回ビルドして署名していた作業を GitHub Actions に渡します。
このシリーズは全 10 編、2 部構成で、この記事は第 1 部の最後です。
- 第 1 部 — アプリを作って配信する: #1 · #2 · #3 · #4 · #5 署名と公証 · #6 CI/CD 自動リリース ← この記事
- 第 2 部 — 完成度とリピーター: #7 ノートエディタの実践 · #8 テスト戦略 · #9 自動更新の実装 · #10 仕上げと完成度
なぜマトリックスか: macOS はクロスコンパイルできない #
入門 #6 で触れたとおり、デスクトップアプリは一つの OS から 3 つの OS 用のバイナリを作るのが難しいです。特に macOS アプリは macOS でしかビルドできません。署名・公証のツール(codesign、notarytool)が macOS 専用だからです。そこで一つのランナーでクロスコンパイルする代わりに、プラットフォームごとにその OS のランナーでビルドするマトリックスを使います。GitHub Actions は macos、windows、ubuntu のランナーをすべて提供するので、この構造が自然です。
ここで #2 の選択が見返りをくれます。SQLite を純粋な Go ドライバー modernc.org/sqlite で選んだので、各ランナーで CGO なしにそのままビルドされます。CGO 版を選んでいたら、ランナーごとに C ツールチェーンを合わせるのにワークフローがはるかに複雑になっていたでしょう。
ワークフロー: タグに反応するマトリックス #
v で始まるタグがプッシュされると、3 つのランナーが並列でビルドします。
on:
push:
tags: ["v*"]
jobs:
build:
strategy:
matrix:
include:
- os: macos-latest
platform: darwin/universal
- os: windows-latest
platform: windows/amd64
- os: ubuntu-latest
platform: linux/amd64
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with: { go-version: "1.23" }
- name: Wails ビルド
uses: dAppServer/wails-build-action@main
with:
build-platform: ${{ matrix.platform }}dAppServer/wails-build-action は Wails CLI のインストール、フロントエンドの依存インストール、ビルドをまとめて処理するコミュニティのアクションです。直接 wails build を呼ぶステップに置き換えてもよいですが、このアクションは署名・インストーラー生成までオプションで支援し、初期構成を減らしてくれます。
署名を CI へ: Secrets から復元 #
#5 で秘密をローカルに置かないと決めたことがここに続きます。証明書は base64 でエンコードして GitHub Secrets に入れ、ワークフローで復元して署名に使います。
- name: 証明書のインポート (macOS)
if: matrix.os == 'macos-latest'
env:
CERT_P12: ${{ secrets.MACOS_CERT_P12 }} # base64 エンコードした .p12
CERT_PW: ${{ secrets.MACOS_CERT_PASSWORD }}
run: |
echo "$CERT_P12" | base64 --decode > cert.p12
security create-keychain -p "" build.keychain
security import cert.p12 -k build.keychain -P "$CERT_PW" -T /usr/bin/codesign
# 以降 codesign → notarytool submit --wait → stapler staple (#5 参照)Windows のランナーも同じ方式でコード署名証明書を復元し、signtool で署名します。機微な値はすべて secrets.* からのみ来て、ログに出力されないよう注意します。
リリースにまとめる #
各ランナーが作った成果物を一つの GitHub Release にまとめます。ビルドの成果物をアーティファクトとしてアップロードした後、最後のジョブでリリースを作って添付するか、各ジョブが同じタグのリリースにアセットを追加する方式を使います。
- name: リリースにアセットをアップロード
uses: softprops/action-gh-release@v2
with:
files: build/bin/*これでサイクルはこうなります。コードをコミットして git tag v1.0.0 && git push --tags をすると、3 つのランナーがそれぞれビルド・署名し、完成したインストーラーが v1.0.0 のリリースページに上がります。ユーザーは自分の OS に合ったファイルをダウンロードし、警告なしにインストールします。
自動更新: 何が使えるか #
アプリを配信した後の次の問いは自動更新です。Wails には公式の内蔵アップデーターがないので、戦略を選びます。
- 軽い方式: アプリの起動時に GitHub Releases の最新タグを照会し、現在のバージョンより高ければリリースページを開いてユーザーに直接ダウンロードしてもらいます。実装が単純で、署名の流れと衝突しません。
- 完全自動: 新しいバイナリをダウンロードして自分自身を置き換える方式です。署名の検証、権限、ロールバックまで自分で扱う必要があり複雑で、誤ると署名済みアプリの信頼を壊しかねません。
個人・小規模の配信なら、軽い方式(更新があることを知らせてリリースへ送る)が安全な既定値です。完全自動の置き換えは、ユーザー規模が大きくなって手動更新の案内が負担になったときに検討します。
第 1 部を終えて — そして第 2 部 #
ここまで第 1 部でメモリベースの骨組みを実際に配信可能なノートアプリに育てました。層を分け(#1)、純粋な Go の SQLite を付け(#2)、検索とデータフローを固め(#3)、バックグラウンドに常駐させ(#4)、署名・公証し(#5)、CI で自動化(#6)して、アイデアを 3 プラットフォームの署名済みインストーラーとして配信する全サイクルを手にしました。
ところが配信可能なアプリと、ユーザーが毎日また開くアプリは違います。これまでバックエンドに偏って後回しにした前側(エディタ・UX)、約束だけしたテスト、戦略だけ話した自動更新、そして設定・ダークモード・データの安全といった仕上げが残っています。第 2 部(#7〜#10)で、このアプリをリピーターが生まれる完成度まで引き上げます。
まとめ #
- macOS アプリは macOS でしかビルド・署名できないので、一つのランナーでのクロスコンパイルではなくプラットフォームごとのランナーのマトリックスを使います。純粋な Go の SQLite のおかげで各ランナーのビルドが単純です。
- ワークフローは
v*タグに反応して 3 つのランナーで並列ビルドし、wails-build-actionがビルド・インストーラー生成をまとめます。 - 署名の秘密は base64 で GitHub Secrets に入れ、ランナーで復元して使います。ローカルに置かない #5 の原則が CI で完成します。
- Wails には公式のアップデーターがありません。個人・小規模は「更新があることを知らせてリリースへ送る」が安全な既定値で、完全自動の置き換えは規模が大きくなったときに検討します。
- タグ一つで 3 プラットフォームの署名済みリリースが自動生成されること、それがこのシリーズの目標とした配信自動化の完成です。