GolangCI-LintとCircleCIを利用して静的解析チェックを自動化する
腹筋ローラーで徐々に立ちコロができるようになってきました。やっさんです。
GolangCI-LintとCircleCIで静的解析チェックを自動化してみました。
そもそもLinterとは?
Linterとはプログラミング言語の静的解析を行うツールです。事前のコンパイルエラーの検知や、ふさわしくない構文などを検知するために利用します。言語毎に存在しており、例えばJavaであればCheckstyle、RubyではRuboCopが有名ですね。
GolangCI-Lintとは
Go言語は複数のLinterが乱立しており、どのLinterを使うべきか悩むこともあるかと思います。GolangCI-LintはLinterを一元管理し高速にLinterを実行することが出来るツールになります。
GolangCI-Lintのメリット
GolangCI-Lintを使うことで以下のメリットがあります。
1. Linterを一括で導入することができる
GolangCI-Lintのインストールはワンライナーで行うことができ、個別のLinterのインストールは不要ですので、一括で主要なLinerを導入することができます。利用したいLinterの数が増えるほどに、開発者の初期セットアップが煩わしくなることがありますので、一括でLinterを導入できることは大変便利です。
継続的インテグレーション(CI)にも簡単に導入することができる
継続的インテグレーション(CI)においてLinterを実行し、静的解析結果に問題がある場合は次のステップを実行せずにエラーとすることで、開発者は必然的に静的解析結果の修正を迫られ品質の高いコードを作成できます。
2. Linterのルールを設定ファイルとして記述できる
GolangCI-Lintは設定ファイルをサポートしており、Gitリポジトリのルート配下に配置することで、リポジトリ毎にLinterのルールを明確に定義することが可能です。これは、どのLinterを利用するかはもちろんのこと、各Linterの詳細設定も可能です。
3. Linterの実行速度が早い
GoLangCI-Lintは非常に高速であることをアピールしています。Linterを並列に実行し、Goビルドキャッシュとキャッシュの解析結果を再利用します。
主要なGo言語のLinterのご紹介
Go言語はLinterが乱立状態でして、40を超えるLinterが存在しています。主要なLinterを紹介します。
gofmt
gofmtはGoのソースコードをフォーマット(整形)するツールです。gofmtは自動整形がtとても便利でして、Visual Studio CodeなどのIDEでファイル更新時に自動整形させることも可能です。
golint
golintはスタイルミスを出力します。golint はコーディングスタイルを重視しており、オープンソースのGoプロジェクトで受け入れられているスタイルと一致させようとしています。golintに従うだけでセンスのあるコードを書けるわけです。
govet
govet は Go のソースコードを検査して、引数がフォーマット文字列と一致しない Printf 呼び出しなどの疑わしい構造を報告します。Vet は、すべてのレポートが本物の問題であることを保証しないヒューリスティックを使用しますが、コンパイラでは検出できないエラーを見つけることができます。
GolangCI-Lintをセットアップする
それでは、GolangCI-Lintをセットアップしていきます。
今回はローカル実行はMacを、CircleCIはLinux環境を前提としております。
MacにGolangCI-Lintをインストールする
homebrewを使い簡単にインストールすることができます。
以下のコマンドを実行します。
brew install golangci-lint
brew upgrade golangci-lint
GolangCI-Lintを実行する
早速、GolangCI-Lintを実行してみます。
以下のコマンドを実行します。
golangci-lint run
実行すると、Linterの結果が標準出力されました。設定ファイルを利用しない場合、GolangCI-Lintはデフォルトで有効になっているLinterを利用します。実行結果の例では、unusedで利用していないメソッドが検出されました。
domain/inquiry.go:173:34: func `ConsultationContentCode.getText` is unused (unused)
設定ファイルでLinterを指定する
今回はGitリポジトリでLinterを指定したいため、設定ファイルをGitリポジトリのルート配下に追加します。ファイル名は .golangci.yml
としました。設定ファイルは以下のような内容としています。
linters:
enable:
- errcheck
- gosimple
- govet
- staticcheck
- unused
- gofmt
- golint
disable-all: true
もう一度Linterを実行する
先程と同じコマンドで、もう一度Linterを実行します。
実行結果は以下の通りです。新たに golint
による検出結果を確認することができました。
usecase/inquiry_interactor.go:126:64: func parameter `sourceIp` should be `sourceIP` (golint)
domain/inquiry.go:173:34: func `ConsultationContentCode.getText` is unused (unused)
どのLinterで検出されたかどうかは、出力の最後のかっこの箇所で分かるようになっています。
Docker ContainerでGolangCI-Lintを実行する
Dockerコンテナ環境下でGolangCI-Lintを実行することで、開発者のローカル開発環境に依存せず実行できます。
Dockerfile
GolangCI-Lintのインストールはwgetとshコマンドを利用しています。
FROM golang:1.15.6-alpine
# install packages
RUN apk update && apk add --no-cache bash make curl git gcc libc-dev openssl
# Install golangci-lint & test library
RUN wget -O- -nv https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.35.0
WORKDIR /go/src/app
COPY . /go/src/app/
# go mod download
RUN go mod download
DockeコンテナでGolangCI-Lintを実行する
こちらはDockerのお作法になりますが、以下のコマンドで実行することで実行できます。
docker run -it 【イメージID】 golangci-lint run
Circle CIで実行する
Dockerfileまで用意ができましたら、CircleCIで自動化するのは簡単です。今回はCircleCIでDockerを起動するDocker in Docker利用してみます。先程のDockerfileをdocker-composeファイルで起動できるようにしました。
これを、makeコマンドで実行できるようにMakefileに記述します。
ci-lint:
docker-compose -f docker-compose-ci.yml run build golangci-lint run
CircleCIではmakeコマンドを実行するように .circleci/config.yml
ファイルを記述します。以下に記述例を示します。
jobs:
build:
working_directory: /go/src/app
<<: *defaults
steps:
- run:
name: Install curl
command: sudo apt-get update && sudo apt-get install -y curl vim-tiny make git
- run:
name: Install Docker Compose
command: |
sudo curl -L https://github.com/docker/compose/releases/download/1.19.0/docker-compose-`uname -s`-`uname -m` > ~/docker-compose
sudo chmod +x ~/docker-compose
sudo mv ~/docker-compose /usr/local/bin/docker-compose
- checkout
- setup_remote_docker
- run:
name: run golangci-lint
command: make ci-lint
GoLandのGolangCI-Lintプラグイン
統合開発環境のGoLandではGolangCI-Lintのプラグインが提供されており、設定ファイルの入力補完や、エディタ上でのハイライトが可能です。
GoLandでGolangCI-Lintの実行を自動化する
GoLandでは、File Watcher
を利用することでGolangCI-Lintの実行を自動化することが可能です。
いかがでしょうか。もし興味がありましたら、GolangCI-Lintを利用してみてください!
以上です!