Github ActionsでクロスコンパイルしてGithub Releaseにアップロードする
追記: GoReleaserのbabarotさんの記事があったので紹介。GoReleaser使ったほうが手軽でよさそう。 Go で書いた CLI ツールのリリースは GoReleaser と GitHub Actions で個人的には決まり | tellme.tokyo
追記: GoReleaserのプロジェクトがGithub Actionを公開したようなのでこちら使ってみるといいかもしれません。 https://github.com/goreleaser/goreleaser-action
この前kube-promptのリリースでミスをしてしまいissueが立て続けに2件上がったことがあったのですが、Github Actionsが自分のリポジトリで使えるようになったのでリリースを自動化することにしました。
触ってみてわかったのですが、↓の記事を書いたときとは多くの変更がありました。workflowの記述フォーマットがyamlに変更されていたり、Azure Pipelinesを裏側で使うようになったことでSupported virtual environmentsにmacOSやWindowsが増えたり、その影響でCustom actionはDockerコンテナベースではなくJavaScriptアプリケーションとして記述できるようになったりしています。JavascriptでCustom actionを記述するのはまた今度にして、とりあえず今回はyaml形式のworkflowを使っていきます。
クロスコンパイルとGithub releasesへのアップロード
kube-promptではこんな感じでいくつかバイナリをGithub Releaseに含めています。今回は tagが作成されたタイミングでフックしてこれらのbinaryをcross compile, zipで圧縮してGithub Release画面を作成します。
まずworkflowのevent trigger指定します。 今回からcronのように定期実行もできるようになっていますが、基本的には GithubのWebhook event を起動トリガーにすることがほとんどかと思います。git tagのcreateイベントをトリガーにしたいので次のようになります 1 。
on: create: tags: - v*.*.*
次にjobs propertyより実際にGithub Actionsで行いたい操作を記述します。 そんなに長くなくて↓のような感じです。
jobs: release: # job_id name: Build runs-on: ubuntu-latest steps: - name: Set up Go 1.12 uses: actions/setup-go@v1 with: version: 1.12 id: go - name: Check out code into the Go module directory uses: actions/checkout@master - name: Build env: GO111MODULE: on GOPATH: /home/runner/work/ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | export CREATE_EVENT_REF_TYPE=$(jq --raw-output .ref_type "$GITHUB_EVENT_PATH") export TAGNAME=$(jq --raw-output .ref "$GITHUB_EVENT_PATH") if [ "$CREATE_EVENT_REF_TYPE" != "tag" ]; then echo "ref_type is not a tag: ${CREATE_EVENT_REF_TYPE}" && exit 78; fi make cross go get -u github.com/tcnksm/ghr $GOPATH/bin/ghr -n ${TAGNAME} -b "ʕ◔ϖ◔ʔ Release ${TAGNAME}" -draft ${TAGNAME} pkg/
jobs.<job_id>.runs-on
に実行環境を指定することができて、今回からmacOSやWindowsが追加されました。kube-promptはCGOの依存とかもなく普通にクロスコンパイルできるので、一番速度や動作が安定してそうなubuntuにしています。他のCIサービスと同様に、matrixも組めるのでテストとか必要に応じてやっておくといいかと思います。- GITHUB_TOKENは以前までだと自分でsecretsに登録する必要がありましたが、今回からはその必要も無いようです。yaml内で
${{secrets.GITHUB_TOKEN}}
とするだけで取り出せます。- どこまでが古いドキュメントにしか書かれてなくて、どこまでが新しいドキュメントに書かれてるのか分からずこれに気づくの少し時間がかかってしまいました。
$GITHUB_EVENT_PATH
にはWebhook eventのJSONファイルがそのまま入っています。今回はcreate
イベントにフックしているので、 こちら にあるように、ref_type
フィールドからtag名、ref
フィールドからrevision hashが取り出せます。make cross
の処理はこんな感じです https://github.com/c-bata/kube-prompt/blob/4e31373f5a10443746b4ab93d584ea0ec17d4e61/Makefile#L31-L43- 最後にghrをgo getしてきてアップロードします。Githubのtokenは
GITHUB_TOKEN
環境変数を見てくれているので特にコマンド実行時には指定する必要がありません。 - ~ちなみに
actions/setup-go
は$GOPATH
が空で$GOPATH/bin
にもパスが通っていないようなので、明示的に指定しました。直したほうがいい気がしますが、JavaScriptベースのCustom actionとして定義されているらしく、まだ自分も調べてないところだったので今度必要になって調べることがあればついでに提案してみたいとおもいます。~uses
で何もDockerイメージが指定されていないstepは、runs-on
で指定したホスト上でそのまま動いているかもです。setup-go
はそのホスト上にGoの環境を構築してくれているということな気がします。ただ環境変数とかは引き継げないのかな?- https://github.com/actions/setup-go
全体像はこんな感じです。試しに v0.0.1 みたいなタグをpushして無事にバイナリ付きでGithub Releaseが作成されることは確認しました。
https://github.com/c-bata/kube-prompt/blob/master/.github/workflows/release.yml
おまけ: golangci-lintとgo testの実行
Goptunaという最近開発してるプロジェクトはまだCIを導入していなかったので、Lintとテストを実行できるようにしました。 他のプロジェクトでもほとんどそのまま使える点も多いと思うのでよければ参考にしてみてください。
name: Run tests and lint checks on: pull_request: branches: - master jobs: lint: name: Lint checking on Ubuntu runs-on: ubuntu-latest steps: - name: Set up Go 1.12 uses: actions/setup-go@v1 with: version: 1.12 id: go - name: Check out code into the Go module directory uses: actions/checkout@master - name: Running golangci-lint env: GO111MODULE: on GOPATH: /home/runner/work/ run: | go get -u github.com/golangci/golangci-lint/cmd/golangci-lint GOCILINT=${GOPATH}/bin/golangci-lint make lint test: name: Test on ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest, windows-latest, macOS-latest] steps: - name: Set up Go 1.12 uses: actions/setup-go@v1 with: version: 1.12 id: go - name: Check out code into the Go module directory uses: actions/checkout@master - name: Running go tests run: make test
https://github.com/c-bata/goptuna/blob/master/.github/workflows/run-tests.yml
追記:
Go関係ないですが、ついでにSphinxのドキュメントをビルドしてGCSにアップロードするscript書いたのでgcloudとかgsutil使いたい方とか参考にしたい方はどうぞ。本当は https://github.com/actions/gcloud を使おうと思ったのですが柔軟性なくて今回の用途には使えなかったのでやめました。
Github Actions Workflow to build your sphinx documentation and upload it to Google Cloud Storage. https://gist.github.com/c-bata/ed5e7b7f8015502ee5092a3e77937c99
おわりに
travis CIを長く使ってきましたが、Windowsの動作が不安定だったり苦労している点が結構ありました。 ActionsはAzure Pipelinesがバックエンドにあることもあり、立ち上がりがかなり速い印象です。 forkしたらそのままActionsが使えるというメリットもあるので、OSSでは積極的に使っていこうと思います。