CircleCI 2.0でhugoのブログ生成を自動化する
このブログは hugo で生成している。生成過程を自動化したくて、CircleCIへ任せることにしようと思ったところ、そういえばCircleCI 2.0をまだ触っていないことに気付いたので、2.0で自動化した。
設定の書き方
1.0におけるcircle.yml
のように、設定ファイルを書いてそれに基づいた処理が行われるという点は変わらないものの、設定の書き方はガラッと変わって後方互換性は一切なくなっていた。
一応マイグレーションガイドがあるので、circle.yml
からステップ踏んで移行できるようにはなってる。
実行タスク
1.0ではCircleCIがリポジトリの言語から実行タスクを自動判定していたので、設定の書き方は基本的に「デフォルトの実行内容と異なることをやりたければ override
する」という形だった。2.0ではデフォルトタスクがなくなり、すべて自前で書く形になった。
正直、デフォルトのタスクをそのまま使うことはほとんどなかったので、すべて自前で書ける方が何も考えずに済んで楽になった。
ジョブとワークフローという概念
タスクは1つの環境上で一気通貫に実行される形ではなくなり、実行したい内容を Job
としてステップで分けて定義する形になった。 Job
ごとに環境も分離されていて、それぞれDocker imageを定義して起動する。各言語で必要なimageは CircleCIが用意している が、それ以外のimageでももちろんよい。
Job
をどの順番で実行するかは Workflow
として定義する。テストのジョブが成功した場合のみデプロイのジョブを実行するなど、 Job
間の依存関係を定義することもできる。
キャッシュの使い所
Job
ごとにDockerコンテナが起動する都合上、コンテナ間で同じファイルを共有したい場合や、実行の度に同じファイルを使うようなときにはキャッシュを利用する。前者としては、 git clone
したソースコードをどの Job
でも使いまわすようなとき、後者としては、依存するライブラリのダウンロードなどが考えられる。
キャッシュはコンテナ内のどのディレクトリを、何という名前でキャッシュするか、という形で定義する。すでに同名のキャッシュが存在する場合は、それを上書きすることはないので、このあたりが設計上肝になる。
キャッシュ名には 変数 (Template) が使えて、この使い方で「いつキャッシュするか」をコントロールできる。{{ checksum }}
を使うと特定ファイルのチェックサムがキャッシュ名に入るので、Gemfileなどを指定すれば、これに変更があったときだけキャッシュを上書き=ライブラリの再ダウンロードが促せる。 {{ epoch }}
を使えば実行時刻に応じたキャッシュ名となり、またキャッシュリストア時は最新の epoch
が入ったキャッシュが選ばれるので、毎回ダウンロードし直すことになるソースコードのキャッシュに使える。
実装
実装を以下に置く。hugoなのでいわゆるソフトウェアのテストは回しておらず、 textlint で文章校正だけ行い、OKであれば build と deploy が走るようになっている。
textlintは当初全記事にかける形にしていたが、今までの記事ほとんどでNGが出てしまったので、「ブランチ名と一致するファイル名のmarkdown」にだけ実行する形にした。それでもデフォルトで使っていると結構厳しく感じるので、設定は改めたい。。
1version: 2
2
3jobs:
4 checkout_code:
5 docker:
6 - image: circleci/golang:1.8
7 working_directory: ~/hugo
8 steps:
9 - checkout
10 - save_cache:
11 key: hugo-cache-{{ epoch }}
12 paths:
13 - ~/hugo
14
15 textlint:
16 docker:
17 - image: circleci/node:9.2.0
18 working_directory: ~/hugo/.circleci
19 steps:
20 - restore_cache:
21 keys:
22 - hugo-cache
23 - hugo-nodemodules-{{ checksum "package.json" }}
24 - run:
25 command: |
26 npm install
27 npm run textlint "../content/blog/${CIRCLE_BRANCH}.md"
28 - save_cache:
29 key: hugo-nodemodules-{{ checksum "package.json" }}
30 paths:
31 - ~/hugo/.circleci/node_modules
32
33 build:
34 docker:
35 - image: circleci/golang:1.8
36 working_directory: ~/hugo
37 steps:
38 - restore_cache:
39 key: hugo-cache
40 - run:
41 command: |
42 git submodule sync
43 git submodule update --init
44 go get github.com/gohugoio/hugo
45 git clone https://github.com/chroju/chroju.github.io public
46 rm -rf public/*
47 sudo cp /usr/share/zoneinfo/Japan /etc/localtime
48 hugo
49 - save_cache:
50 key: hugo-cache-public-{{ epoch }}
51 paths:
52 - ~/hugo/public
53
54 deploy:
55 machine:
56 enabled: true
57 working_directory: ~/hugo/public
58 steps:
59 - restore_cache:
60 key: hugo-cache-public
61 - run:
62 command: |
63 git config --global user.name chroju
64 git config --global user.email chor.chroju@gmail.com
65 git add --all
66 git commit -m "${CIRCLE_BRANCH} (Circle CI)"
67 git push git@github.com:chroju/chroju.github.io
68
69workflows:
70 version: 2
71 build_and_deploy:
72 jobs:
73 - checkout_code
74 - textlint:
75 filters:
76 branches:
77 ignore: master
78 requires:
79 - checkout_code
80 - build:
81 requires:
82 - checkout_code
83 - deploy:
84 filters:
85 branches:
86 only: master
87 requires:
88 - textlint
89 - build
hugo theme の変更
余談にはなるけど、今回のCircleCI実装に合わせて、 hugo のテーマもcocoaというものに変更した。
nishanths/cocoa-hugo-theme: Configurable, responsive blogging theme for Hugo
hugo のテーマ変更は初めてなのだけど、configの書き方がテーマによって少し違いがあり、そのまま移植という形にはできなかったのでちょっと時間がかかった。