はじめに
今回作成したのはGo言語リポジトリ用ワークフロー。
GitHubに指定されたタグがPushされた時点でテストを実行し問題が無ければ、クロスコンパイルを実施しリリースまで行う。
以下にアップロードしているので利用したい方はこちらからどうぞ。
ワークフローの流れは以下となっている。
- タグがPushされたことをトリガーにワークフローが起動
- 依存したモジュールをダウンロード
- テストを実施
- テストに合格した場合、リリースプロセスが始動
- ソースコードをzipにまとめリリース
- クロスコンパイルを実施し、それぞれ生成物をzipにまとめてリリース
以下が実際のworkflowファイル
name: Release Go Project
on:
push:
tags:
- v*
jobs:
test:
name: Test
runs-on: ubuntu-latest
steps:
- name: Set up Go 1.13
uses: actions/setup-go@v1
with:
go-version: 1.13
- name: Check out code into the Go module directory
uses: actions/checkout@v1
- name: Get dependencies
run: go get -v -t -d ./...
- name: Test code
run: go test -v .
setup-release:
name: Setup release
needs: test # This workflow is executed after completed 'test' job
runs-on: ubuntu-latest
steps:
- name: Create release
id: create_release
uses: actions/create-release@v1.0.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
draft: false
prerelease: false
- name: Get url to upload to release from output
env:
url: ${{ steps.create_release.outputs.upload_url }}
run: |
mkdir artifact
echo $url > artifact/url.txt
- name: Upload artifact to share url with other jobs
uses: actions/upload-artifact@v1
with:
name: artifact
path: artifact/url.txt
release-code:
name: Release Source Code
needs: setup-release
runs-on: ubuntu-latest
steps:
- name: Download artifact to get url to upload to release
uses: actions/download-artifact@v1
with:
name: artifact
- name: Get url to upload to release from artifact
id: get_url
run: |
url=$(cat artifact/url.txt)
echo "##[set-output name=upload_url;]$url"
- name: Check out code into the Go module directory
uses: actions/checkout@v1
- name: Pack source code in zip file
run: |
mkdir dist
ls -la
cp *.go dist/
zip -j -r release dist
- name: Upload release asset
uses: actions/upload-release-asset@v1.0.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.get_url.outputs.upload_url }}
asset_path: release.zip
asset_name: source.zip
asset_content_type: application/zip
release-pkg:
name: Release package
needs: setup-release
runs-on: ubuntu-latest
strategy:
matrix:
os: [mac64, lin64, win64]
include:
- os: mac64
goos: darwin
arch: amd64
- os: lin64
goos: linux
arch: amd64
- os: win64
goos: windows
arch: amd64
steps:
- name: Set up Go 1.13
uses: actions/setup-go@v1
with:
go-version: 1.13
- name: Check out code into the Go module directory
uses: actions/checkout@v1
- name: Get dependencies
run: go get -v -t -d ./...
- name: Build
env:
goos: ${{ matrix.goos }}
goarch: ${{ matrix.arch }}
run: |
mkdir dist
cp test.txt dist/
GOOS=$goos GOARCH=$goarch go build -v -o dist/app .
zip -j -r release dist
- name: Download artifact to get url to upload to release
uses: actions/download-artifact@v1
with:
name: artifact
- name: Get url to upload to release from artifact
id: get_url
run: |
url=$(cat artifact/url.txt)
echo "##[set-output name=upload_url;]$url"
- name: Upload release asset
uses: actions/upload-release-asset@v1.0.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.get_url.outputs.upload_url }}
asset_path: release.zip
asset_name: release-${{ matrix.os }}.zip
asset_content_type: application/zip
各種処理の概要
各種処理は、ジョブとステップの二通りで定義することができる。
今回は、テストや各種リリースの処理はそれぞれジョブとして分離し定義する形で設計している。
これは、クロスコンパイルを実施する際にGitHub Actionsの機能(matrix
)を有効活用して実施したいと考えたためである。
以降、各処理の概要を説明していく。
ワークフローのトリガー
以下は、このワークフローが実行される条件を指定している。
この場合は、「v」から始まるタグがpushされた場合にトリガーされ実行されることが定義されている。
on:
push:
tags:
- v*
実行条件は、ほかにも特定のブランチにpushされたや、特定のファイルやディレクトリ下に変更があった場合などを指定することができる。
もちろんpushのみではなく、forkされた場合やissueが立った際なども可能。詳しくは以下のリンクに載っている。
- ブランチやタグによるトリガー条件に付いて:GitHub Actionsのワークフロー構文 - GitHub ヘルプ
- トリガーイベントについて:ワークフローをトリガーするイベント - GitHub ヘルプ
自動テストの実行
以下は、自動テストを実行するジョブが定義されている。
jobs:
test:
name: Test
runs-on: ubuntu-latest
steps:
- name: Set up Go 1.13
uses: actions/setup-go@v1
with:
go-version: 1.13
- name: Check out code into the Go module directory
uses: actions/checkout@v1
- name: Get dependencies
run: go get -v -t -d ./...
- name: Test code
run: go test -v .
各stepにそれぞれ処理が定義されており、上から順に以下の流れとなっている。
- Go1.13の環境をコンテナ内に作成
- リポジトリの中に入り、状態をトリガーされたコミットにする
-
go get
を用いてgo.mod
に記載されている依存関係のあるモジュールをインストール -
go test
を用いて、テストを実行
この中で最も重要なのがactions/checkout@v1
。
これを実行することにより、リポジトリの中に入ることができる。
そのため、実行しないでgo get
しても必要なモジュールをインストールしてくれない。
もし途中のステップで実行に失敗した場合、デフォルトだとそこで処理は止まり、ジョブは失敗扱いとなる。
例として、go get
に失敗した場合、このテスト用ジョブはそこで中断されgo test
が実行されることはない。
リリースの作成
以下は、リリースの作成を定義している。
実際の作成は、actions/create-release@v1.0.0
に行ってもらっている。
setup-release:
name: Setup release
needs: test # 'test' ジョブが成功した後に実行する
runs-on: ubuntu-latest
steps:
- name: Create release
id: create_release
uses: actions/create-release@v1.0.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
draft: false
prerelease: false
- name: Get url to upload to release from output
env:
url: ${{ steps.create_release.outputs.upload_url }}
run: |
mkdir artifact
echo $url > artifact/url.txt
- name: Upload artifact to share url with other jobs
uses: actions/upload-artifact@v1
with:
name: artifact
path: artifact/url.txt
ジョブは基本的にすべて並列に実行される。
しかし、バグなどの致命的欠陥を持ったままリリースはしたくないため、リリース処理などはテストの実施後に行いたいものである。
そのために、このジョブではneeds: test
でtest
ジョブが実行完了しないと実行されないように制限を入れている。
これにより、ジョブの逐次実行が可能となる。ジョブに依存関係を持たせたい場合はneeds
を用いるべき。もちろん依存関係は一つのみでなく複数のジョブを指定することができる。詳しくは、以下のリンク参照。
- ジョブの依存関係について:GitHub Actionsのワークフロー構文 - GitHub ヘルプ
このジョブの後半のステップは、作成されたリリースにパッケージをアップロードする際に必要となるURLを次のジョブに渡すために必要となる。
やっていることは${{ steps.create_release.outputs.upload_url }}
で直前のリリース作成時に出力されたアップロード先URLを取得し、それをファイルに書き込み、actions/upload-artifact@v1
でワークフローのアーティファクトにアップロードしている。
これだけではジョブ間の情報共有はできないのだが、共有先のジョブでactions/download-artifact@v1
を実行することでアーティファクト経由で情報を共有することができる。ジョブ間の情報共有については以下のリンクを参照。
- ジョブ間での情報共有について:Persisting workflow data using artifacts - GitHub ヘルプ
パッケージのアップロード
以下は、先ほど作成されたリリースにパッケージをアップロードする処理が定義されている。
release-pkg:
name: Release package
needs: setup-release
runs-on: ubuntu-latest
strategy:
matrix:
os: [mac64, lin64, win64]
include:
- os: mac64
goos: darwin
arch: amd64
- os: lin64
goos: linux
arch: amd64
- os: win64
goos: windows
arch: amd64
steps:
#
# 'test' ジョブと処理がほぼ一緒なので一部割愛
#
- name: Build
env:
goos: ${{ matrix.goos }}
goarch: ${{ matrix.arch }}
run: |
mkdir dist
cp test.txt dist/
GOOS=$goos GOARCH=$goarch go build -v -o dist/app .
zip -j -r release dist
- name: Download artifact to get url to upload to release
uses: actions/download-artifact@v1
with:
name: artifact
- name: Get url to upload to release from artifact
id: get_url
run: |
url=$(cat artifact/url.txt)
echo "##[set-output name=upload_url;]$url"
- name: Upload release asset
uses: actions/upload-release-asset@v1.0.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.get_url.outputs.upload_url }}
asset_path: release.zip
asset_name: release-${{ matrix.os }}.zip
asset_content_type: application/zip
このジョブは実行の定義自体は一種類しかないが、matrix
を用いることによりパラメータを変化させて同時に3つのジョブを並列に実行するように定義されている。
matrix
には対象OSごとの実行ファイルを作るために必要なパラメータを設定している。これによりジョブは、ビルド時に必要な情報を取得し、指定したOS用の実行ファイルを並列に生成かつリリースにアップロードすることができる。この仕組みを用いて、クロスコンパイルを実施している。
リリースへのアップロードにはactions/upload-release-asset@v1.0.1
を用いている。これはアップロード先のURLが必要となるので、新規にリリースをアップロードしたい場合は先ほど利用したactions/create-release@v1.0.0
と併用する必要がある。詳しくは以下のリンクを参照。
おわりに
GitHub Actionsが正式リリースされたとのことでいろいろ触ってみたが、結構いろいろ自動化できそうで楽しい。
今回は、触っていた際にたまった知見を活かして、Go言語のリリース用ワークフローを作成してみたが、まだやりたいことをシンプルに実現するにはあと一歩って感じがした。
実現できなくはないが、ちょっとめんどくさいところがまだある(特にジョブ間とワークフロー間の情報共有)ので、今後さらにアップデートを重ねてよりよくなっていくことに期待。