GitLab CIで同GitLabプロジェクト内への参照(submodule)のあるリポジトリを扱う


GitLab/GitLab CIで隣接プロジェクトへのsubmoduleありのリポジトリを扱っていて、ハマっていたのでメモ。

GitLab CIはデフォルトでsubmoduleは引っ張ってこないので、 GIT_SUBMODULE_STRATEGY を設定しよう

GitLab CIはデフォルトでsubmoduleは無視します。

下記のように GIT_SUBMODULE_STRATEGY に適当な値を指定しましょう。

.gitlab-ci.yml
something_to_do:
  stage: test
  variables:

    # "none" (デフォルト): submoduleは引っ張ってこない
    # "normal": トップレベルのsubmoduleのみ引っ張ってくる (submodule内は解決しない)
    # "recursive": submoduleのsubmodule といった入れ子も解決する
    #
    # cf. https://docs.gitlab.com/ee/ci/yaml/README.html#git-submodule-strategy
    GIT_SUBMODULE_STRATEGY: "recursive"

  script:
    - ...

基本的にはこれで問題ないのですが、残念ながらこれでも submodule を引っ張ってこれないケースがあります。

同GitLabインスタンス内のプロジェクトのsubmoduleが引っ張ってこれない場合は、相対URL(../project-name.git)で参照しよう

同GitLabインスタンスの兄弟プロジェクトを別プロジェクトから参照するなど、よくあるケースだと思うのですが、その参照の際に、下記のように絶対URLで参照しているとGitLab CIがcloneできないことがあります。 (特にDockerでGitLabランナーをたてている場合など)

.gitmodules
[submodule "path/to/somewhere"]
    path = path/to/somewhere
    url = ssh://[email protected]/some-group/slave-project.git

エラーとしては、下記のようなものが出たりします。また、httpであっても、リポジトリ内容が取得できなかったりします。

error: cannot run ssh: No such file or directory
fatal: unable to fork

SSHをGitLabランナーが使えるようにするのか? HTTPにして、HTTPの認証をどうにかするか? たかだか同一GitLab内のリポジトリなのになんで参照できないんだ? と思うのは当然ですね。

相対URLを使えば、問題なく参照できます。 公式マニュアルもそのように指示しています。 下記のような参照の方法ですね。

.gitmodules
[submodule "path/to/somewhere"]
    path = path/to/somewhere
    url = ../slave-project.git

# あるいは ../../some-group/slave-project

「そもそも git submodule で相対URLなんて使えるの?」 と思うかもしれませんが、使えます。

<repository> is the URL of the new submodule’s origin repository. This may be either an absolute URL,
or (if it begins with ./ or ../), the location relative to the superproject’s default remote repository

(Please note that to specify a repository foo.git which is located right next to a superproject bar.git, you’ll have to use ../foo.git instead of ./foo.git - as one might expect when following the rules for relative URLs - because the evaluation of relative URLs in Git is identical to that of relative directories).

引用元: https://git-scm.com/docs/git-submodule

cloneしたディレクトリではなく、親プロジェクトのデフォルトのリモートリポジトリに対して相対になると書いてあります。

そして、GitLabの同一グループの兄弟プロジェクトであれば、 ../project-name.git みたいに参照するのがよさそうですね。

実際、上記URLを使えばGitLab CIランナーはちゃんとsubmoduleをクローンしてくれます!やったね! 👌

(ちなみにインターネットで公開されているリポジトリをsubmoduleに追加する場合は何もしなくてもうまくいきます。)

追記: 正しく上記をやっているはずなのにGitLab CIで失敗する場合

もし、上記を正しく実施しているのに、下記のメッセージが出る場合、

Updating/initializing submodules recursively...
Synchronizing submodule url for 'slave-dir/'
fatal: not a git repository: slave-dir/../../.git/modules/slave-pj

現状(2019/06/05)、GitLab CI Runnerに問題があるようなので、CI Runnerを走らせているマシンで、下記を走らせると解決します。(しました)

$ docker system prune