Permission denied (publickey) on Travis.CI

タイトルで察した方は帰って結構です。

git submoduleというのがある。これは、別レポジトリをレポジトリの一部として管理できる機能で、要するに依存しているレポジトリのURLと対応するコミットをコードの一部として管理するものだ(大雑把すぎる)。すると依存レポジトリのバージョンをgitで一括で管理できるようになる。

$ git submodule add <repo URL>
# その後
$ git submodule init
$ git submodule update
# または、上記を一括で
$ git submodule update --init
# submodule の submodule まで再帰的に
$ git submodule update --init --recursive

submoduleも一つの独立したgitディレクトリとして振る舞うので、そこでpullしてから上でaddすることによって「依存関係にあるレポジトリのバージョンを上げる」という変更をgitで記録できる。

さて、このようなことを実践したレポジトリをpushしたところ、Travisが落ちた。Permission denied (publickey)と言われている。gitのsshプロトコルでアクセスした場合、sshの鍵がないとダウンロードできない(sshでログイン出来ないので)。もちろん、自分の秘密鍵を公開レポジトリに置くような馬鹿はいない。よって、submoduleをダウンロードできず、CIは失敗する。

さてどうしたものか。 とりあえずググると、Gistに解決策が転がっていた。まず、Travisが自動で行うgit clone --recursiveをやめさせる(git: submodules: false)。続いて、sedgit@github.comhttps://github.comに変換する。力技だ。

Travis-CI submodules · GitHub

確かにこれはLinuxでなら動くが、OS Xだと動かない。OS XUnixでありLinuxではないので、コマンドの挙動がほんの少しずつ異なる。以下に同じ問題に苦しめられた人間の怨嗟の声がある。

Sed: 'sed: 1: invalid command code R' on Mac OS X

何が起きているかというと、sed -iはファイルをその場で(in-place)書き換える。これは怖いので、sedはバックアップファイルを作りたいと思っている。そのバックアップファイルの拡張子を-iオプションの引数として要求されているのだが、我々はそれを渡さず、代わりにsedスクリプトと変更して欲しいファイルを渡した。するとsedスクリプトをバックアップファイルの拡張子と思い込み、続くファイル名をsedスクリプトだと思って実行しようとして、「そんなコマンドはない」と返しているというわけだ。

回避するには、適当な拡張子をくれてやればいい。あるいは、空の文字列を渡せばそもそもバックアップファイルは作られない。

# この""が必要
$ sed -i "" 's/hoge/foo/g' foobar.dat

あとはこれで、Travisで環境を見て分岐してから実行して終わりだ。