Taskfileを使用して記事管理を自動化した話
こちらの記事で自作のnote-cli
というnoteや個人ブログの記事を管理するためのCLIツールを作成した話を紹介させていただきました。
個人的に使いやすいようにちょこちょこいじっていて個人ブログの記事管理にも対応させたのとコマンド実行時に複数のフラグを指定する感じになってしまったのでタスクランナーとしてTaskfileを導入したのでその備忘録です。
Taskfileについて
Makefileを覚えてから何かとMakefileでやろうとするくらいMakefileが気に入っていたのですが上記記事でMakefile警察の存在を知ったので次Makefile使いたくなったらTaskfileを使用しようと思っていたため採用してみました。
詳しくは上記記事や公式のドキュメントを参照していただければと思いますがざっくり言うとTaskfile.yml
というようなyamlファイルでタスクを管理します。以下は公式ドキュメント記載の例です。
version: '3'
tasks:
hello:
cmds:
- echo 'Hello World from Task!'
silent: true
% task hello
> Hello World from Task!
Taskfileのインストール方法はいろいろ用意されていますが今回はHomebrewでインストールしました。
brew install go-task
他の方法はこちらを参照してください。
個人ブログの記事管理に導入してみる
個人ブログをAstroで公開していて記事ファイルはsrc/content/blog
配下にmarkdownファイルを配置して管理していました。
tree ./src/content/blog
./src/content/blog
├── 2023-10-01.md
├── 20230321.md
├── 20230506.md
└── 20230719.md
各記事ファイルには以下のようなメタデータ的なものを記載してます。
---
title: "Workers Tech Talk#1に参加した感想"
tags: ["tech", "ポエム", "Cloudflare"]
date: "2023-07-19"
---
これらの記事ファイルは直接手動で作成していたのを自動化したいと思っていたため、note-cli
の機能を拡張して対応させてみました。
% note-cli create article ./src/content/blog -n article --no-dir -author Junichi.Y
% cat ./src/content/blog/article.md
---
title: ""
tags: []
date: "2023-10-02"
author: "Junichi.Y"
---
このコマンドを毎回実行するのもあれなのでTaskfileを使用してタスク化してみます。
version: '3'
tasks:
new:article:
dir: $HOME/myapp/my-blog/astro-my-blog/src/content/blog
cmds:
- note-cli create article -a Junichi.Y --no-dir -t .
これで以下のコマンドだけで記事ファイルが作成されます。
% task new:article
せっかくTaskfileを導入したので個人ブログでもTaskfileの導入について簡単に記事にしてみました。
noteの記事管理にも導入してみる
noteの記事管理にも同じように導入してみます。作成したTaskfileは以下のような感じです。
version: '3'
tasks:
new:article:
dir: $HOME/note
cmds:
- note-cli create article -a Junichi.Y -t .
個人ブログのときとほとんど一緒です。noteの方は一応記事ファイルのメタデータからアップロード用の画像ファイルを生成できるようにしているのでそれもタスク化してみます。
先にコマンドはこんな感じで画像生成できます。
% note-cli create image ./article/article.md -i ./icon.png --template 1 -o ./article/output.png
-
./article.md
メタデータを読み込むために対象の記事ファイルのパスを指定 -
-i
生成する画像に埋め込むアイコン画像のパスを指定 -
--template
使用する画像テンプレートの番号を指定 -
-o
出力ファイル名
Taskfileに引数を渡す
画像生成の場合、対象の記事ファイルを引数として指定する必要がどうしてもあったためタスクの実行に引数を指定できるようにする必要がありそうでした。いろいろやり方がありそうだったんですがまず以下のようにして引数をそのままTaskfileに渡せます。以下の例はTaskfileの公式ドキュメントに記載の例です。
version: '3'
tasks:
yarn:
cmds:
- yarn {{.CLI_ARGS}}
$ task yarn -- install
--
のあとに指定した引数はTaskfile内で{{.CLI_ARGS}}
で全て渡すことができます。上記タスクの実行するコマンドはyarn install
となります。
この仕組みを使い引数にディレクトリ名を渡しTaskfile内でごにょごにょして必要な変数を用意します。
new:image:
dir: $HOME/note
cmds:
- |
# 変数に引数から渡ってきたディレクトリ名を格納
DIR={{.CLI_ARGS}}
# 一応、末尾のスラッシュあれば除去しておく
[[ $DIR == */ ]] && DIR="${DIR%/}"
# 出力先
OUTPUT=$DIR/output.png
# 対象の記事ファイル
ARTICLE=$DIR/$DIR.md
また、cmds
には上記のようにして複数行のコマンドをスクリプトとして書くこともできます。
(おまけ)乱数を使用してテンプレートをランダムに使用する
本題から逸れますが画像生成に使用するテンプレート画像が番号を指定するだけなので疑似乱数を生成してランダムに選択されるようにしてみました。シェルで乱数生成をしたことがなかったのですが$RANDOM
を使用することで0 〜 32767
の範囲の数値をランダムに生成できるようです。テンプレートは3つしかないので1-3
の範囲で乱数が生成できればいいので問題なさそうです。
new:image:
dir: $HOME/note
cmds:
- |
# 変数に引数から渡ってきたディレクトリ名を格納
DIR={{.CLI_ARGS}}
# 一応、末尾のスラッシュあれば除去しておく
[[ $DIR == */ ]] && DIR="${DIR%/}"
+ # これを追加
+ TEMPLATE_NUM=$((RANDOM % 3 + 1))
# 出力先
OUTPUT=$DIR/output.png
# 対象の記事ファイル
ARTICLE=$DIR/$DIR.md
これで1-3
の範囲の値がランダムに変数に格納されると思ったのですが毎回同じ値が使用されてしまう。。seedが毎回同じ値使われてるのかな?
ちょっと原因がわからなそうだったのでrubyのrand関数を使用するように変更しました。こういう時、スクリプト言語便利!!
new:image:
dir: $HOME/note
cmds:
- |
# 変数に引数から渡ってきたディレクトリ名を格納
DIR={{.CLI_ARGS}}
# 一応、末尾のスラッシュあれば除去しておく
[[ $DIR == */ ]] && DIR="${DIR%/}"
# これを追加
- TEMPLATE_NUM=$((RANDOM % 3 + 1))
+ TEMPLATE_NUM=$(ruby -e 'puts rand(1..3)')
# 出力先
OUTPUT=$DIR/output.png
# 対象の記事ファイル
ARTICLE=$DIR/$DIR.md
最終的なTaskfileは以下のようになりました。
version: '3'
tasks:
new:article:
desc: create new article. [command] task new:article
dir: $HOME/note
cmds:
- note-cli create article -a Junichi.Y -t .
silent: true
new:image:
desc: create new article image. [command] task new:image -- [directory name]
dir: $HOME/note
preconditions:
- sh: command -v ruby
msg: This command requires ruby.Please install ruby.
cmds:
- |
DIR={{.CLI_ARGS}}
[[ $DIR == */ ]] && DIR="${DIR%/}"
# TEMPLATE_NUM=$((RANDOM % 3 + 1))
TEMPLATE_NUM=$(ruby -e 'puts rand(1..3)')
OUTPUT=$DIR/output.png
ARTICLE=$DIR/$DIR.md
note-cli create image -i ./icon.png --template $TEMPLATE_NUM -o $OUTPUT $ARTICLE
silent: true
タスクの実行
% task new:image -- 2023-10-01
Complete generate OGP image
% tree 2023-10-01
2023-10-01
├── 2023-10-01.md
└── output.png
まとめ
今回は以下のことについて紹介しました。
- note-cliの個人ブログへの導入方法について
- タスクランナーであるTaskfileの導入方法について
- Taskfileに引数を渡してスクリプトを実行する方法について
個人的にはこれでzenn, qiita, note, 個人ブログが同じような感覚で手元で執筆できるようになったので満足してます。使ってみた感じTaskfileは直感的にわかりやすくタスクが定義できるのでめちゃくちゃ良かったです。今後も個人的なものはMakefileではなくTaskfileを使用したいと思います。
今回は以上です🐼
Makefileと比較してみる(おまけ)
最後に作成したTaskfileをMakefileにしたものと比較してみます。
version: '3'
tasks:
new:article:
desc: create new article. [command] task new:article
dir: $HOME/note
cmds:
- note-cli create article -a Junichi.Y -t .
silent: true
new:image:
desc: create new article image. [command] task new:image -- [directory name]
dir: $HOME/note
preconditions:
- sh: command -v ruby
msg: This command requires ruby.Please install ruby.
cmds:
- |
DIR={{.CLI_ARGS}}
[[ $DIR == */ ]] && DIR="${DIR%/}"
# TEMPLATE_NUM=$((RANDOM % 3 + 1))
TEMPLATE_NUM=$(ruby -e 'puts rand(1..3)')
OUTPUT=$DIR/output.png
ARTICLE=$DIR/$DIR.md
note-cli create image -i ./icon.png --template $TEMPLATE_NUM -o $OUTPUT $ARTICLE
silent: true
.PHONY: new-article new-image
new-article:
@cd $(HOME)/note && \
note-cli create article -a Junichi.Y -t .
new-image:
@if ! command -v ruby > /dev/null; then \
echo "This command requires ruby. Please install ruby."; \
exit 1; \
fi
@cd $(HOME)/note && \
DIR=$(filter-out $@,$(MAKECMDGOALS)); \
[[ $$DIR == */ ]] && DIR="$${DIR%/}"; \
TEMPLATE_NUM=$$(ruby -e 'puts rand(1..3)'); \
OUTPUT=$$DIR/output.png; \
ARTICLE=$$DIR/$$DIR.md; \
note-cli create image -i ./icon.png --template $$TEMPLATE_NUM -o $$OUTPUT $$ARTICLE
どちらのほうがわかりやすいでしょうか??
Discussion