Go
Vendoring
CircleCI2.0

githubにcommitをpushしたらCircleCIでgo buildを実行できるようにする

設定ファイル

  • version: 2でCircleCI 2.0の設定と明示する
  • build用のdocker imageはcircleciが用意しているものを使用する

基本的な流れは以下

  1. キーからキャッシュを復元
  2. もしvendorがなければdep ensureを実行
  3. depもなければインストール
  4. dep自体とvendor以下をキャッシュに保存
  5. go build
#.circlci/config.yml
version: 2
  build:
    working_directory: /go/src/github.com/tanden/go-echo-with-mysql/

    docker:
      - image: circleci/golang:1.10

    steps:
      - checkout

      - restore_cache:
          keys:
              - v1-vendor-{{ .Branch }}-{{ checksum "src/Gopkg.lock" }}
              - v1-dep

      - run:
          name: dep ensure
          command: |
              cd src/
              if [ ! -d vendor ]; then
                if ! type dep >/dev/null 2>&1; then
                  go get -u github.com/golang/dep/cmd/dep
                fi
                dep ensure
              fi
      # ローカルとcircleci上でgo getしたdepのversionが異なると
      # dep ensureしたときにGopkg.lockのchecksumが変わってしまい
      # 別のkeyで保存され、restore_cacheで取り出せない
      - save_cache:
          key: v1-vendor-{{ .Branch }}-{{ checksum "src/Gopkg.lock" }}
          paths:
              - src/vendor

      # depをキャッシュする
      - save_cache:
          key: v1-dep
          paths:
              - /go/bin/dep

      - run:
          name: go build
          command: |
              go build -v -o src/app src/server.go


depとvendorのキャッシュ

パッケージをdep管理しているので、CircleCI上のコンテナでdep ensureコマンドを実行しvendor以下にパッケージをインストールします。

ただ、Gopkg.lockの内容に変化がない(使用しているパッケージが変わらない)場合、前回と同じインストールされたパッケージを使いたい。インストールに6〜7秒かかるので(毎回行われるので合計するとバカになりません)

なので、depコマンド自体と、vendor以下をCircleCIのキャッシュ機能をつかってキャッシュさせます。

キャッシュクリアするにはキーの名前を変える

キャッシュクリアをするために、都度キーの名前を変えるてしまうのがよいようです(restore_cacheをいちいち消して、キャッシュをリストアせずに新しくインストールしてキャッシュした値を更新する、、、などしなくてよくなります)

ドキュメントでは、v1などのバージョンプレフィックスをつけてキーの名前を変えていくことを推奨しています

https://circleci.com/docs/2.0/caching/#clearing-cache

はまったこと:vendorをキャッシュできない

vendorをキャッシュできず、はまりました。

src/Gopkg.lockのchecksumの値をキャッシュのキーにしているのですが、commitしているGopkg.lockとCircleCIのコンテナ上にcloneしたGopkg.lockのchecksumが異なりrestore_cacheでリストアできませんでした。

自分のローカルのdepのバージョンが古く、最新のdep(CirclCIでgo getしたdepのバージョン)では、Gopkg.lockのフォーマットが異なるようです。

  1. checkoutでcloneしたリポジトリ上のGopkg.lockのchecksumでrestore_cacheを行う
  2. restoreできない
  3. 再度 dep eusureする
  4. Gopkg.lockのchecksumが変わる
  5. 変わった後のchecksumを使ったkeyでキャッシュを保存してしまう
  6. 1でrestoreできない

CircleCI上のコンテナにインストールしているdepのバージョンと、ローカルのバージョンを同じにして再度dep initを行なって、新しいGopkg.lockをcommitしなおすと想定通りキャッシュしてくれるようになりました!