はじめに
設計とコードの整合性についての話は昔からよくある議題ですよね。
実装コードは直したけど文書の修正を忘れていて、気付けばコードと異なる仕様が文書に残ってしまったことは一度や二度では無いでしょう。
Go言語にはとても親切な Go Doc が提供されており、Go言語に関わったことがあれば https://pkg.go.dev でサードパーティ製のドキュメントを目にしたことがあるはずです。
しかし、プライベートなパッケージやhtmlではない方法でGo docと同様の内容が読みたいこともあります。
今回は gomarkdoc を使ってGithub ActionsでコードからMarkdownを生成することで、Githubサイトでプレビューしやすい文書にしてみたいと思います。
Install go 1.21.6 on Ubuntu 20.04
これは導入のためのサンプル手順です。
お手元のGo言語開発環境がある場合は不要です。
$ sudo -i
# curl -LO https://go.dev/dl/go1.21.6.linux-amd64.tar.gz
# tar -C /usr/local -xzf go1.21.6.linux-amd64.tar.gz
# exit
$ mkdir ~/bin
$ ln -s -r /usr/local/go/bin/go ~/bin/go
$ go version
go version go1.21.6 linux/amd64
$ vi ~/.bashrc
# Add go/bin path
if [ -d "$HOME/go/bin" ] ; then
PATH="$HOME/go/bin:$PATH"
fi
$ . ~/.bashrc
Create sample project
適当なプロジェクトをGithubで作成し、ログメッセージを出力して終了するだけのサンプルコードを作成します。
Githubで gomarkdoc-sample
プロジェクトを作って、それを使います。
URLは削除済みのプライベートリポジトリなので一部伏せています。
また、実際に外部から使うわけでは無いのでモジュールパスはダミーです。
$ git clone git@github.com:<your-name>/gomarkdoc-sample.git
$ cd gomarkdoc-sample
$ go mod init example.com/qiita/gomarkdoc-sample
go: creating new go.mod: module example.com/qiita/gomarkdoc-sample
go: to add module requirements and sums:
go mod tidy
$ cat main.go
package main
import (
"fmt"
"log/slog"
)
func SomeInfo(message string) {
slog.Info(fmt.Sprintf("Hello, %s", message))
}
func main() {
SomeInfo("test")
}
$ go run main.go
2024/01/14 11:06:04 INFO Hello, test
gomarkdocによる文書生成
それではgomarkdocをインストールしましょう。
インストール方法は https://github.com/princjef/gomarkdoc に書いてある通りです。
$ go install github.com/princjef/gomarkdoc/cmd/gomarkdoc@latest
$ gomarkdoc --version
v1.1.0
パスが通っていれば動くはずです。
パスが通っていない場合は ~/go/bin/gomarkdoc
でも動きますね。
次に先ほどのサンプルコードを対象にMarkdownを生成します。
$ gomarkdoc --output doc/main.md example.com/qiita/gomarkdoc-sample
$ cat doc/main.md
<!-- Code generated by gomarkdoc. DO NOT EDIT -->
# gomarkdoc\-sample
```go
import "example.com/qiita/gomarkdoc-sample"
```
## Index
- [func SomeInfo\(message string\)](<#SomeInfo>)
<a name="SomeInfo"></a>
## func [SomeInfo](<https://github.com/<your-name>/gomarkdoc-sample/blob/main/main.go#L8>)
```go
func SomeInfo(message string)
```
Generated by [gomarkdoc](<https://github.com/princjef/gomarkdoc>)
今のところ公開している関数が無いので出力はほとんどありません。
このファイルをリポジトリに追加して、Github上で見てみましょう。
Github上での見た目は次の画像のようになります。
見慣れた https://pkg.go.dev と似た感じの出力で、コードへのリンクも機能します。
Github ActionsでMarkdownを生成&比較
Github Actionsでもgomarkdocを使ってMarkdownファイルを生成し、差分が発生するかどうかをチェックするようにしてみましょう。
以下のように .github/workflows/gomarkdoc.yml
を作成して、git pushしてみます。
name: gomarkdoc-sample
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
doc:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v4
with:
go-version: 1.21.6
- name: Ensure doc update
run: |
go install github.com/princjef/gomarkdoc/cmd/gomarkdoc@latest
gomarkdoc --output doc/main.md example.com/qiita/gomarkdoc-sample
git diff --exit-code doc
さて、Github Actionsでの結果は...と言うと、以下のように差分が発生して失敗しました。
コードを変更したのに文書を変更し忘れたことを検出できそうです。
でも、この差分のリンクは文書の更新忘れとは違うもののようです。
gomarkdoc - Additional Options によると、どうやらローカルでMarkdownファイルを生成した時はgitの設定を自動的に読み込んでいたようです。
そこで、以下のように .github/workflows/gomarkdoc.yml
を変更して、再度pushしてみます。
diff --git a/.github/workflows/gomarkdoc.yml b/.github/workflows/gomarkdoc.yml
index a29bd30..30d80d8 100644
--- a/.github/workflows/gomarkdoc.yml
+++ b/.github/workflows/gomarkdoc.yml
@@ -19,6 +19,6 @@ jobs:
- name: Ensure doc update
run: |
go install github.com/princjef/gomarkdoc/cmd/gomarkdoc@latest
- gomarkdoc --output doc/main.md example.com/qiita/gomarkdoc-sample
+ gomarkdoc --repository.url "${{ github.server_url }}/${{ github.repository }}" --repository.default-branch "main" --repository.path "/" --output doc/main.md example.com/qiita/gomarkdoc-sample
git diff --exit-code doc
今度は成功しました。
ローカルで生成したものとGithub Actionsで生成したもので差分が無いので、コードと一緒に文書も正確に更新されていることが分かります。
Markdown生成時のオプションに repository.url
, repository.default-branch
, repository.path
の3点を与えることでローカルgitの内容が不明な場合でも、文書のリンク生成に必要なパラメータを解決できます。
おわり
今回は、gomarkdocを使ってGoコードからGithubの画面でも見やすいMarkdownを作成できることを確認しました。
コードの更新に合わせて文書が更新されるのは、DoxygenやJavaDocなど昔からよく使われる方法だと思います。
今回使用したgomarkdocはGo言語の標準であるGo DocをベースにMarkdownが生成できるので、Go言語開発では比較的気軽に導入できると思います。
GithubでMermaid.jsを表示できるようにもなったので、コードコメントにMermaid.jsを書いてシーケンス図をGithub上で表示できないかと思ったのですが、やはりGo Docがベースと言うこともあり難しいようです。
https://github.com/princjef/gomarkdoc/issues/78 で軽い提案はあったようですが、今のところ動きは無いようです。
開発チームに合わせた適切な文書管理が実現できるように、色々な方法を探りたいものです。それでは。