こうさくきろく

つくるのたのしい

Cloud Build から Code Climate にテストレポートを送信する

Cloud Build から Code Climate にテストカバレッジを含むテスト結果を送信しようとしたところ、ひと手間必要だったので、その手順を紹介します。

Code Climate Test Reporterの実行方法

Getting Started にあるように、Test Reporter のバイナリをダウンロードして実行することで、Code Climate にテスト結果を送信できます。

docs.codeclimate.com

Linux 環境であれば、Git リポジトリ内で下記のコマンドを実行します。 (事前に Code Climate 側でリポジトリの設定とトークンの発行をしておく必要があります)

# 実行ファイルの取得
curl -L \
  https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 \
  ./cc-test-reporter
chmod +x ./cc-test-reporter

# 実行前の準備
./cc-test-reporter before-build

# テスト結果の送信(SimpleCovの場合)
CC_TEST_REPORTER_ID=XXXXXXXXXXXXXXX ./cc-test-reporter after-build -t simplecov

今回はテストレポートを SimpleCov で出力したため -t simplecov としていますが、このオプションはテスト環境に応じて置き換えてください。

Cloud Buildでの実行

GitHub から Cloud Build への連携は GitHub Apps として Cloud Build に登録しておきます。

f:id:mukopikmin:20200115210227p:plain

Cloud Build で実行する場合も手順は変わりませんが、Cloud Build で取得されるリポジトリには .git ディレクトリが含まれていないことに注意する必要があります。

cc-test-reporterは実行時に、Git リポジトリの下記の情報を利用しています。

  • ブランチ名(GIT_BRANCH
  • コミットハッシュ(GIT_COMMIT_SHA
  • コミットタイムスタンプ(GIT_COMMITED_AT

.gitディレクトがないとこれらの情報が取得できないので、手動で与えるか、別の手段で .git ディレクトリを取得する必要があります。

手動で与える場合

手動で必要な情報を与える場合は、下記のスクリプトのように GIT_COMMITED_AT を手動で与える必要があります。

今回は .git ディレクトリがなく本来のコミットタイムスタンプを取得でないため、現在時刻を代わりに与えています。 なお、このタイムスタンプは Unixtime で与える必要があります。

#! /bin/sh

set -ex

curl \
  -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 \
  > ./cc-test-reporter
chmod +x ./cc-test-reporter

GIT_COMMITTED_AT=$(date +%s) ./cc-test-reporter $@

このスクリプトを使う場合の、cloudbuild.ymlは下記のようになります。

steps:
  # テスト用のイメージのビルド
  - name: gcr.io/cloud-builders/docker
    args: 
      - build
      - -t
      - gcr.io/$PROJECT_ID/$REPO_NAME:$SHORT_SHA
      - .
  # Test Reporter実行前の準備
  - name: gcr.io/$PROJECT_ID/$REPO_NAME:$SHORT_SHA
    dir: /app
    entrypoint: sh
    args:
      - scripts/test_report.sh
      - before-build
  # テストの実行
  - name: gcr.io/$PROJECT_ID/$REPO_NAME:$SHORT_SHA
    dir: /app
    args: 
      - bundle
      - exec
      - rake
      - spec
    volumes:
      - name: coverage
        path: /app/coverage
  # テスト結果の送信
  - name: gcr.io/$PROJECT_ID/$REPO_NAME:$SHORT_SHA
    entrypoint: sh
    dir: /app
    args:
      - scripts/test_report.sh
      - after-build
      - -t
      - simplecov
    env:
      - CC_TEST_REPORTER_ID=XXXXXXXXXXXXXXX
      - GIT_COMMIT_SHA=$COMMIT_SHA
      - GIT_BRANCH=$BRANCH_NAME
    volumes:
      - name: coverage
        path: /app/coverage

GIT_COMMIT_SHAGIT_BRANCH は Cloud Build でのビルド実行時に変数として与えるために変数名を変えて与えています。

一応、結果は送信されているようですが、コミットタイムスタンプに適当なものを与えている点が気になります。

.gitディレクトリを取得する場合

.gitディレクトリなしでパラメーターを与える場合、どうしてもコミットタイムスタンプなどのリポジトリ固有の情報を取得できません。

コミットタイムスタンプの正しい値を取得するためには、Git リポジトリの情報(.gitディレクトリ)が必要になります。 これを取得するアプローチを取った cloudbuild.yml は次のようになります。

steps:
  # リポジトリの取得
  - name: gcr.io/cloud-builders/git
    dir: /git
    args:
      - clone
      - https://github.com/user/repo.git
      - .
    volumes:
      - name: git
        path: /git
  # コミットタイムスタンプをボリュームに書き出す
  - name: gcr.io/cloud-builders/git
    entrypoint: sh
    dir: /git
    args:
      - -c
      - "git show -s --format=%ct $COMMIT_SHA > /git/timestamp"
    volumes:
      - name: git
        path: /git
  # テスト用のイメージのビルド
  - name: gcr.io/cloud-builders/docker
    args: 
      - build
      - -t
      - gcr.io/$PROJECT_ID/$REPO_NAME:$SHORT_SHA
      - .
  # Test Reporter実行前の準備
  - name: gcr.io/$PROJECT_ID/$REPO_NAME:$SHORT_SHA
    dir: /app
    entrypoint: sh
    args:
      - scripts/test_report.sh
      - before-build
    volumes:
      - name: git
        path: /git
  # テストの実行
  - name: gcr.io/$PROJECT_ID/$REPO_NAME:$SHORT_SHA
    dir: /app
    args: 
      - bundle
      - exec
      - rake
      - spec
    volumes:
      - name: coverage
        path: /app/coverage
  # テスト結果の送信
  - name: gcr.io/$PROJECT_ID/$REPO_NAME:$SHORT_SHA
    entrypoint: sh
    dir: /app
    args:
      - scripts/test_report.sh
      - after-build
      - -t
      - simplecov
    env:
      - CC_TEST_REPORTER_ID=XXXXXXXXXXXXXXX
      - GIT_COMMIT_SHA=$COMMIT_SHA
      - GIT_BRANCH=$BRANCH_NAME
    volumes:
      - name: coverage
        path: /app/coverage
      - name: git
        path: /git

この処理では、gitコマンドが使えるコンテナ内でリポジトリを取得し、以降の処理で必要になる情報をボリュームにファイルとして書き出しています。 このようにすることで、リポジトリのコミット情報を以降の処理で再利用できます。

リポジトリの情報であれば同様の手順で利用できるので、例えばコミットメッセージを利用したい場合は下記のステップを追加することで実現できます。

steps:
  # コミットメセージをボリュームに書き出す
  - name: gcr.io/cloud-builders/git
    entrypoint: sh
    dir: /git
    args:
      - -c
      - "git log --format=%B -n 1 $COMMIT_SHA > /git/message"
    volumes:
      - name: git
        path: /git

取得した値の参照は下記のようなスクリプトで利用できます。

#! /bin/sh

set -ex

curl \
  -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 \
  > ./cc-test-reporter
chmod +x ./cc-test-reporter

GIT_COMMITTED_AT=$(cat /git/timestamp) ./cc-test-reporter $@

まとめ

CI サービスでは、.gitディレクトリがないためリポジトリに関する情報を CI で再利用しにくいことがあります。 Cloud Build では上記の手順でボリュームに一時的に書き出すことでリポジトリの情報を利用できます。