Dartでコマンドラインツールを作ったものをGitHub Actionsでビルドして公開する
やりたいこと
Dartは dart compile exe
すればシングルバイナリを出力してくれるので、社内向けのコマンドラインツールを作って配布するなどがしやすい。
GitHub Releasesで↓こういう感じにしたい。
GitHub ActionsでビルドしてReleasesにアップロードする
Goで書けばクロスコンパイルもできるしgoreleaserでGitHub Releasesへのアップロードも楽勝なのだが、Dartではそこまで整った仕組みはない。
クロスコンパイルできないまま2年くらい経っていて、そろそろみんな諦め始めている。代わりに、GitHub Actionsのwindows-latest, macos-latest, ubuntu-latestを使うというのが定石になりつつある。
上のissueには実際にそれぞれのビルド環境でビルドしてアーティファクトにアップロードするサンプルがあるが、GitHub Releasesにそれをまとめるスクリプトはない。
コンパイル
各OSで dart compile exe
するだけなのだが、出力ファイル名がWindowsだけ .exe
をつけないといけない。以下のようにmatrix/includeを使用するとよい。
jobs:
compile:
name: dart compile exe
strategy:
matrix:
include:
- runs-on: ubuntu-latest
binary-name: mycli_linux_amd64
- runs-on: macos-latest
binary-name: mycli_macos_amd64
- runs-on: windows-latest
binary-name: mycli_windows.exe
runs-on: ${{ matrix.runs-on }}
steps:
- uses: actions/checkout@v2
- uses: dart-lang/setup-dart@v1
- run: dart pub get
- run: mkdir ${{ matrix.runs-on }}
- run: dart compile exe bin/mycli.dart -o ${{ matrix.runs-on }}/${{ matrix.binary-name }}
リリースの作り方
を見るに、2つの作業が必要らしい。
- リリースというものをつくる
- POST /repos/{owner}/{repo}/releases
- リリースにassetをアップロードする
- POST /repos/{owner}/{repo}/releases/{release_id}/assets
- api.github.comではなくuploads.github.com
最初は頑張ってcurlでやってみようとしたが、GitHub Actionsのマーケットプレイスをみると既存でいくらでもあるようなので、それを拝借することにした。
action-gh-release を使ってリリースを作る
actions/create-release@v1
や actions/upload-release-asset@v1
はもうメンテされていないらしいので、代わりに softprops/action-gh-release@v1
を使用する。
リリースの作成とファイルのアップロードを1つのアクションでやってくれるので、けっこう便利。
いろいろオプションは指定できるが、とりあえず下書きでリリースを作ってそこにファイルをアップロードしたいだけなら、以下の内容だけでよい。
- uses: softprops/action-gh-release@v1
with:
draft: true
files: out/*
filesはglob形式で指定することもできるし、以下のように複数行指定もできるようだ。
files: |
out/mycli_linux
out/mycli_macos
out/mycli_windows
まとめ
こんなかんじでいける。バイナリ名だけ調整すれば、けっこういろんなCLIアプリで使えるんじゃないかな。
name: Deploy
on:
push:
tags:
- '[0-9]+.[0-9]+.[0-9]+'
jobs:
compile:
name: dart compile exe
strategy:
matrix:
include:
- runs-on: ubuntu-latest
binary-name: mycli_linux_amd64
- runs-on: macos-latest
binary-name: mycli_macos_amd64
- runs-on: windows-latest
binary-name: mycli_windows.exe
runs-on: ${{ matrix.runs-on }}
steps:
- uses: actions/checkout@v2
- uses: dart-lang/setup-dart@v1
- run: dart pub get
- run: mkdir ${{ matrix.runs-on }}
- run: dart compile exe bin/mycli.dart -o ${{ matrix.runs-on }}/${{ matrix.binary-name }}
- uses: actions/upload-artifact@v2
with:
name: bin-${{ matrix.runs-on }}
path: ${{ matrix.runs-on }}
release:
needs: compile
name: github release
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v2
with:
name: bin-ubuntu-latest
path: bin-linux
- uses: actions/download-artifact@v2
with:
name: bin-macos-latest
path: bin-macos
- uses: actions/download-artifact@v2
with:
name: bin-windows-latest
path: bin-windows
- uses: softprops/action-gh-release@v1
with:
draft: true
files: bin-*/*
これで実際にtag pushしてみると、
3並列コンパイルからの・・・リリース作成で
思っていた通りのものが作れた\(^o^)/
Discussion