下町柚子黄昏記 by @yuzutas0

したまち発・ゆずたそ作・試行錯誤の瓦礫の記録

技術同人誌のアジャイル執筆を支えるCI・CD整備

技術同人誌 Advent Calendar 2019の12日目の記事です。

この記事のゴール

本稿ではTechBooster/ReVIEW-Templateリポジトリをベースに

  1. 著者はマークダウンで原稿を書く。
  2. GitHubのプルリクで差分をチェックする。
  3. マージしたら自動でPDF生成→Slack配信。

上記を実現するための取り組み(突貫工事)をご紹介します。

この記事の対象読者

技術同人誌の快適な執筆環境を整備しようとしている方。

自己紹介

販売数1,000部を超えた技術同人誌『個人開発がやりたくなる本』の発起人・編集代表です。 詳しくは以下の記事・スライドを参照ください。

yuzutas0.hatenablog.com

既存のツール

TechBooster/ReVIEW-Templateという有名なGitHubリポジトリがあります。 Re:VIEWという書籍執筆支援システムを手軽に利用するためのサンプルです。 私自身もこのリポジトリをフォークして使いました。

解きたい課題

Re:VIEW独自のファイル形式 .re と記法ではなく、マークダウンで書きたいと考えました。 著者は.mdファイルの編集だけを意識すればOK。 これが理想です。 Re:VIEWの恩恵は受けたいのですが、.reファイルを人手で管理したくないのです。

また、原稿をアップデートしたら、最新版PDFをSlackに自動送信したいと考えました。 最新版の原稿を読んで、気になったところを書き直す。 この繰り返しで書籍(プロダクト)を磨き込む。 いわば「アジャイル執筆」を実現したいのです。

ソリューション①

まずはローカル環境でmarkdown.re ファイルに変換します。 私が突貫で書きました。

./Gemfile ファイルに以下を追記します。

# Custom
#gem 'md2review'

ビルド処理を ./build.sh ファイルに書きます。

sed -e "s/#gem 'md2review'/gem 'md2review'/" Gemfile > tmp && mv tmp Gemfile
bundle

for file in `find ./articles/ -name "*.md" -type f`; do
  ./bundle_bin/md2review $file > ${file%.*}.re
done

sed -e "s/gem 'md2review'/#gem 'md2review'/" Gemfile > tmp && mv tmp Gemfile
bundle

docker run -t --rm -v $(pwd):/book vvakame/review /bin/bash -ci "cd /book && ./setup.sh && npm run pdf"

for file in `find ./articles/ -name "*.re" -type f`; do
  rm $file
done

変換ライブラリ md2review を利用しています。

  1. article ディレクトリ以下にある .md ファイルを探す。
  2. それぞれの .md ファイルに変換コマンドを実行して .re ファイルを生成する。
  3. リポジトリnpmコマンドを実行して .re ファイルからPDFを生成する。
  4. .re ファイルを削除する。

最終的には原稿( .md ファイル)と成果物(PDFファイル)だけが手元に残ります。

ソリューション②

CircleCIでPDF変換とSlack配信を自動化します。 上のコードをベースにして@toiroakrが突貫で書いてくれました。

./.circleci/config.yml ファイルに以下を書きます。

version: 2.1

executors:
  default:
    working_directory: /book
    docker:
      - image: vvakame/review
      - image: circleci/ruby:2.6.3

jobs:
  build:
    executor:
      name: default
    steps:
      - checkout
      - run: git submodule init && git submodule update
      - restore_cache:
          keys:
            - npm-cache-{{ checksum "package-lock.json" }}
      - run: gem install bundler:2.0.2
      - run: bundle install
      - run: npm install --no-save
      - save_cache:
          key: npm-cache-{{ checksum "package-lock.json" }}
          paths:
            - ./node_modules
      - run: |
          for file in `find ./articles/ -name "*.md" -type f`; do
            md2review $file > ${file%.*}.re
          done
      - run: npm run pdf
      - run: $(npm bin)/slaup -f IndieCoderJP.pdf -k pdf -m "PDFが更新されました" ./articles/IndieCoderJP.pdf
      - store_artifacts:
          path: ./articles/IndieCoderJP.pdf
          destination: generated PDF data

workflows:
  version: 2
  build_and_test:
    jobs:
      - build:
          filters:
            branches:
              only:
                - master

Dockerコマンドの内容+マークダウンからの変換処理を反映しています。

なお、Slackに slaup で配信するため、CircleCIの環境変数SLAUP_CHANNELSSLAUP_SLACK_TOKEN を設定します。

得られた体験

マークダウンの原稿を更新して、プルリクをマージすると、

f:id:yuzutas0:20191212235037p:plain

CircleCIでビルド&配信が行われて

f:id:yuzutas0:20191212235055p:plain

Slackに最新版の原稿が届くようになりました!

f:id:yuzutas0:20191212235111p:plain

書籍というプロダクトを開発するにあたって、改善サイクルを高速で回せるようになったわけです! やった〜〜〜!!🎉🎉🎉

終わりに

ご質問等があれば、お気軽に@yuzutas0@toiroakrにお問い合わせください! 皆様も素敵な執筆ライフを楽しんでくださいね!

技術同人誌を書こう! アウトプットのススメ (技術の泉シリーズ(NextPublishing))

技術同人誌を書こう! アウトプットのススメ (技術の泉シリーズ(NextPublishing))

  • 作者:
  • 出版社/メーカー: インプレスR&D
  • 発売日: 2018/04/13
  • メディア: オンデマンド (ペーパーバック)