tech.guitarrapc.cóm

Technical updates

GitHub ActionsでREADMEにリポジトリのコードを埋め込みたい

READMEに、リポジトリにおいているコードを埋め込みたい時があります。 そんな時に便利なのが、embedmeです。

https://github.com/zakhenry/embedme

今回は、GitHub Actionsを使ってREADMEにリポジトリのコードを埋め込むことをしたので紹介します。

概要

  • 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に次のようにコードブロックと言語を示しておいてリポジトリのファイルパスを示します。

https://gist.github.com/guitarrapc/6849719bbeb5b34042349eeef87b9325

TIPS: OS問わずファイルパスは/区切りがいいです。

あとは、インストールしたembedmeをREADME.mdに実行します。

embedme README.md

これでexample.tsのファイルがコードブロックに差し込まれます。便利。

https://gist.github.com/guitarrapc/3e0eda90cf93776aa68c7ede11ca85aa

行指定も直感的にできます。

// 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をいろいろ試しているリポジトリで組んだ例を示します。

https://github.com/guitarrapc/githubactions-lab

大量にyamlを埋め込んでいるので本当に助かっています。

https://github.com/guitarrapc/githubactions-lab での自動埋め込み例

GitHub Actions workflow を用意する

普段はpull_requestで実行して、変更があればPRにコミットを積むようにします。 必要に応じてworkflow_dispatchで手動更新もできるようにします。

https://gist.github.com/guitarrapc/f873228e307a3cda8a2f1ed682ef10e8

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が走って重すぎるので好みじゃなかったです。

https://github.com/tokusumi/markdown-embed-code