はじめに
こんにちは、H×Hのセンリツ大好きエンジニアです。
前回:TypeScript(Next.js)のCIをGitHub Actionsで構築してみる!
今回は、Go言語のCIをGitHub Actionsで構築してみた!という内容です。
初めて作成したのでおかしな所もあると思いますが、あまり責めないでください。。。(泣きます)
GitHub Actionsとは?
こちらの記事が非常に分かりやすいので、詳しく知りたい方は参考にしてみて下さい!(他力本願寺)
【初心者向け】【入門】GitHub Actionsの書き方についてデバッグ設定、runs-onやcheckoutなどの仕組みや構造も含めて徹底解説
簡単に言うと、GitHub上でCI/CDが構築できるよ!と言うものです。
(今までは、CircleCIなどの外部サービスと連携させる必要がありましたが、必要なくなります。一つのサービスで完結できるのって素晴らしいですね!)
CIの内容
GoのCIでは、主に3点を行います。
- goのテスト
- golangci-lintを用いた静的解析
- Dockleを用いた脆弱性検査
Dockleを用いた脆弱性検査に関しては前回と同じです。
実装
Github Actionsはリポジトリ直下の.github/workflows
にあるymlファイルに記述されたワークフローを元に実行されます。
公式リファレンス: GitHub Actions
なので、まずはリポジトリ直下に.github/workflows
ディレクトリを作成し、その中に今回使用するymlファイルを作成します。(名前はなんでも良いので、backend_ci.yml
とかにしておきます。)
構成図は以下になります。
.
├── .github
│ └── workflows
│ └── backend_ci.yml <- コレ!
├── .octocov.yml
├── backend
│ ├── .air.toml
│ ├── .golangci.yml
│ ├── Dockerfile
│ ├── go.mod
│ └── main.go
└── compose.yml
.
.
.
「自分はこのリポジトリではバックエンドだけ開発するからリポジトリ直下に置くよ!」という方はこの後のymlファイルの作業ディレクトリを.
に変更して下さい。
気になるymlファイルの中身ですが、以下のようにしました!
# ワークフローの名前
name: backend_ci
# トリガーになる Github イベント
on:
pull_request:
branches:
- develop
# ルート直下の場合は不要
paths:
- "backend/**"
# 無くても良い(手動実行したい人だけ残す)
workflow_dispatch:
# 環境変数を設定
env:
DOCKER_IMAGE_TAG: "backend"
# デフォルトの作業ディレクトリ変更
# ルート直下の場合は不要
defaults:
run:
working-directory: backend
# ジョブ定義
jobs:
# ジョブ名
backend_test:
runs-on: ubuntu-latest
steps:
# リポジトリからソースコードの取得
- name: Checkout Repository
uses: actions/checkout@v4
# Go の実行環境 Setup
- name: Go Setup
uses: actions/setup-go@v4
with:
go-version: 1.21
# テストの実行
- name: Run Test
run: go test -v ./... -coverprofile=coverage.out
# 実行結果を出力
- name: Run Octocov
uses: k1LoW/octocov-action@v0
backend_lint:
runs-on: ubuntu-latest
# GITHUB_TOKEN への権限設定
permissions:
checks: write
contents: read
pull-requests: write
steps:
# リポジトリからソースコードの取得
- name: Checkout Repository
uses: actions/checkout@v4
# Reveiwdogでgolangci-lintを実行
- name: Run golangci-lint with Reviewdog
uses: reviewdog/action-golangci-lint@v2
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
go_version: 1.21
# reviewdog の動作モードの指定
reporter: github-pr-review
# Github Status へのレポートレベルの指定
level: warning
workdir: backend/
golangci_lint_flags: "--config=.golangci.yml"
backend_build_check:
runs-on: ubuntu-latest
steps:
# リポジトリからソースコードの取得
- name: Checkout Repository
uses: actions/checkout@v3
# Dockerのコンテナイメージをビルド
- name: Docker Build
run: |
docker build -f Dockerfile -t ${{ env.DOCKER_IMAGE_TAG }} .
# Dockleで脆弱性検査を行う
- name: Run Dockle
uses: erzz/dockle-action@v1
with:
image: ${{ env.DOCKER_IMAGE_TAG }}
exit-code: 1
failure-threshold: fatal
行ごとに必要な箇所はコメントしているので、所々割愛しながら説明していきます。
# トリガーになる Github イベント
on:
pull_request:
branches:
- develop
# ルート直下の場合は不要
paths:
- "backend/**"
# 無くても良い(手動実行したい人だけ残す)
workflow_dispatch:
ここでは、GitHub Actionsを呼び出すトリガーを設定します。
今回は、以下のように設定しました。
- developブランチにPull Requestが作成された時に発火
- pathsでbackendディレクトリの中身が編集されていれば実行するように変更
- 手動実行もしたいので
workflow_dispatch
をトリガーに追加
# 環境変数を設定
env:
DOCKER_IMAGE_TAG: "frontend"
今回は、Dockerを用いてフロントエンドとバックエンドを管理しており、脆弱性検査の時にDockerfileのイメージを指定するので、ここで環境変数に設定しています。
goのテスト
# ジョブ定義
jobs:
# ジョブ名
backend_test:
runs-on: ubuntu-latest
steps:
# リポジトリからソースコードの取得
- name: Checkout Repository
uses: actions/checkout@v4
# Go の実行環境 Setup
- name: Go Setup
uses: actions/setup-go@v4
with:
go-version: 1.21
jobs
では、実行するジョブを定義します。
実行する内容を記述する前にジョブの実行を行うOSの指定をしています。
ジョブの内容ですが、まずはリポジトリからソースコードを取得します。
次に、Goの環境を準備していきます。バージョンは1.21にしてますが、ここは自由に変更して下さい!
# テストの実行
- name: Run Test
run: go test -v ./... -coverprofile=coverage.out
# 実行結果を出力
- name: Run Octocov
uses: k1LoW/octocov-action@v0
Run Testでテストを実行するとともに、カバレッジを計算します。
Octocovは、テストカバレッジ値やテストコード実行時間を管理できるツールです。
このツールを用いて、カバレッジを出力してもらいます。
また、ルート直下にoctocov.yml
ファイルを作成します。
coverage:
paths:
- coverage.out
codeToTestRatio:
code:
- "**/*.go"
- "!**/*_test.go"
test:
- "**/*_test.go"
testExecutionTime:
if: true
comment:
if: is_pull_request
これで、テストカバレッジ値をPull Requestのコメントとして投稿してくれるようになります!
goの静的解析
backend_lint:
runs-on: ubuntu-latest
# GITHUB_TOKEN への権限設定
permissions:
checks: write
contents: read
pull-requests: write
同じようにジョブの実行を行うOSの指定をしています。
また、GitHub Actionsの権限設定ですが、golangci-lintで指摘項目があった際にPull Requestのコメントに内容を送信してもらうためです。(直す箇所が特定できるのでめためた便利です!)
steps:
# リポジトリからソースコードの取得
- name: Checkout Repository
uses: actions/checkout@v4
# Reveiwdogでgolangci-lintを実行
- name: Run golangci-lint with Reviewdog
uses: reviewdog/action-golangci-lint@v2
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
go_version: 1.21
# reviewdog の動作モードの指定
reporter: github-pr-review
# Github Status へのレポートレベルの指定
level: warning
workdir: backend/
golangci_lint_flags: "--config=.golangci.yml"
ジョブの中身では、以下を実行します。
- リポジトリからソースコードを取得
- golangci-lintを実行し、結果をreviewdogでレビューコメント投稿
reviewdogという便利ツールを使います。
このツールは、各種linterの検出結果をレビューコメントとして自動的に投稿してくれるツールです。(とても便利です!)
公式リファレンス:reviewdog/reviewdog
今回はこのreviewdogのgolangci-lintバージョンで実行します。
オプションでは、以下のことを行なっています。
-
github_token
でreviewdogに権限を付与 - goのバージョン指定
-
reporter
で投稿方法を設定- Pull Requestのレビューコメントに設定
-
level
で警告をどのレベルで指摘するか設定- warningに指定
-
workdir
で作業ディレクトリ変更 -
golangci_lint_flags
でgolangci.ymlファイルから静的解析の設定を指定
golangci.yml
は静的解析の設定を記載しているファイルです。
今回はbackend
ディレクトリに入れています。
run:
deadline: 5m
linters-settings:
govet:
check-shadowing: true
golint:
min-confidence: 0.8
linters:
disable-all: false
enable:
- govet
- errcheck
- staticcheck
- unused
- gosimple
- misspell
- lll
- gofumpt
golangci.yml
ファイルでは使用するLinter等を設定しています。
設定したいLinterはこちらで確認して、取捨選択して下さい!
公式リファレンス:Linters
これで実際に動かしてみましょう!
きちんと指摘してくれました!
指摘があると、自分は「うっ!やばい!」と思うのですが、botに言われても心に余裕があるので素晴らしいツールですね!
脆弱性検査
最後に、脆弱性検査のジョブを見ていきましょう。
backend_build_check:
runs-on: ubuntu-latest
steps:
# リポジトリからソースコードの取得
- name: Checkout Repository
uses: actions/checkout@v3
# Dockerのコンテナイメージをビルド
- name: Docker Build
run: |
docker build -f Dockerfile -t ${{ env.DOCKER_IMAGE_TAG }} .
# Dockleで脆弱性検査を行う
- name: Run Dockle
uses: erzz/dockle-action@v1
with:
image: ${{ env.DOCKER_IMAGE_TAG }}
exit-code: 1
failure-threshold: fatal
先ほど同様リポジトリからソースコードを取得した後、Dockerイメージをビルドしていきます。
自分はDockerを使っているのですが、Dockerを使っていない場合は分かりません。。。
最後に、脆弱性検査ツールのDockleを実行します。
今回は、指摘される警告レベルをfatalに設定しました。
Dockerfile上で、「apk add
を使う場合は--no-cache
を使えよ!」と怒られます。
botになら怒られても「すみません。。。」とはならないので、ガラスのハートを持ってる自分でもヒビが入るくらいで耐えられますね!
さいごに
golangのCIをGitHub Actionsで構築してみました!(完全に理解した())
ただ、自分の完全に理解した()ではカバーできない所もあるので、アドバイスも頂ければ幸いです!
ここまでご覧いただきありがとうございました!