Help us understand the problem. What is going on with this article?

CircleCIでGitHubのPull Request時のみGoプロジェクトのチェックを実行する

やりたかったこと

GitHubのPull Request時にGoプロジェクトのビルド前チェックを行いたかったのでCircleCIで実現しました。
要件としては下記です。

  • errcheckやらlint等のチェックを実施
  • migrationを実施
    • DB処理を行うため、MySQLとRedisのイメージも利用
  • 処理時間の最大限短縮
    • 必要な外部ライブラリを取得済みのカスタムイメージを利用(イメージはプライベートリポジトリに保持)
    • vendorはキャッシュを利用
  • 処理結果をslackに通知

方針策定

migrationの確認はDBを立ち上げなくてはならず、なおかつDBの起動を待って処理を行わなくてはなりません。そのため、dockerizeコマンドをstepsに組み込みます。
今回は例としてMySQLとRedisのDockerイメージを使用しています。

また、チェック処理やmigrationには外部ライブラリの利用が必要となり、それらのインストールに時間がかかってしまいます。
処理時間の短縮を図るため、ライブラリを予めインストールしたカスタムイメージの利用とvendorのキャッシュ化を行います。

設定手順

GitHubをCircleCI連携するためにはプロジェクト直下に.circleciディレクトリを作成し、config.ymlファイルを配置する必要があります。
また、今回は必要なライブラリをインストール済みのカスタムイメージを利用するため、Dockerfileを用意する必要があります。このDockerfileの配置に関しても公式が配置箇所を指定しているのでそれに従います。

├── adapter
├── domain
├── usecase
├── hogehoge
└── .circleci/
    ├── config.yml
    └── images
        └── go
            └── Dockerfile

1. Dockerfile用意

今回はGo言語での開発のため、予めライブラリをgo getしたカスタムイメージを作成して利用することにします。
depも利用しているのでバージョン指定をしてdepのインストールも行います。
CircleCi純正のDockerイメージをベースに、カスタムしました。

.circleci/images/go/Dockerfile
FROM circleci/golang:1.11

ENV GOPATH /go
ENV DEP_VERSION 0.5.0

RUN curl -L -s https://github.com/golang/dep/releases/download/v${DEP_VERSION}/dep-linux-amd64 -o $GOPATH/bin/dep
RUN chmod +x $GOPATH/bin/dep

RUN go get -u golang.org/x/tools/cmd/goimports
RUN go get -u github.com/kisielk/errcheck
RUN go get -u golang.org/x/lint/golint
RUN go get -u bitbucket.org/liamstask/goose/cmd/goose
RUN go get -u github.com/client9/misspell/cmd/misspell

2. DockerHubにアップロード

CircleCIからDockerfileを利用する場合、用意したDockerfileをDockerHubにアップロードする必要があります。
方法としては直接アップロードする方式とGitHub等と連携して自動で更新する方法があるようです。今回は直接アップロードを行います。
また、下記操作をする前に予めリポジトリは任意の名前で作成してください。

$ cd path-to-project # プロジェクト直下へ
$ docker build --tag=hogehoge/foo:1.0.0 .circleci/images/go # tagは作成した任意のもの&初回は1.0.0が無難
$ docker login
$ docker push hogehoge/foo # tagは作成した任意のもの

3. CircleCIプロジェクト設定

CircleCIをGitHubに連携する方法に関してはこちらの記事がとても参考になりました。
今回は割愛します。
サンプルのconfig.ymlを作成するところまで進めてください。

4. config.yml用意

config.ymlはCircleCIのyml書式に従って記述します。
作成したconfig.ymlはコミットしてmasterブランチまで反映させてください。

.circleci/config.yml
version: 2

jobs:
  check:
    environment:
      - GOPATH: /go
      - APP_ENV: circleci
    working_directory: /go/src/github.com/path-to-project
    docker:
      - image: hogehoge/foo:1.0.0
        auth:
          username: hogeuser
          password: $DOCKERHUB_PASSWORD
      - image: circleci/mysql:5.7-ram
        environment:
          MYSQL_ROOT_PASSWORD: rootpw
          MYSQL_DATABASE: test
          MYSQL_USER: circleci
          MYSQL_PASSWORD: circleci
      - image: circleci/redis:5.0-alpine

    steps:
      - checkout

      - run: dockerize -wait tcp://127.0.0.1:3306 -timeout 120s
      - run: dockerize -wait tcp://127.0.0.1:6379 -timeout 120s

      - restore_cache:
          keys:
            - v1-vendor-{{ checksum "Gopkg.lock" }}
      - run:
          name: ensure
          command: |
            if [ ! -d vendor ]; then
              dep ensure -vendor-only
            fi
      - save_cache:
          key: v1-vendor-{{ checksum "Gopkg.lock" }}
          paths:
            - vendor

      - run: goose -env circleci up

      - run: go test -v ./...
      - run: find . -type f -name '*.go' -not -path "./vendor/*" -print0 | xargs -0 goimports -l | xargs -r false
      - run: find . -type f -name '*.go' -not -path "./vendor/*" -print0 | xargs -0 misspell -error
      - run: # その他もろもろの確認処理

workflows:
  version: 2
  setup-install-check:
    jobs:
      - check

5. CircleCIプロジェクト設定の調整

上記の設定のみでは要件が満たせないため、プロジェクトの設定を調整します。

実行タイミングの設定

初期設定ではすべてのコミットに対してCircleCIが実行されます。
今回はPull Request時のみにCircleCIを実行したいため、設定を変更します。

CircleCIプロジェクトからSetting > Advanced Settings に進み、「Only build pull requests」をOnに設定。
スクリーンショット 2019-10-21 18.29.14.png

これによって、PR時にのみ実行されるようになりますが、defaultブランチに対してのコミットは常に実行される点、注意です。
※defaultブランチはリポジトリごとに設定可能です。GitHubのSettingsから確認をしてみてください。

Slack通知の設定

CircleCIの実行結果をSlackに通知する設定を入れます。

CircleCIプロジェクトからSetting > Chat Notifications に進み、Slackの「Webhook URL」を設定。
SlackのWebhook URLは画面内のCircleCI Integrationリンクから遷移して取得することが可能です。
スクリーンショット 2019-10-21 18.30.17.png

環境変数の設定

DockerHubにカスタムイメージを置く際、セキュリティの関係でプライベートリポジトリを使う必要がある場合があります。カスタムイメージを取得する際に、CircleCIがユーザ情報を保持する必要があるのですが、config.ymlに記載するのは良くないでしょう。
そのため、環境変数にカスタムイメージ取得用アカウントのパスワードを持たせ、config.ymlから呼び出しています。

CircleCIプロジェクトからSetting > Environment Variables に進み、Add Variableをクリック。
スクリーンショット 2019-10-21 18.32.01.png

出てきたダイアログに環境変数名とその値を記載してAdd Variableをクリック。
スクリーンショット 2019-10-21 18.32.46.png

config.yml説明

ポイントだけ少し補足説明します。

Docker周り

今回はプライベートリポジトリにアップロードしているカスタムイメージを利用するため、最初のimage(実体はGo用のイメージ)に対してauthを設定しています。
$DOCKERHUB_PASSWORDは前項で設定した環境変数の値が適応されます。

MySQLイメージのenvironmentに各設定値を入力することで、その設定で起動されます。MYSQL_DATABASEを設定することでtestという名前のDBスキーマも作ることができます。

    docker:
      - image: hogehoge/foo:1.0.0
        auth:
          username: hogeuser
          password: $DOCKERHUB_PASSWORD
      - image: circleci/mysql:5.7-ram
        environment:
          MYSQL_ROOT_PASSWORD: rootpw
          MYSQL_DATABASE: test
          MYSQL_USER: circleci
          MYSQL_PASSWORD: circleci
      - image: circleci/redis:5.0-alpine

DB起動待機

今回はredisとmysqlのDockerイメージを利用するが、それらの起動を待つために下記の処理を行っています。

      - run: dockerize -wait tcp://127.0.0.1:3306 -timeout 120s
      - run: dockerize -wait tcp://127.0.0.1:6379 -timeout 120s

キャッシュの利用

depを利用して取得したライブラリはvendorに格納されるため、vendorをキャッシュ化しています。
depはライブラリの依存関係がGopkg.lockに反映されるため、Gopkg.lockのチェックサム値をキーとしてキャッシュを保存します。

処理としては下記の流れです。

  1. キャッシュが存在したら取得する(restore_cache)
  2. キャッシュが存在しなかった(vendorがリストアされなかった)場合、dep ensureを行う。
  3. vendorをキャッシュに保存する(save_cache)

なお、dep ensureの際にGopkg.lockが更新され、キャッシュ保存時にキー値が変わってしまう恐れがあるため -vendor-onlyをつけています。

      - restore_cache:
          keys:
            - v1-vendor-{{ checksum "Gopkg.lock" }}
      - run:
          name: ensure
          command: |
            if [ ! -d vendor ]; then
              dep ensure -vendor-only
            fi
      - save_cache:
          key: v1-vendor-{{ checksum "Gopkg.lock" }}
          paths:
            - vendor

※ 保持しているキャッシュを削除したい場合は、v1-vendor-の数値を書き換えるらしいです。

おわりに

Goのサンプルが少なめだったので参考になれば嬉しいです。

ayatothos
GoとFlutterが好き
andfactory
Smartphone Idea Companyとして、人々の生活に「&(アンド)」を届ける。
https://andfactory.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした