RustのLinuxとmacOS向けのバイナリをビルドしてGitHub Releaseへのリリースの自動化をするGitHub Actions
#GitHub_Actions #Rust
やりたいこと
以下のようにRust製のプロジェクトをビルドして実行形式のバイナリをGitHub Releaseで配布したい。
https://gyazo.com/661d2dd0394005105f23378eaaf7b8dc
またLinux向けのバイナリはポータブルにしたい。いわゆるシングルバイナリにしたい。
macOS向けにもリリーする。
タグがあるときにGitHub Releaseにリリースされる
なるべく標準の機能を使ってサードパーティ製のものを避ける。
やりかた
.github/workflows/ci.ymlを以下の内容でGitHubのリポジトリに設置する。
ci.ymlは任意の名前にできる。
下の"piping-server"となっているところを自分のプロジェックト名に置換すれば使えるはず。
code:.github/workflows/ci.yml
name: CI
on: push, pull_request
jobs:
build_for_linux_and_operational_test:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- name: Build
run: |
set -eux
docker run --rm -v "$(pwd)":/home/rust/src ekidd/rust-musl-builder:1.46.0 sh -c 'sudo chown -R rust:rust . && cargo build --release'
sudo chown -R $USER:$USER .
- name: Archive
run: |
set -eux
mkdir piping-server-x86-64-linux
cp target/x86_64-unknown-linux-musl/release/piping-server piping-server-x86-64-linux
zip -r piping-server-x86-64-linux.zip piping-server-x86-64-linux
tar czf piping-server-x86-64-linux.tar.gz piping-server-x86-64-linux
- name: Upload Linux executables as artifacts
uses: actions/upload-artifact@v2
with:
name: ${{ github.sha }}-linux-artifacts
path: piping-server-x86-64-linux.*
build_for_mac:
runs-on: macOS-10.15
steps:
- uses: actions/checkout@v2
- run: cargo build --release
- name: Archive
run: |
set -eux
mkdir piping-server-x86-64-apple-darwin
cp target/release/piping-server piping-server-x86-64-apple-darwin
zip -r piping-server-x86-64-apple-darwin.zip piping-server-x86-64-apple-darwin
tar czf piping-server-x86-64-apple-darwin.tar.gz piping-server-x86-64-apple-darwin
- name: Upload macOS executables as artifacts
uses: actions/upload-artifact@v2
with:
name: ${{ github.sha }}-mac-artifacts
path: piping-server-x86-64-apple-darwin.*
release_if_tag_exits:
needs: build_for_linux_and_operational_test, build_for_mac
runs-on: ubuntu-18.04
steps:
- name: Extract tag name
shell: bash
run: echo "##set-output name=tag;$(echo ${GITHUB_REF#refs/tags/})"
id: extract_tag
- uses: actions/checkout@v2
- name: Download the artifact (Linux)
uses: actions/download-artifact@v2
with:
name: ${{ github.sha }}-linux-artifacts
- name: Download the artifact (macOS)
uses: actions/download-artifact@v2
with:
name: ${{ github.sha }}-mac-artifacts
- name: Release
if: contains(github.ref, 'refs/tags/')
run: |
set -eux
hub release create \
-a piping-server-x86-64-linux.tar.gz \
-a piping-server-x86-64-linux.zip \
-a piping-server-x86-64-apple-darwin.tar.gz \
-a piping-server-x86-64-apple-darwin.zip \
-m "Release ${{ steps.extract_tag.outputs.tag }}" ${{ steps.extract_tag.outputs.tag }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
実際に使っているworkflowのYAMlファイルは以下にある。
やっていることなどの詳細
処理内容について触れる。
Linuxのシングルバイナリを作るために以下のようにekidd/rust-musl-builderを使っている。ここが唯一の外部のツールになっている。
code:sh
docker run --rm -v "$(pwd)":/home/rust/src ekidd/rust-musl-builder:1.46.0 sh -c 'sudo chown -R rust:rust . && cargo build --release'
sudo chown -R rust:rust .が必要なところが少しハマりどころ。
また上記のdocker run --rm ...が終わった後にsudo chown -R $USER:$USER .をして権限を元に戻す必要もあった。そのあとの処理はzipやtar.gzを作るだけ。他のjobにzipやtar.zipを渡すためにactions/upload-artifactを利用している。
GitHub Releaseするためにhubコマンドを使っている。これはGitHub Actionsの環境にはデフォルトで入っているため利用した。
releaseための純正のGitHub Actionsもある。だが、以下のissueのように複数のassetをアップロードできなく、複数のstepを書く必要がある。そうなるとやりたいことに対してコードの見通しが悪くなるためhubコマンドを使うことにした。
How to upload multiple assets? · Issue #28 · actions/upload-release-asset
release_if_tag_exits: というjobで- uses: actions/checkout@v2をするのはhubコマンドを使うことと関連している。hubコマンドはGitリポジトリ内で動かすことを前提としていると思われ、checkoutしないとしないとGitではないということでエラーする。本当は.zipや.tar.gzだけをactions/download-artifactするだけなのでcheckoutは不要なはずだが、checkoutする必要があるのはこういう理由から。
GitHub公式のghコマンドがより成熟すればこの問題は解決しそう。
cli/cli: GitHub’s official command line tool
またhubコマンドに何かオプションや環境変数を渡すとhubコマンドを使ってもcheckoutが不要になるかもしれない。
hub release createするときだけif: contains(github.ref, 'refs/tags/')してタグかどうか判別している。release_if_tag_exits: のjob全体でifしたい気もするかもしれないが、なるべくCIのコードは動かして誤りをリリース以外の時にも検知したいと思っているのでこのようにしている。publicリポジトリだとGitHub Actionsを贅沢に使えるという前提も多少ある。