actdocsでアクション/Reusable Workflowsのドキュメントを自動生成して、GitHub Actionsライフを快適にする
『actdocs』はアクション/Reusable Workflowsのドキュメントを自動する生成ツールです。GitHub Actionsの開発がちょっとだけ楽になる小粋なツールです。
READMEは大事だよ
GitHub ActionsではアクションやReusable Workflowsという、再利用可能な部品を作る機能が提供されています。GitHub Marketplaceでもたくさんのアクションが公開されています。
ただ自分で実装する場合に、メンドウなのがドキュメントです。たとえば「GitHubの公式ガイドライン」では、READMEについて次のような推奨事項が記載されています。
We recommend creating a README file to help people learn how to use your action. You can include this information in your README.md:
- A detailed description of what the action does
- Required input and output arguments
- Optional input and output arguments
- Secrets the action uses
- Environment variables the action uses
- An example of how to use your action in a workflow
利用者のために概要・入出力パラメータ・コード例をREADMEへ書け、という正論が述べられています。せやな感はありますが、いざ自分でやると正直ツラって気持ちになります。
そこで実装したのが『actdocs』です。actdocsはアクション/Reusable WorkflowsのYAMLファイルをパースし、Descriptionなどをマークダウン形式で書き出します。description
キーさえきちんと書いておけば、いい感じのドキュメントになります。ちなみにGoで実装しました。
サクッと試してみる
前置きはこれぐらいにして早速使ってみましょう。actdocsはDockerイメージ経由での利用が簡単です。次のコマンドを実行すると、アクションのドキュメントを生成します。
docker run --rm -v "$(pwd):/work" -w "/work" \
ghcr.io/tmknom/actdocs generate action.yml
生成されたドキュメントをGitHubで表示すると、次のようになります。これだけっちゃこれだけなんですが、ちゃんと管理されてるっぽい雰囲気が出ますね!
Reusable Workflowsの場合も同様です。actdocsは、アクションとReusable Workflowsを自動識別します。ファイルの指定先だけ変更すれば、まったく同じように使えます。
docker run --rm -v "$(pwd):/work" -w "/work" \
ghcr.io/tmknom/actdocs generate .github/workflows/lint.yml
インストール
前述のとおり、Dockerイメージの利用が楽です。Docker HubとGitHub Packagesに同じイメージが置いてあるので、好きなほうからプルしてください。
-
Docker Hub:
docker pull tmknom/actdocs
-
GitHub Packages:
docker pull ghcr.io/tmknom/actdocs
バイナリファイルがよければ、GitHub Releasesからダウンロードできます。actdocsはパスだけ通せばワンバイナリで動きます。
使い方
actdocsの使い方は大きく2つです。
- ドキュメントを生成して標準出力
- ドキュメントを生成してREADME.mdなどのファイルへ挿入
それではもう少し具体的に見ていきます。
ドキュメントの標準出力
たとえば次のようなアクションが、action.yml
に実装されているとします。
name: Create PR
description: |
Create a pull request for changes to your repository.
Create PR action is designed to be used in conjunction with other steps that change files.
This action will run following steps:
1. Add file contents to the index with `git add`
2. Record changes to the repository with `git commit`
3. Update remote refs along with associated objects with `git push`
4. Create a pull request on GitHub
inputs:
paths:
required: true
description: "File paths for the git add"
branch:
required: true
description: "The branch that contains commits for your pull request"
base-branch:
default: "main"
required: false
description: "The branch into which you want your code merged"
commit-message:
required: true
description: "Message for the git commit"
title:
default: "Generated by create-pr-action"
required: false
description: "Title for the pull request"
body:
default: "Please merge me"
required: false
description: "Body for the pull request"
outputs:
sha:
value: ${{ steps.push.outputs.sha }}
description: "The full SHA-1 object name for the revision"
runs:
using: composite
steps:
- run: echo "Create PR"
shell: bash
このファイルに対し、actdocsのgenerate
コマンドを実行してみましょう。
docker run --rm -v "$(pwd):/work" -w "/work" \
ghcr.io/tmknom/actdocs generate action.yml
すると次のようなマークダウン形式のドキュメントが標準出力されます。
## Description
Create a pull request for changes to your repository.
Create PR action is designed to be used in conjunction with other steps that change files.
This action will run following steps:
1. Add file contents to the index with `git add`
2. Record changes to the repository with `git commit`
3. Update remote refs along with associated objects with `git push`
4. Create a pull request on GitHub
## Inputs
| Name | Description | Default | Required |
| :--- | :---------- | :------ | :------: |
| branch | The branch that contains commits for your pull request | n/a | yes |
| commit-message | Message for the git commit | n/a | yes |
| paths | File paths for the git add | n/a | yes |
| base-branch | The branch into which you want your code merged | `main` | no |
| body | Body for the pull request | `Please merge me` | no |
| title | Title for the pull request | `Generated by create-pr-action` | no |
## Outputs
| Name | Description |
| :--- | :---------- |
| sha | The full SHA-1 object name for the revision |
YAMLファイルの内容を素直にマークダウン化しただけですが、GitHubではだいぶ見やすくなります。InputsのDefault
やRequired
が一覧で確認できるのも、地味にうれしいポイントです。
ドキュメントのファイルへの挿入
actdocsは任意のファイルへドキュメントを挿入できます。まずは挿入対象のファイルへ、目印となるコメントを事前に書いておきます。ここではREADME.mdへ書いたとしましょう。
<!-- actdocs start -->
<!-- actdocs end -->
次にinject
コマンドを実行します。--file
フラグには挿入対象のファイルを指定します。
docker run --rm -v "$(pwd):/work" -w "/work" \
ghcr.io/tmknom/actdocs inject --file README.md action.yml
これで<!-- actdocs start -->
と<!-- actdocs end -->
の間に、generate
コマンドと同様のドキュメントが挿入されます。おそらくメインのユースケースはこちらでしょう。
次のリポジトリはactdocsによるドキュメント自動生成の活用例です。
出力のカスタマイズ
actdocsは少しだけ出力をカスタマイズできます。
項目のソート
--sort
フラグを使うと、InputsやOutputsの各項目をソートできます。generate
/inject
コマンドのどちらにも対応しています。
docker run --rm -v "$(pwd):/work" -w "/work" \
ghcr.io/tmknom/actdocs inject --sort --file README.md action.yml
項目が空の場合に省略
InputsやOutputsに項目がない場合、デフォルトでは次のような出力になります。
## Inputs
N/A
## Outputs
N/A
しかし--omit
フラグを使うと、項目が空の場合に出力自体を抑制できます。もちろん項目が存在する場合は、普通に出力されます。
docker run --rm -v "$(pwd):/work" -w "/work" \
ghcr.io/tmknom/actdocs inject --omit --file README.md action.yml
JSON形式
actdocsは基本的にマークダウン形式で扱うツールです。ただ、他のフォーマットで扱いたいケースもあるでしょう。そこで加工しやすいように、JSON形式の出力にも対応しています。
docker run --rm -v "$(pwd):/work" -w "/work" \
ghcr.io/tmknom/actdocs generate --format json action.yml
あとはjqコマンドで頑張るなり、自作ツールでJSONを操作するなり好きに使ってください。自力で元のYAMLファイルをパースするよりは、扱いやすい構造になっています。
出力項目の違い
アクションとReusable Workflowsでは微妙にシンタックスが異なります。
そのためactdocsでは、アクションとReusable Workflowsで出力項目を変えています。出力される項目は次のとおりです。
- アクションの出力項目
- Description
- Inputs
- Outputs
- Reusable Workflowsの出力項目
- Inputs
- Secrets
- Outputs
- Permissions
こうやって並べてみると、結構違います。これはactdocsの制約ではなく、GitHub Actionsのシンタックスの制約です。たとえばアクションではPermissionsの定義ができません。そのため不足している項目は、引き続き手作業で書く必要があります。
実運用への組み込み
実運用へ組み込む際のヒントを3つ紹介します。
タスクランナー
お気づきでしょうが、Docker経由で使うとコマンドが長いです。そこでオススメなのは、タスクランナーに組み込んでしまうことです。タスクランナーは好みもあるでしょうから、好きなものを使ってください。個人的にはMakefile[1]へ次のようなスクリプトを書いています。
.PHONY: docs
docs: ## generate docs
docker run --rm -v "$(pwd):/work" -w "/work" \
ghcr.io/tmknom/actdocs inject --sort --file=README.md action.yml
このように書いておけば、次のコマンドを実行するだけで済みます。
make docs
継続的ドキュメンテーション
チームで開発しているなら、GitHub Actionsへ組み込んでしまうのもよいでしょう。たとえば次のコードは、アクションのREADMEを自動更新するワークフローです。action.yml
ファイルを変更するプルリクエストを出すと、自動的にREADMEを最新化してプッシュしてくれます。
name: Docs
on:
pull_request:
paths: ["action.yml"]
permissions:
contents: write
jobs:
generate:
runs-on: ubuntu-latest
timeout-minutes: 5
env:
YAML_FILE: action.yml
MD_FILE: README.md
steps:
- name: Checkout
uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.ref }}
- name: Inject document
run: |
docker run --rm -v "$(pwd):/work" -w "/work" \
ghcr.io/tmknom/actdocs inject --sort \
--file "${MD_FILE}" "${YAML_FILE}"
- name: Push
run: |
if [[ "$(git status -s)" == "" ]]; then
echo 'skipped'
exit 0
fi
git config --global user.name "github-actions[bot]"
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add "${MD_FILE}"
git commit -m "Update ${MD_FILE}"
git push
READMEへ<!-- actdocs start -->
と<!-- actdocs end -->
を追加しておけば、actdocsのローカルへのインストールは不要です。READMEの修正漏れの指摘も、いちいちせずに済みます。
ドキュメント生成のCIへの組み込みは、会社組織では特に威力を発揮します。次のような先駆者の記事なども参考にしながら、ワークフローを組み立ててみるのも一興です。
DescriptionにはUsageも書こう
アクションでのみ使える小技ですが、description
キーへUsageも書くと結構体験がよいです。
name: Create PR
description: |
Create a pull request for changes to your repository.
Create PR action is designed to be used in conjunction with other steps that change files.
This action will run following steps:
1. Add file contents to the index with `git add`
2. Record changes to the repository with `git commit`
3. Update remote refs along with associated objects with `git push`
4. Create a pull request on GitHub
## Usage
```yaml
steps:
- name: Create PR
uses: tmknom/create-pr-action@v0
with:
paths: "*.md **/*.md"
branch: example-pr
commit-message: Committed by create-pr-action
title: Generated by create-pr-action
body: Please merge me
```
このように書いておくと、次のようなドキュメントを生成できます。
コピーアンドペーストできるUsageは、利用者からすると地味に便利です。またDescriptionを定義するYAMLファイルでは、Usageがファーストビューに入ってきます。すると久しぶりのコード変更でもスッと思い出せます。ちょっとしたことですが、UXとDXが両方向上してオススメです。
なぜ「actdocs」を作ったのか
アクションやReusable Workflowsの数が増えてくると、ドキュメントの維持がメンドクサすぎるためです。軽く検索してみましたが、探した当時は発見できませんでした[2]。というわけで自作に至りました。YAMLを少しパースすればすぐ作れそうに見えたのも、自作を後押しています。
設計の参考にしたのはterraform-docsです。よく仕事でTerraformモジュールを実装しているのですが、ドキュメント生成はこのツールでいつも自動化しています[3]。そこでGitHub Actionsでも同じような開発体験を実現しよう、というコンセプトで実装しました。入出力パラメータが表形式なのは、terraform-docsの影響です。
不思議なものでコードの近くにドキュメントがあると、「ちゃんと書こうかな」という気になります。おそらくコード修正時に視界へ入りやすく、ついでに直すモチベーションが湧きやすいのでしょう。実際actdocsを作ってから、以前よりDescriptionをちゃんと書くようになりました。
まとめ
本記事ではドキュメント生成ツール『actdocs』を紹介しました。もしアクションやReusable Workflowsのドキュメント維持に課題を感じているなら、一度お試しください。
ちなみにREADMEは一応英語で書いてありますが、筆者の英語力はゼロです。完全にDeepL頼みです。そのためもしご意見あれば、日本語でいただけるとありがたいです。
完全に余談ですが、ドッグフーディングできるのは楽しいですね。仕事ではコードを書く以外の活動も多いため、こういうちょっとしたツールの実装は癒やされます。
-
MakefileというかMakeはビルドツールだろというツッコミを受けそうですが、筆者自身は完全にタスクランナーとして使っています。macOSやLinuxであれば環境構築がいらなくて便利です。 ↩︎
-
探したのは半年以上前の話です。actdocs自体は結構前にできてたんですが、自分の課題が解決して満足してしまったので、これまで告知なども行っていませんでした。ちなみに今回この記事を書いたのは、チームへ説明するためという理由もあります。 ↩︎
-
terraform-docsはTerraform界隈では有名なドキュメント生成ツールです。多くのTerraformモジュールで利用されています。どのTerraformモジュールのREADMEでも同じように書かれているため、読み手の認知負荷低減にかなり寄与している印象があります。 ↩︎
Discussion