はじめに
タイトルのとおりですが、意外と苦労したのでやり方をまとめておきます。
使う道具
- CirleCI 2.0
- markdown-pdf
- MarkdownをPDFに変換するためのCLIツール
- npmでインストール
- gdrive
- Googleドライブを操作するためのCLIクライアント
- PDFのアップロードに使う
バイナリをダウンロードしてインストール- ソース(golang)をコンパイルしてインストール(後述)
具体的な方法
事前準備
CircleCIからGoogleドライブにファイルをアップロードするためには、サービスアカウント での認証が必要なので、以下のとおり準備しておきましょう。
- Google API Console でサービスアカウントを作る
- デプロイ先にしたいGoogleドライブ上のフォルダを、サービスアカウントに共有する
- CircleCIのプロジェクト設定で、サービスアカウントの認証情報のJSON文字列を一行化して環境変数として登録する
markdown-pdfでのPDF生成方法
例えば、src/
配下にMarkdownファイル群が階層構造で格納されているとして、それらを同じ階層構造で build/
配下に拡張子だけを .pdf
に変えて出力したい場合、以下のようなシェルスクリプトで実現できます。
for file in `find src -type f` ; do
name=`echo $file | sed -r 's/src\\/(.*)\\.md/\\1/'` # src/<ファイル名>.md から <ファイル名> を取り出す
npx markdown-pdf -s css/style.css -o build/$name.pdf $file
done
-s css/style.css
でレンダリングに使用するCSSファイルを指定しています。これは本来は必須ではありませんが、こちらで指摘されているとおり、デフォルトのCSSだと [text](url)
というMarkdownが text (url)
という表記に変換されてしまうため、これを回避するために最低限以下のCSSを当てる必要があります。
abbr[title]:after,
a[href]:after {
content: "";
}
GitHub風のCSSを適用
markdown-pdfはMarkdownパーサーとして remarkable を使っており、remarkableはデフォルトで GFM(GitHub Flavored Markdown)をコンパイルできるようです。
せっかくなのでGitHub風のCSSを適用して、それらしい見た目でPDFが生成されるようにしておきましょう。
とりあえず今回は泥臭く、github-markdown-cssのcss をコピペして .markdown-body
を body
に置換しました。フォントサイズも必要に応じて変更するとよいでしょう。
body
に置換すればいいと判断したのは、markdown-pdfのデフォルトのcss がそうなっていたからです。
ワンライナー化してpackage.jsonにscriptsとして追加
以下のようにワンライナー化して、npm scriptsから実行できるようにしておくと便利です。(ついでに、ビルド時に build/
配下を一旦全削除するようにしてあります)
{
"dependencies": {
"markdown-pdf": "^8.1.1"
},
"scripts": {
"build": "rm -rf build/* && for file in `find src -type f` ; do npx markdown-pdf -s css/style.css -o build/`echo $file | sed -r 's/src\\/(.*)\\.md/\\1/'`.pdf $file ; done"
}
}
gdriveでのアップロード方法
gdriveコマンドで build/
ディレクトリを丸ごとGoogleドライブの特定のフォルダ配下にアップロードする方法は、以下のとおりです。
gdrive --config $(pwd) --service-account credential.json upload -p <ここにデプロイ先フォルダのID> -r build
credential.json
が置かれている場所を --config
で指定する必要があります。--config
の値はデフォルトでは $HOME/.gdrive
になっています。ここでは、credential.json
がカレントディレクトリに置いてある想定で、 $(pwd)
としています。
後述しますが、
--service-account
オプションは2018/05/14現在の最新版v2.1.0にはまだ入っていません。最新のソースコードをコンパイルしてインストールしないと使えませんので、ご注意ください。
CircleCIの設定ファイル
上記を踏まえて、CircleCIの設定ファイル .circleci/config.yml
を書いてみます。
キャッシングなどを省いて処理の要点だけを書くと、以下のような内容になります。(書式の詳細については 公式リファレンス をご参照ください)
version: 2
jobs:
# markdown-pdfを使ってPDFを生成するジョブ
build:
docker:
- image: circleci/node
working_directory: ~/wd
steps:
# 日本語のフォントがないと、PDF生成時に日本語部分がレンダリングされない
- run: sudo apt-get update && sudo apt-get install fonts-ipaexfont -y
- checkout
- run: npm i
- run: npm run build
# ビルドの成果物(PDFが入っているディレクトリ)をキャッシュしてデプロイジョブに渡す
- save_cache:
key: build-{{ .Revision }}
paths:
- ~/wd/build
# gdriveを使ってPDF(が入っているディレクトリ)をデプロイするジョブ
deploy:
docker:
# gdriveをソースからコンパイルするのでgolang環境が必要
- image: circleci/golang
working_directory: ~/wd
steps:
# gdriveをインストール
- run: go get github.com/prasmussen/gdrive
# 成果物をリストア
- restore_cache:
keys:
- build-{{ .Revision }}
- deploy:
command: |
# 環境変数から認証情報を取得してJSONファイルに出力
echo $GOOGLE_SERVICE_ACCOUNT_CREDENTIAL > credential.json
# 成果物のディレクトリ名を日時でリネーム
dirname=`date +%Y%m%d_%H%M%S` && mv build $dirname
# 成果物のディレクトリを丸ごとデプロイ
gdrive --config $(pwd) --service-account credential.json upload -p <ここにデプロイ先フォルダのID> -r $dirname
workflows:
version: 2
build_and_deploy:
jobs:
- build
- deploy:
requires:
- build
build
ジョブでPDFを生成して、deploy
ジョブでGoogleドライブにデプロイしています。
日本語フォントが何も入っていない環境だとPDFを生成するときに日本語部分がレンダリングされないので、build
ジョブのはじめで fonts-ipaexfont
をインストールしています。インストールするフォントは何でもOKです。
deploy
ジョブのほうでは、CircleCIのコンテナにサービスアカウントの認証ファイルを設置するために、事前準備で登録しておいた環境変数の中身をJSONファイルに書き出しています。また、build
というディレクトリ名のままだと分かりにくいので、日時の名前にリネームしてからデプロイするようにしています。
gdriveの最新バージョンがリリースされた暁には
なお、gdriveをソースからコンパイルしてインストールしていますが、これはgdriveの --service-account
機能が まだバイナリとしてリリースされておらず、最新のソースを自分でコンパイルしないと使えない が故の措置です。(README からダウンロードできるv2.1.0には、この機能は入っていません)
v2.2.0(多分)がリリースされた暁には、インストールはバイナリをダウンロードしてくるだけでよくなるため、golang環境も不要になり、以下のようにジョブを1つにまとめることができるようになります。
version: 2
jobs:
build:
docker:
- image: circleci/node
steps:
- run: sudo apt-get update && sudo apt-get install fonts-ipaexfont -y
- checkout
# gdriveのバイナリをダウンロードして、チェックサムを確認して、実行パーミッションをつける
- run: |
wget "<ここにgdrive-linux-x64のダウンロードURL>" -O gdrive
[ `sha1sum gdrive | awk '{print $1}'` = '<ここにgdrive-linux-x64のshasum>' ]
chmod +x gdrive
- run: npm i
- run: npm run build
- deploy:
command: |
echo $GOOGLE_SERVICE_ACCOUNT_CREDENTIAL > credential.json
dirname=`date +%Y%m%d_%H%M%S` && mv build $dirname
./gdrive --config `pwd` --service-account credential.json upload -p <ここにデプロイ先フォルダのID> -r $dirname
実装例
以下のGitHubリポジトリに実装例を上げてみたので、参考にしてみてください。
https://github.com/ttskch/markdown-pdf-googledrive-ci-sample
実際に動かすと、以下のように日時のフォルダ配下に成果物がデプロイされます。
おわりに
簡単なことのようで意外とつまずきポイントが多かったので自分のためのメモも兼ねてまとめてみました。
どこかの誰かのお役に立てば幸いです。