fleekでホストしているブログの記事だけをプライベートリポジトリに移した

2021/12/31

一日坊主ですが……

今年の1/1にブログを始めたにもかかわらず、一度も記事を揚げることなく大晦日を迎えてしまった。三日坊主どころが一日坊主である。

Twitterに脳死でうめき声を垂れ流すことに慣れてしまった今、ブログを書くことはあまりにも難しい。 それに加えて更新が滞っていた理由として、書きかけの記事を作りにくいという問題があった。 このブログがGitHubで公開リポジトリとなっており、書きかけの記事がmainブランチになくサイトでは公開されていないとしても、GitHubでは丸見えになっていたのである。 いや、プライベートリポジトリにしてしまえば解決するのだが、このブログもあまりにも寂しいGitHubのアカウントを少しでも賑やかそうとしたところがあり、できればパブリックのままにしておきたい。

そこで、ブログのレイアウト等を記述しているvueやcssファイルはそのままに、記事の中身にあたるmarkdownファイルを入れたディレクトリだけをプライベートリポジトリにすることにした。

構築手順

構築は以下の順で行う

  1. contentディレクトリを別リポジトリに移す
  2. git submoduleで1.で移したリポジトリを参照するようにする
  3. fleekでデプロイするとき、git submoduleも同時にcloneできるようにする

contentディレクトリを別リポジトリに移す

これは何も工夫することはなく、単に移すだけである。

@nuxt/contentは/contentディレクトリにあるmarkdownファイルを記事として扱い、このブログでは/content/posts以下に記事を入れるように設計している。詳しくはこちらの記事を参照。

そのため、postだけを移すことも考えたが、今後ディレクトリ構造を変更した際(つまりURL設計を見直したとき)、また同じ作業を実施するのはだるいのでcontentごと移すことにした。

ちなみに、ブログに挿入している画像は、/static以下においてあるので変わらずGitHubで丸見えなのだが、画像を選ぶのは大抵最後なので公開したままでも構わない。 将来画像もプライベートリポジトリに入れたくなったときは同様の手順を検討する。 (画像等のサイズによってはGit LFSの方が良いかもしれない)

git submoduleで1.で移したリポジトリを参照するようにする

続いてgit submoduleを導入する。 submoduleに分離することで、記事の執筆と更新の作業を分離し、うっかり公開されてしまうことを防ぐことができる。

上の手順で既に/contentディレクトリは削除されているので、/で以下を実行する

git submodule add git@github.com:PikkamanV/NaukaSiteContent.git

これで/.gitmoduleファイルが生成され、submoduleの追加が完了した。なお、HTTPSではなくSSHで追加した理由は後述する。

submoduleを追加するとVScodeのgit管理ウィンドウは以下のように変わる。

VScodeの左カラムのgit

この状態で/content以下を編集した場合NaukaSiteContentのウィンドウに変更したファイルが表示され、NaukaSiteの方は/contentだけに変更が入ったように表示される。 これはgit submoduleがsubmoduleで読み込んだリポジトリのコミットを参照しているからであり、そのリポジトリであるNaukSiteContent内のファイルを編集すると最終コミットから差分が生じるためである。 このNaukaSiteの/contentの方もコミットしてしまうと、NaukaSiteリポジトリが読んでいる先のコミットが変更されてしまうため、記事の意図しない公開を防ぐためには、NaukaSiteContentの方だけをコミットしておく。

まとめると、これからは以下の手順で記事の更新を行う。

  1. NaukaSiteリポジトリでcontent以下に移動する
  2. NaukaSiteContentリポジトリに入るので、新しくブランチを切る
  3. 新しく切ったブランチ上で記事を書く
  4. 記事を書き終わったらNaukaSiteContentのmainブランチにマージする
  5. NaukaSiteリポジトリに戻り、mainブランチのcontentが更新されている扱いになるので、それをコミット&プッシュする
  6. fleekがmainブランチの更新を検知し、mainブランチがデプロイされる。

fleekでデプロイするとき、git submoduleも同時にcloneできるようにする

最後にデプロイ時にプライベートリポジトリになっているNaukaSiteContentをfleekが読めるようにする。

fleekGitHubでアプリ連携を行ったとしても、ビルドするメインのリポジトリ以外にはアクセスしてくれない。 ためしにGitHubのアカウント設定から連携アプリでfleekを探し、既にアクセスが許可されていたNaukaSiteに加えてNaukaSiteContentを許可してもcloneはできなかった。 そこで、ビルド時に実行するコマンドを指定できるので、その中でGitHubに登録したdeploy keyによるSSH接続でcloneを行う。

具体的には以下の順で実行する。

  1. mkdir -p ~/.ssh
  2. echo "$DEPLOY_KEY" > ~/.ssh/id_ed25519
  3. perl -pe "s;😼;\n;g" -i ~/.ssh/id_ed25519
  4. chmod 600 ~/.ssh/id_ed25519
  5. git c core.sshCommand="ssh -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=no -F /dev/null" clone git@github.com:PikkamanV/NaukaSiteContent.git content
  6. git submodule update --init --recursive
  7. yarn && yarn build --target static
  8. yarn export

ただし、実際の設定画面では1行でしか指定できないので&&で各コマンドをつないでいる。(yarn exportはもう古いという話は一旦無視させていただく)

なお、先のsubmoduleでHTTPSではなくSSH接続を選んだ理由であるが、鍵の漏洩時の影響を最小限に抑えるためである。 GitHubの場合、personal access tokenを用いることでHTTPS接続でもプライベートリポジトリをcloneすることができる。 しかし、トークンはリポジトリごとではなくアカウントに紐付くため、あるサービスからトークンが漏洩すると、そのサービスに連携していないプライベートリポジトリまでもが編集可能になってしまう。 また、deploy keyの場合write権限を与えないこともできるので、もし漏洩したとしても、pushされるのを防ぐことができる。 よって設定が少々面倒ではあるが、SSH接続によってcloneすることが望ましい。

ただしwork aroundとして、fleekの管理画面ではdeploy keyそのものは登録できないので、環境変数として登録することにする。 さらに、環境変数は当然複数行では登録できないので、元の秘密鍵をあらかじめ決めた区切り文字(上の例では😼)で1行になるように加工し、読み込み前に改行に変換している。 そうして登録した秘密カ鍵を指定してNaukaSiteContentリポジトリをcloneし、git submodule updateでsubmoduleとして読み込んでいる。 こうすることでビルド時にcontentディレクトリの中身が存在するものとしてビルドすることができる。

おわりに

こうして書きかけの記事を公開することなくGitHubにpushすることができるようになった。また1つブログをサボる理由が失われてしまったとも言える。