ちょっと話題の記事

GitHub Actions で Go言語の lint と test を実行する

GitHub Actions で Go言語の lint を test を実行を行うサンプルについてのブログです。
2018.12.29

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

黒澤です。皆さんは GitHub Actions のベータに当選しましたでしょうか。 私は11月の頭ぐらいに当選していたのですが、当時は private リポジトリ限定で使える仕様だったため使うのを諦めていた勢です。

ですが先日ついに public リポジトリにも解禁されていたので軽く使い方を書いていこうと思います。

Enabling Actions on Public Repositories | GitHub Developer Guide

ベータ権の申し込みとかそんなの知らない!って人はこちらのページからエントリーできます。

GitHub Actions

GitHub Actions とは

2018年10月の GitHub Universe というイベントで発表された GitHub の新機能です。 ワークフローをコードで書き、GitHub のイベントと連動して自動で実行することができます。

例えば、GitHub に push が行われたら Docker image をビルドしてデプロイする、みたいなワークフローを GitHub Actions で実現できます。

ワークフローの具体例は公式ブログや GitHub Universe の Live 等に事例がいっぱい乗っているのでそちらも参考になります。

GitHub Actions で Go言語の lint を test を実行する

今回はその GitHub Actions を使って Go言語の lint と test を実行します。 今までなら外部の CI サービスを使って実現していたことが GitHub Actions を使うことで GitHub で完結できるようになりました。便利!

今回の実現するワークフローのディレクトリ構成は以下のようになっています。

$ tree -a
.
├── .github
│   ├── actions
│   │   └── golang
│   │       ├── Dockerfile
│   │       └── entrypoint.sh
│   └── main.workflow
├── go.mod
├── main.go
└── main_test.go

.workflow ファイル

GitHub Actions では .github/main.workflow ファイルにワークフローを定義していきます。

workflow "Golang workflow" {
  on = "push"
  resolves = ["Test"]
}

action "GolangCI-Lint" {
  uses = "./.github/actions/golang"
  args = "lint"
}

action "Test" {
  needs = ["GolangCI-Lint"]
  uses = "./.github/actions/golang"
  args = "test"
}

上のファイルをビジュアル化したものがこちら

なんとなく雰囲気は伝わったでしょうか。 それぞれ解説をしていきます。

ワークフローの定義です。

workflow "Golang workflow" {
  on = "push"
  resolves = ["Test"]
}
  • on でワークフローがキックされるイベントを指定します。この場合は push イベントに反応してワークフローがキックされます。 サポートされているイベント一覧はこちらのドキュメントを参照してください。
  • resolves にワークフローの終点のアクションを指定します。それぞれのアクションに依存関係を定義することができ、依存しているワークフローを含めてまとめて実行されます。

次に、アクションの定義です。

action "GolangCI-Lint" {
  uses = "./.github/actions/golang"
  args = "lint"
}

action "Test" {
  needs = ["GolangCI-Lint"]
  uses = "./.github/actions/golang"
  args = "test"
}

GitHub Actions は Docker コンテナ内で実行されます。実行に使われる Docker image は DockerHub などで公開されているものや、リポジトリ内にある Dockerfile から作成したものを使用することができます。 今回は Dockerfile から image を作成します。

  • uses に Dockerfile が置いてあるディレクトリを指定します。DockerHub の image を使う時などは指定方法が変わります。ドキュメントはこちら
  • needs には依存関係を指定します。 action Test は action GolangCI-Lint に依存していることがわかります。
  • args に引数をしていします。今回は lint と test で共通の Docker image を使用しており、引数で制御を行なっています。

ここまでが .workflow の解説です。

Dockerfile & entrypoint.sh

今回使用する Dockerfile と ENTRYPOINT のシェルスクリプトです。

FROM golang:1.11.4

LABEL "name"="Golang workflow" \
    "maintainer"="Dai Kurosawa <hogehoge@example.com>" \
    "com.github.actions.icon"="code" \
    "com.github.actions.color"="green-dark" \
    "com.github.actions.name"="golang workflow" \
    "com.github.actions.description"="This is an Action to run go and golangci-lint commands."

ENV LINT_VERSION="v1.12.5"

COPY entrypoint.sh /entrypoint.sh

RUN curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin ${LINT_VERSION} \
  && chmod +x /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]
#!/bin/bash

APP_DIR="/go/src/github.com/${GITHUB_REPOSITORY}/"

mkdir -p ${APP_DIR} && cp -r ./ ${APP_DIR} && cd ${APP_DIR}

export GO111MODULE=on
go mod tidy
go mod verify

if [[ "$1" == "lint" ]]; then
    echo "#######################"
    echo "# Running GolangCI-Lint"
    golangci-lint --version
    golangci-lint run --enable-all --disable gochecknoglobals --disable gochecknoinits
fi

if [[ "$1" == "test" ]]; then
    echo "#######################"
    echo "# Running Test"
    go test ./... -race
fi

今回は GolangCI-Lint という lint を使用します。 この lint を使用するとさまざな Go言語の lint をまとめて実行してくれます。 GolangCI については以前ブログを書いたのでこちらもご覧ください。

無料で使える Go 言語の CI サービス『GolangCI』を使ってみる

こちらのファイルについては特に解説することもないのですが一点だけ、

APP_DIR="/go/src/github.com/${GITHUB_REPOSITORY}/"

mkdir -p ${APP_DIR} && cp -r ./ ${APP_DIR} && cd ${APP_DIR}

ここの処理で GOPATH 配下にソースを突っ込んでいます。 今回の例では Modules を使用して依存関係を解決しているので GOPATH に縛られることもないのですが、使用しない場合などは GOPATH 配下にソースを移動させてあげましょう。 Go言語を使用したワークフローを作成する場合はテンプレート的に書いておくのもアリかもしれません。

今回の例とは違うパターンで dep などを使用して依存関係を解決する際は Docker iamge に含めておくことも忘れずに。

実行する

ファイルを用意できたら GitHub に push してあげるとワークフローが実行されます。 ベータに当選している人なら Actions ってタブが見えていると思います。

失敗した場合はこのような感じ。

Log をクリックするとアクション中に標準出力に吐き出されたログやメッセージを確認できます。失敗した原因を確認する際もここから見ます。

中は標準出力に吐き出されたものがそのままずらっと並んでいるだけなので、テストを失敗した部分だけ見たい場合などは見づらいかもしれません。そこは実行する側で見やすくしてあげるなどの工夫が必要っぽいです。

PR 画面から見るとこんな感じ。

おわりに

GitHub Actions、いかがでしたでしょうか。

今回は CI っぽく使って見ましたが、ワークフローを自動化するものなので他にも色々なことが実現できます。 公式ドキュメントに色々書いてあるので見てみると良いかもしれません。

GitHub Actions | GitHub Developer Guide

GitHub Actions はまだベータで、今後もっと使いやすくなっていくと思うので期待ですね!