RustのLinuxとmacOS向けのバイナリをビルドしてGitHub Releaseへのリリースの自動化をするGitHub Actions
やりたいこと
https://gyazo.com/661d2dd0394005105f23378eaaf7b8dc
またLinux向けのバイナリはポータブルにしたい。いわゆるシングルバイナリにしたい。 macOS向けにもリリーする。
なるべく標準の機能を使ってサードパーティ製のものを避ける。
やりかた
.github/workflows/ci.ymlを以下の内容でGitHubのリポジトリに設置する。
ci.ymlは任意の名前にできる。
下の"piping-server"となっているところを自分のプロジェックト名に置換すれば使えるはず。
code:.github/workflows/ci.yml
name: CI
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:
runs-on: ubuntu-18.04
steps:
- name: Extract tag name
shell: bash
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ファイルは以下にある。
やっていることなどの詳細
処理内容について触れる。
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を利用している。 releaseための純正のGitHub Actionsもある。だが、以下のissueのように複数のassetをアップロードできなく、複数のstepを書く必要がある。そうなるとやりたいことに対してコードの見通しが悪くなるためhubコマンドを使うことにした。 release_if_tag_exits: というjobで- uses: actions/checkout@v2をするのはhubコマンドを使うことと関連している。hubコマンドはGitリポジトリ内で動かすことを前提としていると思われ、checkoutしないとしないとGitではないということでエラーする。本当は.zipや.tar.gzだけをactions/download-artifactするだけなのでcheckoutは不要なはずだが、checkoutする必要があるのはこういう理由から。 hub release createするときだけif: contains(github.ref, 'refs/tags/')してタグかどうか判別している。release_if_tag_exits: のjob全体でifしたい気もするかもしれないが、なるべくCIのコードは動かして誤りをリリース以外の時にも検知したいと思っているのでこのようにしている。publicリポジトリだとGitHub Actionsを贅沢に使えるという前提も多少ある。