「AWS無料相談会」をオンラインで開催中

GolangCI-LintとCircleCIを利用して静的解析チェックを自動化する

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の実行を自動化することが可能です。

File Watherによる自動実行

いかがでしょうか。もし興味がありましたら、GolangCI-Lintを利用してみてください!
以上です!