理系学生日記

おまえはいつまで学生気分なのか

ReviewdogをGitLabで使うときに`failed to get merge-base commit`が発生する

CIで実行した静的解析の結果をMerge Requestのコメントとして書き込みたいというニーズは多くあります。 これを容易に叶えてくれるプロダクトがreviewdogです。

問題

このreviewdogをGitLab CI/CDに設定したのですが、以下の様なエラーが出て失敗してしまうのです。

reviewdog: fail to get diff: failed to get merge-base commit: exit status 1

解決法とその理由

これが最善なのか、他に方法がないのかというとなかなか答えに窮しますが、以下のようにして解決できました。 要するに、ジョブの変数としてGIT_STRATEGYGIT_DEPTHを設定するということです。

unittest:
  (snip)
  variables:
    GIT_STRATEGY: clone
    GIT_DEPTH: 0
  script:
  (snip)

この意図なのですが、前提としてreviewdogではfeature branchとtarget branchの共通の祖先を探すべくgit merge-baseを実行します。

func (g *MergeRequestDiff) gitDiff(_ context.Context, baseSha, targetSha string) ([]byte, error) {
    b, err := exec.Command("git", "merge-base", targetSha, baseSha).Output()
    if err != nil {
        return nil, fmt.Errorf("failed to get merge-base commit: %w", err)
    }

従ってreviewdogの動作前提は、CIランナーのGitローカルリポジトリの中に、その両branchとそれらのコミットが存在していることです。

GitLabでのリポジトリ取得仕様

GitLab Runnerがリモートリポジトリからコンテンツをどのように取得するかは、 Choose the default Git strategyに定められています。

プロジェクトのCI/CDの設定として位置付けられており、各CIジョブは特別な指定がなければこの設定に従います。 以下がデフォルト設定。

reviewdogの動作前提を満たす

Reviewdogの動作前提を満たすためには、確実にcloneし、取得する歴史も無制限にしてやれば良いでしょう。 もちろん巨大な歴史を持つリポジトリなら軽々に判断できない話ですが、今回ぼくが使うリポジトリの歴史は大したことがありません。

これらを設定するのがGIT_STRATEGYGIT_DEPTHという2つの変数です。ドキュメントは以下。

GIT_STRATEGYclonefetchnoneを指定できます。 cloneを指定すると無条件でgit cloneしてくれるため、GitLab Runnerのローカル状態がどうであっても、target branchを取得することが保証されます。

GIT_DEPTHはいわゆるShallow Cloneを行うか否かで、"0"を指定することでShallow Copyを無効にしています。