README に、リポジトリにおいているコードを埋め込みたい時があります。 そんな時に便利なのが、embedme です。
今回は、GitHub Actions を使って README にリポジトリのコードを埋め込むことをしたので紹介します。
tl;dr;
- GitHub Actions で embedme を実行して、README.md にリポジトリのコードを埋め込み自動化ができる
- リポジトリと README.md で同じコードを示す時の二重管理が解消するのでうれしい
- 軽量シンプルなので、pull_request、push、workflow_dispatch など任意のトリガーで組めて便利
embedme の基本的な利用例
例として、README.md に src/example.ts
の中身を埋め込むことを考えてみましょう。
まずはembedme をインストールします。
npm install -g embedme
README.md に次のようにコードブロックと言語を示しておいてリポジトリのファイルパスを示します。
TIPS: OS問わずファイルパスは
/
区切りがいいです。
あとは、インストールした embedme をREADME.md に実行します。
embedme README.md
これでexample.ts のファイルがコードブロックに差し込まれます。便利。
行指定も直感的にできます。
// src/embedme.lib.ts#L44-L82
embedme のいいところ
個人的に気に入ってるところは3つあります。
埋め込むときに使ったコメントがコードブロックに残る
埋め込み後もコメントが残ることで、埋め込むソースコードを更新してembedmeを実行すると埋め込みが更新されるので、勝手にメンテが維持します。 どことリンクしていたかも一目瞭然で、README.md を見る人が探すこともできるので好きです。
実行が軽い
インストールも実行も早いのはいいこととです。
npm install -g embedme
で入るので、GitHub Actions などの CI との相性もいいです。
実行も即座に終了するのでカジュアルに走らせられる安心感があります。
実行履歴
README.md の何行目のコードブロックを実行した、実行できなかったを理由を添えて表示してくれます。 例えばファイルパスが見つからず埋め込みができなかったら次のように教えてくれます。
README.md#L381-L383 Found filename .github\workflows\concurrency_control_cancel_in_progress.yaml in comment in first line, but file does not exist at /home/runner/work/githubactions-lab/githubactions-lab/.github\workflows\concurrency_control_cancel_in_progress.yaml!
十分です。
embedme で困るであろうこと
コードブロックのコメント
コードブロック内のコメントを検知するので、埋め込む前提になってないのにコメントを適当にいれたコードブロックを作ると警告は出ます。 ファイルパスが示されていないければ問題ないですが注意です。
言語ごとのコメントが違う
言語ごとに対応しているので当然ですが注意しましょう。
yaml や bash なら #
でコメント認識ですし、js や ts なら //
でコメント認識です。
GitHub Actions で自動化する
embedme は GitHub Actions としては公開されていないので適当に組みます。 今回は、GitHub Actions をいろいろ試しているリポジトリで組んだ例を示します。
大量に yaml を埋め込んでいるので本当に助かっています。
GitHub Actions workflow を用意する
普段は pull_request で実行して、変更があれば PR にコミットを積むようにします。 必要に応じて workflow_dispatch で手動で更新もできるようにします。
PRで リポジトリを checkout するときは、Merge コミットではなく PR のコミットを checkout します。 refを指定せず checkout すると、後段で git push したときにマージコミットが PR に入ってしまいます。
- if: ${{ github.event_name == 'pull_request' }} uses: actions/checkout@v3 with: ref: ${{ github.event.pull_request.head.sha }} # checkout PR HEAD commit instead of merge commit
19-22行目で embedded を実行します。
- name: Embedding Code into README run: | npm install -g embedme embedme README.md
あとは変更があれば git push します。
- name: git diff id: diff run: | git add -N . git diff --name-only --exit-code continue-on-error: true - if: steps.diff.outcome == 'failure' name: git-commit run: | git config user.name github-actions[bot] git config user.email 41898282+github-actions[bot]@users.noreply.github.com git add . git commit -m "[auto commit] Embed code" - if: steps.diff.outcome == 'failure' name: Push changes uses: ad-m/github-push-action@master with: github_token: ${{ secrets.GITHUB_TOKEN }} branch: ${{ github.head_ref }}
push で実行してもいいですが、私のリポジトリではREADMEの目次作成 (toc) を push でやっているので pull_request にしています。 コード生成は重なると直列実行 と checkout 時の ref 伝搬を気にしないといけないので注意です。
まとめ
embedme 便利です。 あんまり README にリポジトリのコードを埋め込むのを考えてこなかったのですが、いざやってみると便利でいろいろ使えそうです。(実際コピペではることありますし)
補足情報として、類似したものに tokusumi/markdown-embed-codeがありますが、これはそもそも実行できなかったのと docker のpullが走って重すぎるので好みじゃなかったです。