はじめに
前回 Go で 簡単な API を作りました。
今回は Github Actions を使って CI の実装をしてみたいと思います。
Github Actions とは?
Github が提供するビルド、テスト、デプロイのパイプラインを自動化できる継続的インテグレーションと継続的デリバリー(CI/CD)のプラットフォームのこと。
リポジトリに対するすべての pull request をビルドしてテストしたり、マージされた pull request を運用環境にデプロイしたりするワークフローを作成できます。
詳細は以下を参照してください。
今回のゴール
Github Actions を使って簡単な CI のワークフローを作ります。
CIのフローは以下のようになります。
- リポジトリへソースを PUSH or PR の作成
- Github Actions 上で CI の実行
- 単体テストの実行
- linter の実行
- 結果を Slack へ通知
ワークフロー作成
ワークフローの作成には、
.github/workflows
配下に YAML 形式のファイル(.yml, yaml)を作成しワークフローを定義していきます。
.
├── .github # ディレクトリ作成
│ └── workflows
│ └── golang-ci.yml # 作成するワークフローのファイル
単体テスト
まずは、単体テストを実行するためのワークフローを書いていきます。
Github Action 上で Go の単体テスト(go test -v
)を行うための構文は以下のようになります
# ワークフローの名前
name: Go CI
# トリガーになる Github イベント
# 今回は、リポジトリへのコミット(push)と PR 作成(pull_request)をトリガーにします
on:
push:
pull_request:
# ジョブ定義
jobs:
# ジョブ名
test:
# ジョブ実行環境の指定
runs-on: ubuntu-latest
# ジョブ内で実行する step を定義
steps:
# リポジトリからソースコードの取得
- uses: actions/checkout@v3
# Go の実行環境 Set up
- uses: actions/setup-go@v4
with:
go-version: ^1.20
# テストの実行
- name: Run Test
run: go test -v ./...
これだけです。簡単ですね。
では、実際にこのコードをリポジトリに push して CI を走らせます。
↑こんな感じにリポジトリの Actions タブから ワークフローの実行結果を確認することができます。
無事、テストも成功しているようです。
実際の開発現場では、PR 作成前に 単体テストを実行して、問題なければ PR 作成、問題があれば再度修正をする、という流れになると思います。
では、特に問題なさそうなので、このまま PR を作成します。
実際に作成した PR はこんな感じ。
PR のページでは、All check have passed
と表示され、テストが成功している事もわかります。
リポジトリの設定で、ワークフローが失敗している場合(今回であれば単体テストの実行)、マージをブロックすることもできるので、そこはよしなに運用にあわせて設定してみてください。
では、これで PR をマージして、単体テスト実行のワークフロー作成は完了です。
linter
続いて、 linter を実行するためのワークフローを書いていきます。
linter には golangci-lint
を使用します。
また、補助ツールとして reviewdog を使い、 linter 指摘箇所を PR 作成時にコメントさせてみます。
そもそも linter とは?
いわゆる静的解析を行うツールです。
ソースコードの静的解析を行ってくれるもので、構文のチェックやバグの発見をしてくれたりします。
Java であれば CheckStyle とか FindBugs なんかが有名ですね。
golangci-lint とは?
Go の静的解析ツールを統合して実行してくれるツールです。
Golang には色々な解析ツールがあります(gofmt, goimports, govet)。
golangci-lint はこれらの様々な解析ツールを統合して実行することができます。
これ一つあれば、複数のツールを組み合わせなくていいし、実行速度も早いという優れもの。
reviewdog とは?
各種 linter の解析結果を PR にコメントする形で指摘してくれる補助ツールです。
linter を使って規約違反があることがわかっても実際の該当コードを探すのが大変だったりするのですが、 reviewdog を使うと、PR に直接コメント形式で linter 指摘を書いてくれるので該当コードを確認するのがとても楽になります。
golangci-lint の設定
では、まずは golangci-lint の設定ファイルを書いていきます。
golangci-lint は、設定で、どの linter を有効にするのか
、解析対象のファイルの指定
や除外対象のファイルの指定
などを行うことができます。
詳細は以下を参考にしてみてください。
今回はこんな感じに設定してみました。
# linter の設定
linters:
# 全ての linter を無効化
disable-all: true
# 指定した linter のみ有効化
enable:
- govet
- errcheck
- staticcheck
- unused
- gosimple
- varcheck
- misspell
- lll
- gofumpt
設定ファイルの書き方は大きく black list
形式と white list
形式があります。
golangci-lint にはデフォルトで有効になっている linter があり、何も指定しないとデフォルトで有効化されている linter が実行されます。利用する linter は明示的に指定したいので、今回は全ての linter を無効化してから、使いたい linter のみ enable で指定して有効化しています。(これが white list 形式)
reviewdog の設定
続いてreviewdog の設定です。
PR 作成時、 golangci-lint を実行し、指摘箇所があれば PR にコメントをさせるようワークフローを設定します。
以下のファイルを追加します。
.
├── .github
│ └── workflows
├── golang-ci.yml
└── golangci-lint-reviewdog.yml # 追加したファイル
追加したファイルの内容
# ワークフローの名前
name: Golangci-lint ReviewDog
on:
pull_request:
# ジョブ定義
jobs:
# lint
golangci-lint:
# GITHUB_TOKEN への権限設定
permissions:
checks: write
contents: read
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: reviewdog/action-golangci-lint@v2
with:
github_token: ${{ secrets.github_token }}
go_version: ^1.20
# reviewdog の動作モードの指定
reporter: github-pr-review
# Github Status へのレポートレベルの指定
level: warning
golangci_lint_flags: "--config=.golangci.yml"
こちらは、 PR 作成時のみ動作するようにしています。
主な設定はポイントは以下です。
- github_token
- reviewdog が PR にコメントできるようにトークンを指定
- reporter
- reviewdog の動作設定の指定
- ここでは、PR に直接コメントをさせたいので github-pr-review を指定します。
- level
- Github Checks に報告するレベルの指定
- info, worning, error の指定が可能
- 今回は指摘があってもマージができるようにしたいので warning としています
実際に動かしてみる
動作確認用に以下のファイルを追加しました。
これを使って実際に PR を作成します。(スペルミスで指摘されるはず)
package main
func typo() {
mispell := "misspell"
println(mispell)
}
すると、こんな感じにコメントが付きました。いいですね!
コードレビューする時、このレベルのチェックに時間や労力を割きたくないので、自動化できるところは自動化して、人間は大事なところにのみ労力を集中したいものです。
linter の設定は以上です。
Slack 連携
最後に Slack 連携です。
ここまでで、Github Actions を使った CI(単体テスト、静的解析) の構築をしました。
ここでは、、その CI の実行結果を Slack に連携できるようにしてみたいと思います。
ただし、実行結果を毎回全て通知されてもうざいだけなので、ここでは CI(単体テスト) が失敗したときのみ Slack へ通知する
ようにしてみたいと思います。
いやいや、とにかくなんでも通知が欲しいんだーって方は、
この辺使ってできるので参考にしてみてくださいmm
Slack 連携のやり方
以下の手順でやっていきます。
- Slack の Incoming Webhook URL の発行
- 発行した Incoming Webhook URL を リポジトリに環境変数として登録
- CI が失敗した時のみ Slack 通知できるようにワークフローの修正
1. Slack の Incoming Webhook URL の発行
まずは Webhook の発行です。
Slack 公式サイトより Webhook 作成ページを開き、ログイン、通知先のチャンネルを指定して「Incoming Webhook インテグレーションの追加」をします。
※ ここでは、#golang-api-sample-todo
を通知先として指定しています。(各自、これは自身の環境にあわせてください)
すると、こんな感じに Webhook の URL が発行されます。
これは後で使うのでしっかりメモっておいてください。
2. 発行した Incoming Webhook URL を リポジトリに環境変数として登録
次に、発行した Webhook の URL をリポジトリに環境変数として登録します。
Settings
タブからSecres and variables
-> Actions
を選択し、New repository secret
から登録します。
Name には参照するときの変数名、Secret には実際の値を入力します。
ここでは、 Name は SLACK_WEBHOOK_URL
としておきます。
Add secret
で追加。こんな感じに SLACK_WEBHOOK_URL が追加されます。
3. CI が失敗した時に Slack 通知できるようにワークフローの修正
これで Slack 通知のための下準備ができたので、ワークフローを修正して失敗時のみ Slack 通知するようにします。
修正したコードはこちら。
# ワークフローの名前
name: Go CI
# トリガーになる Github イベント
# 今回は、リポジトリへのコミットと PR 作成をトリガーにします
on:
push:
pull_request:
# ジョブ定義
jobs:
# ジョブ名
unit-test:
# ジョブの実行環境の指定
runs-on: ubuntu-latest
# ジョブ内で実行する step を定義
steps:
# リポジトリからソースコードの取得
- uses: actions/checkout@v3
# Go の実行環境の Set up
- uses: actions/setup-go@v4
with:
go-version: ^1.20
# テストの実行
- name: Run Test
run: go test -v ./...
# 以下を追記
# Slack 通知用の step
- uses: rtCamp/action-slack-notify@v2.0.2
# テストが失敗したときのみ通知する
if: failure()
env:
SLACK_TITLE: Test Failure
SLACK_COLOR: danger
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
※${{ secrets.SLACK_WEBHOOK_URL }}
は、先程登録した環境変数を参照するための記述です。
では、テストが失敗するようにコードを修正して、実際に通知されるか試してみます。
結果、こんな感じにちゃんと通知がきました。よかった
Slack 連携は以上です。
最後に
簡単ですが、 Github Actions を使った CI の構築から Slack 連携までやってみました。
Github Actions、便利ですね (´・ω・`)
今回作ったものは以下に公開してます。参考までに。
次回は AWS に環境作って、 API を デプロイしていくとこもつくってみようかなーと思います。
ではでは。