Deploy With Github Private Repos

submoduleにGitHubのprivate repoがある場合、Herokuへのデプロイがさくっといくかと思ったらガツッとハマったので、メモとして残しておきます。 ちなみに、以下はRailsアプリでの例です(他のフレームワークでも応用が効くとは思いますが、効かないかもです)。基本的にはHerokuの公式ドキュメントを見ていただければ載っているので、それで事足りそうな方はそちらに飛んでください。

まず、ローカルで幸せに開発していたときは、githubにある他のrepoをsubmoduleとしてaddするときは以下の様なコマンドでやってました。ここでは、アプリフォルダの中のvendorの中にprivate repoなgemたちを突っ込んでいる感じです。

$ git submodule add git@github.com:keiko713/some_gem.git vendor/some_gem

この場合は、GitHubのSSHキーがローカルのマシンに登録してあれば、some_gemがprivate repoであろうがなかろうが、submoduleとしてvendor/some_gem以下に登録されます。GitHub上で見てもその部分はリンクになっていて、クリックするとそのrepoにジャンプできます。

ここでHerokuにアプリをデプロイしたい場合、もしaddしたsubmoduleがprivate repoでなければ、git push heroku masterの結果は次のようになり成功します(以下はdeviseをsubmoduleとしてaddした例)。

$ git submodule add git://github.com/plataformatec/devise.git vendor/devise
-----> Git submodules detected, installing
Submodule 'vendor/devise' (git://github.com/plataformatec/devise.git) registered for path 'vendor/devise'
Initialized empty Git repository in /tmp/build_1qsjqayd6a5g6/vendor/devise/.git/
Submodule path 'vendor/devise': checked out '7c8f636b98810c21c339df484258c0b1446c0d43'

しかし、これがprivate repoの場合、残念なことに次のようなエラーが出ます(以下はprivate repoであるsome_private_repoをaddした例)。

$ git submodule add git://github.com/keiko713/some_private_repo.git vendor/some_private_repo
-----> Git submodules detected, installing
Submodule 'vendor/devise' (git://github.com/plataformatec/devise.git) registered for path 'vendor/devise'
Submodule 'vendor/some_private_repo' (git@github.com:keiko713/some_private_repo.git) registered for path 'vendor/some_private_repo'
Initialized empty Git repository in /tmp/build_3lbuhu9ljt94n/vendor/devise/.git/
Submodule path 'vendor/devise': checked out '7c8f636b98810c21c339df484258c0b1446c0d43'
Initialized empty Git repository in /tmp/build_3lbuhu9ljt94n/vendor/some_private_repo/.git/
Host key verification failed.
fatal: The remote end hung up unexpectedly
Clone of 'git@github.com:keiko713/some_private_repo.git' into submodule path 'vendor/some_private_repo' failed
! Heroku push rejected, Submodule install failed

今回は、Resolving Application Dependencies with Git Submodulesのドキュメントの中にあるProtected Git submodulesを参考にしてみました。

まず、今追加してしまった分のsome_private_repoを削除します(参考: Stack Overflow)。

  • .gitmodulesの中の該当submoduleの部分を削除
  • .git/configの中の該当submoduleの部分を削除
  • git rm –cached vendor/some_private_repo(後ろにスラッシュはつけない)
  • コミットして、untrackedになっているvendor/some_private_repoフォルダを削除

次に、対象のprivate repoにアクセス可能なユーザー名とパスワードを付けて然るべき手順でsubmoduleをaddしていきます。

$ git submodule add https://username:password@github.com/keiko713/some_private_repo vendor/some_private_repo
-----> Git submodules detected, installing
Submodule 'vendor/devise' (git://github.com/plataformatec/devise.git) registered for path 'vendor/devise'
Submodule 'vendor/some_private_repo' (https://username:password@github.com/keiko713/some_private_repo) registered for path 'vendor/some_private_repo'
Initialized empty Git repository in /tmp/build_3dbb0x2kdopen/vendor/devise/.git/
Submodule path 'vendor/devise': checked out '7c8f636b98810c21c339df484258c0b1446c0d43'
Initialized empty Git repository in /tmp/build_3dbb0x2kdopen/vendor/some_private_repo/.git/
Submodule path 'vendor/some_private_repo': checked out '7c8f636b98810c21c339df484258c0b1446c0d43'

成功!ということでちょっとした変更で簡単に立ち上がりました。

ここで注意したいのが、この方法でデプロイをすると、.gitmodulesファイルにusernameとpasswordが残ってしまうという問題です。.gitmodulesはたいていrepoに上げていると思うので、public repoでこれをしてしまうとパスワード等がバレバレです。そもそもprivate repoなgemを使っている時点で、アプリ側のrepoもprivateであることが想像されるので、Herokuデプロイ用のユーザーなどを作ればいいかもしれませんが、セキュリティ的に許容しがたい場合は他の方法を探ってください。

Herokuのドキュメントの中には他にVendoringPrivate dependency repositoriesの方法が載っていましたが、前者は試行錯誤の上残念ながらうまく行かず、後者は試していません。他にもStack Overflow にGemfile中でやりくりする方法(ENVを使ってusername/passwordを設定するのでよさげだった)やここを参考に生成したOAuth tokenを使ってやる方法も載ったりしていましたが、なんだかうまく行かず、結局上記の方法が一番シンプルでサクッと出来ました。

もっといい方法が見つかったらまた追記したいと思います。(その前にHerokuじゃないところにデプロイすることになりそうだけど…)

ではでは