ENECHANGEのSRE Infraチームの id:tockeysan です。
先日のAIリレーブログではClaude Codeを利用してOSSを読み、弊社に合ったoctocovの使い方を模索した話をしました。
CluadeCodeでOSSを読み解く - 導入時のエラーに立ち向かう - ENECHANGE Developer Blog
この記事はそのoctocovの導入編になります。
前提
前の記事の繰り返しですが、全プロダクト横断的な取り組みをする前は以下のような状態でした。
- コードカバレッジツールの導入が各チームに依存しており、導入されていないプロダクトが複数存在する
- 導入されているコードカバレッジツールがバラバラで、横断的な分析ができない
- 仮に導入を進めたとしてもプロダクト数が非常に多いので各プロダクトがどの程度のカバレッジ率なのかを把握することが難しい
導入するにあたっての課題
弊社ではCIツールとしてGitHub Actionsの他にBuildkiteを利用していますが、octocovはGitHub Actionsでの利用を前提としていました。理想は全てのリポジトリでoctocovを導入することです。Buildkiteを利用しているリポジトリをGitHub Actionsに移行するのは現実的ではなく、Buildkiteでのテスト実行はそのままにoctocovも利用したいということが必要になってきます。
Buildkite + octocov with GitHub Actions
そこでBuildkiteのCIパイプラインに手を加え、最後のステップにGitHub Actions(repository_dispatch)を呼び出す構成をとることにしました。repository_dispatchはHTTPリクエストによって起動するタイプのGitHub Actionsです。
sequenceDiagram
participant Dev as Developer
participant GH as GitHub
participant BK as Buildkite
participant S3 as S3 Storage
participant GHA as GitHub Actions
participant PR as Pull Request
Dev->>GH: Push to PR branch
GH->>BK: Trigger Buildkite pipeline
rect rgb(240, 248, 255)
Note over BK: Buildkite Pipeline
BK->>BK: Build
BK->>BK: Test with Knapsack
BK->>BK: Generate coverage report
BK->>S3: Upload .resultset.json
BK->>GH: curl repository_dispatch
end
rect rgb(245, 255, 245)
Note over GHA: GitHub Actions (octocov)
GH->>GHA: Trigger octocov workflow
GHA->>S3: Download coverage data
GHA->>GHA: Run octocov
GHA->>GHA: Generate coverage report
GHA->>PR: Post coverage comment
end
PR-->>Dev: Coverage report visible
Buildkiteパイプライン
repository_dispatchはPRには紐づかないため、そのままでは上記のフローにおける Post coverage comment では対象のPRを特定することができません。そのため、Buildkiteパイプライン側からPR等の情報を渡してあげる必要があります。BuildkiteパイプラインにはPRのブランチ名などをはじめ様々な環境変数が用意されているので、これらの変数を渡すこと自体はさほど難しくありません。
一部略...
json_payload="{
\"event_type\": \"buildkite-build-complete\",
\"client_payload\": {
\"build_number\": \"${BUILDKITE_BUILD_NUMBER}\",
\"state\": \"passed\",
\"branch\": \"${BUILDKITE_BRANCH}\",
\"commit\": \"${BUILDKITE_COMMIT}\",
\"pull_request\": \"${BUILDKITE_PULL_REQUEST}\",
\"pipeline\": \"${BUILDKITE_PIPELINE_SLUG}\"
}
}"
curl -X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${GITHUB_API_TOKEN}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/${ 組織名 }/${BUILDKITE_PIPELINE_SLUG}/dispatches \
-d "$json_payload"
GitHub Actions
続いて、呼び出されるGitHub Actionsのコードです。
name: Coverage Report with Octocov on: repository_dispatch: types: [buildkite-build-complete] permissions: id-token: write contents: write pull-requests: write issues: read actions: read jobs: coverage: runs-on: ubuntu-latest if: github.event.client_payload.state == 'passed' env: PR_BRANCH: ${{ github.event.client_payload.branch }} PR_COMMIT: ${{ github.event.client_payload.commit }} steps: - uses: actions/checkout@v4 with: ref: ${{ env.PR_BRANCH }} - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: ${{ secrets.AWS_ROLE_ARN }} aws-region: ap-northeast-1 - name: Download Coverage Report run: | aws s3 cp s3://${{ バケット名 }}/coverage/${{ env.PR_COMMIT }}/.resultset.json coverage/.resultset.json - name: Run Octocov uses: k1LoW/octocov-action@v1 with: config: .octocov.yml work-dir: ${{ github.workspace }} env: OCTOCOV_GITHUB_REF: refs/heads/${{ env.PR_BRANCH }} OCTOCOV_GITHUB_SHA: ${{ env.PR_COMMIT }}
以下がポイントです。
1.カバレッジレポートの受け渡し
octocovはカバレッジレポートそのものを生成するものではなく、simplcovで生成したレポートを渡すことで機能します。simplcovレポートはBuildkiteパイプライン上で生成されるため、GitHub Actions側に明示的に受け渡す処理が必要です。そこでsimplecovレポートを一度S3にアップロードしておき、GitHub Actions側でダウンロードするということをしています。S3のsimplecovレポートはコミットハッシュをprefixに含めることで、リポジトリ側から簡単に特定できるようにしています。
実装例ではRails+simplecovを利用していますが、他言語でもサポートされているフォーマットのレポートが生成できればoctocovを利用できます。
2.環境変数のOverride
この機能があったからこそ、この構成が実現できました。GitHub Actionsにはデフォルトで用意されている環境変数があり、
octocovステップの実行時にOCTOCOV_というプレフィックスを付けた環境変数を設定することでその変数を上書きすることができます。OCTOCOV_GITHUB_SHAとOCTOCOV_GITHUB_REFを指定して上書きすることで、無事PRに対してoctocovのコメントがされました。

なお、withでconfigとwork-dirの指定も必要でした。指定しなかった場合.octocov.yml and octocov.yml are not foundとなってしまい正常に動きませんでした。repository_dispatchを使用しているため起こった事象かもしれません。
.octocov.yml
あとはoctocov自体の設定のみです。ここはほとんどREADMEにあるサンプル通りです。
coverage: paths: - coverage/.resultset.json codeToTestRatio: code: - "app/**/*.rb" test: - "spec/**/*spec.rb" comment: if: is_pull_request summary: if: true diff: datastores: - artifact://${GITHUB_REPOSITORY} report: if: is_default_branch datastores: - artifact://${GITHUB_REPOSITORY}
制約
特殊な使い方をしているため制約もあります。repository_dispatchはPRによって直接トリガーされるactionではないため以下のようなことが出てきました。
- テスト実行はBuildkiteで行われるためテスト実行時間をoctocovに渡せずバッジ生成ができない
- PRのステータスチェック欄に表示されない
- そのためoctocovのカバレッジ率をマージ条件にする設定が(おそらく)動かない
この制約はやむを得ないものとして割り切っています。
複数リポジトリのカバレッジを管理できるCentralモード
octocovにはCentralモードという機能があり、複数リポジトリのoctocovレポートを集約用のリポジトリに集めて一覧化することができます。弊社はプロダクト(リポジトリ)が非常に多いため、この一覧機能が大変助かっています。バッジも生成することができ各リポジトリのREADMEにペタリと貼れるのでこちらも便利です。

Centralリポジトリ用の.octocov.ymlとGitHub Actionsワークフローのyamlはサンプルコードをほとんどそのまま利用していますが、留意点としてはPrivateリポジトリを収集する時は対象リポジトリの参照権限があるアクセストークンを設定する必要があります。
name: Collect on: workflow_dispatch: schedule: - cron: '0 0,3,6,9 * * *' # JST 9時,12時,15時,18時 push: branches: - main jobs: collect: name: Collect metrics using central mode of octocov runs-on: ubuntu-latest env: GH_TOKEN: ${{ secrets.OCTOCOV_GITHUB_TOKEN }} DEBUG: true steps: - name: Check out source code uses: actions/checkout@v4 - name: Run octocov uses: k1LoW/octocov-action@v1
Centralモードは導入設定がシンプルながら、簡単にカバレッジ管理をすることができます。
まとめ
octocovでコードカバレッジを計測し、Centralモードで管理した取り組みについて紹介しました。なかでもBuildkiteとのCI併用は少々苦労しました。試行錯誤の結果、統一的なツールを選定したことで、アプリチームのカバレッジ率への関心を高め、継続的な運用の下地を作ることができました。今後はこのCentralモードによってできたリストを元に運用の議論を進めることができそうです。
GitHub Actions以外のCIでテストを実行している環境でoctocovを導入したい方の参考になれば幸いです。