データベースドキュメント生成コマンド tbls 更新情報(Mermaid対応 / schema.json / tbls outの強化)

久しぶりのtblsの新機能紹介エントリです。

ドキュメントのER図出力にMermaidを指定できるようになりました

ER図の出力フォーマットにMermaidを指定できるようになりました。次のように er.format: セクションか --er-format オプションに mermaid を指定することで変更できます。

er:
  format: mermaid

開発裏話

GitHubがMermaid対応したことで「tblsもMermaid対応してほしい」という要望や提案は以前より多く受け取っていました。 しかし、個人的にあまりメリットを見出せずそのままPull Request待ちとなっていたのですが、今回エイッと作ってみました。

Mermaid対応をするにあたって1つとても面倒な仕様がありました。それはMermaidはER図の多重度(カーディナリティ)の指定が必須となっていることでした。

もともとtblsが持つスキーマ情報にはカーディナリティがなかったのと、カーディナリティはスキーマの情報から一意に決まるものではないので、今回のMermaid対応に向けて次の機能を追加しました。

  • リレーション情報をオーバーライドする機能(修正できる機能)
    • 自動判定されたカーディナリティを修正するため
  • スキーマ情報にカーディナリティを新たに新設
    • そもそもカーディナリティの概念がスキーマ情報になかったため
  • カーディナリティの自動判定
    • 現状と同等のステップでER図を生成するため「Mermaidの場合はカーディナリティを手入力」という方向は取れないため

Mermaid対応よりむしろこちらのほうが大変だったのはいうまでもありません。

ドキュメントの出力と同時に schema.json を出力するようになりました

ドキュメントの出力と同時に、スキーマ情報を集約した schema.json を出力するようにしました( tbls out -t json で出力されるものと同等のものです)。出力先はドキュメントの出力ディレクトリになります。

目的としてはスキーマ情報の構造化データの保持です。

tbls doc で出力されるMarkdown形式のドキュメントはあくまでドキュメントで、構造化データとは言いにくいものです。都度データベースに接続してスキーマ情報を解析しなくても良いように一度取得したスキーマ情報を構造化データとして保持するようにしました。

開発裏話

実は、schema.jsonのファイル名を何にするかと、その出力先をどこにするかを本当に悩みました。

Issueでいろいろご意見を下さった皆様、本当にありがとうございました。

tbls out を強化しました

tbls out コマンドを強化しました。

github:// スキームに対応( tbls out だけでなく tbls doc tbls diff でも使用可能)

schema.jsonGitHubリポジトリから直接取得してデータソースとして使用可能です。

出力するテーブルを制御する --include --exclude --table オプションを整理。さらに --label オプションを追加

tbls out で出力するテーブルを制御するオプションを整理しました。またテーブルに付与しているラベルでも出力テーブルをフィルタリングできるようになりました。

開発裏話

tblsは基本データベースドキュメントを生成する tbls doc コマンドがフィーチャーされるので tbls out はあまり目立たないですが、個人的には今回の新機能の目玉はこちらのほうです。

schema.jsonをデフォルト出力にしたことで、将来的にはデータソースドキュメントをtblsで管理しているリポジトリには schema.json もコミットされるようになるはずです。

そうすると次のようなことが簡単にできるようになります。

$ tbls out github://k1LoW/tbls/sample/mysql/schema.json -t mermaid --table users --table posts
erDiagram

"posts" }o--|| "users" : "FOREIGN KEY (user_id) REFERENCES users (id)"

"posts" {
  bigint id PK
  int user_id FK
  varchar_255_ title
  text body
  enum__public___private___draft__ post_type
  datetime created
  datetime updated
}
"users" {
  int id PK
  varchar_50_ username
  varchar_50_ password
  varchar_355_ email
  timestamp created
  timestamp updated
}

tblsで管理されている最新のスキーマ情報をデータベース接続なしにいつでも取得できるようになります。

また、 tbls out コマンドで対応しているフォーマットにはMermaidだけではなくPlantUMLやJSONSVGPNGなどもあります。

私はこれを「"スキーマ情報の取得"から"スキーマ情報の活用"への道が開かられた」と捉えています。

テーブルに付与するラベルを活用することで、ラベルで意味のあるグルーピングされたテーブルのER図だけ出力するということもできます。 ここらへんのグルーピングはndiagでも実装したビューポイントの考え方につながってくると思っています*1


というわけで、

そうです。仕込み、実はまだ続いています。

「runn クックブック」はじめました

昨年からrunnというオペレーション自動化ツールを開発しています。 runnの認知のされ方としては「インテグレーションテスティングツール」とか「シナリオテスティングツール」といったほうがいいかもしれません。

github.com

runnにはさまざまな機能があります。 しかし、その機能全てを作者である私自身が紹介しているかというと全くできていない状況です。Twitterですらつぶやいていない。

READMEもできるだけ書いていますが、十分とは言い難い。

これは良くないと思い、もう少し頑張ることにしました。

今後、しっかりとrunnの機能の紹介をしていこうと思います。

runn クックブック

というわけで「runn クックブック」はじめました。

zenn.dev

せっかくならストックされていく形が良いだろうと思い、Zennの本の形式で書いていくことにしました。 また、「どうせ一気に書ききることは難しいだろう」「本の構成を決めて書くこともできないだろう」と判断していわゆる「クックブック形式」で書くことにします。

この本は、不定期でレシピの追加や編集をする形で運用する予定です。 まだ紹介していない機能やユースケースがあるので、今後もレシピを増やしていこうと思います。

(runnの新機能を「runn クックブック」で紹介するような習慣ができるといいな...)

ちょっと実験

はじめて「本形式」で書くのですが、最初で最後の可能性もあるので「有料」の実験をしようと思っています。 この本は500円の有料本としていますが、無料公開範囲をちょいちょい変更してみようと思っています。 なので、購入する場合は注意してくだい。明日には全てが無料公開範囲になっている可能性もあります(逆もあります)。 ただ、もし、もし購入していただけたら開発や執筆のモチベーションになります。どうぞよろしくお願いします。

2022年の振り返りと2023年の抱負

2022年の振り返り

2022年はそれなりに変化のあった年でした。 仕事もですがプライベートの方面で多くの変化がありました。一番大きいのは引越しです。変化を嫌う私としては当時本当にストレスだったのですが、今、「引っ越していなかったら」と思うとゾッとします。むしろ変化に耐えられた要因の1つが今の家だったと思います*1

2021年に「自分が何が好きなのか」を言語化できて2022年を過ごしてみて、振り返ってみるとやはり「開発者のための開発」が好きなんだと感じました。 ますます「何エンジニア」なのかわからなくなってきているのでその点は悩みです。

2022年の抱負は「挑戦する」でした。 「挑戦したか?」というと疑問が残るところです。

ごく小さな挑戦としては新しい勉強会コミュニティへの参加があります。 1つは開発しているツールが対象とする領域のコミュニティでの発表、もう1つはツールを開発しても良い場への参加をしました。

testautomationresearch.connpass.com

gophersou.connpass.com

どちらもとても楽しかったです。

ソフトウェアテスト自動化カンファレンスでは、カンファレンスを通してテスト自動化の世界の広さだったり普段テストを生業としている方の考えを体験できたのがよかったです。

ごーふぁー荘は、後期TechTouch*2や私が参加させてもらっていた時代のFukuoka.rbを思い出してしまい、とても居心地が良いです。また参加したいです。

あと、大名エンジニアカレッジで講師をさせてもらいました。

daimyo-college.pepabo.com

「人に教える」は本当に難しいと感じた体験でした。

OSS

2022年は2021年と比べて新規は少なかったですが、既存OSSのメンテナンスも多かった気がするのでこんなものかなと思っています。

2022年最も力を入れたOSSは何かと問われたら runn です。「runnの開発のためにOSSを書く」ということも多かったです。

2023年ももう少しrunnに力を入れていきます。「自身のツールを広める」という意味での広報面も強化したい。

発表

お誘いいただいたのを含めて4件。少なかったかなあという印象です。

2023年の抱負

今年は「書く」です。

コードを「書く」もですが、Issueを「書く」、Slack TLに「書く」、文書を「書く」をやっていきたいです。Twitterも書いていく。あと「描く」も再開したい。

リモートワークがメインになっている状況だと「書かない=いない」になります。もっと書いていかないと本当に存在が希薄になっていくなあと感じています。普段出不精なのがインターネット活動にまで影響しはじめていて本当にヤバい。家族にしか存在を認知されなくなってしまう。

「アウトプットをした結果インプットできる」というのは各所で言われていますし私もそう思っています。書くもアウトプット。

「書いていくぞ!」というか「(もう一度)書くのに慣れるぞ!」という気持ちです。

あ、あ、あ、あ、あと分割キーボードを今年こそ!手に入れたい。買うキーボードはもう決めているんです。

今年もよろしくお願いします。

*1:何にゾッとしていたのかについてはここでつらつら書く話でもないので直接会った時にでも聞いてください。主に子育ての話なので特に面白い話でもないです。

*2:会社の名前ではなく、はるか昔に私が運営していた勉強会というかもくもく会です。

octocovのコードメトリクスをMackerelで可視化する

この記事はMackerel Advent Calendar 2022の5日目の記事です。3年ぶりのMackerel Advent Calendarへの参加です。

4日目は id:buty4649 さんで、サーバの温度を監視するmackerel-plugin-thermalを作った - ぶていのログでぶログでした。自宅サーバ、私にはまだ未知の領域です。自宅にサーバがあるということは自宅がDCになるわけで、温度管理も必要ということか...。


octocovとは

github.com

octocovはOSSのコードメトリクス計測ツールです。

コードメトリクス(コードカバレッジやCode To Test Ratio、テスト実行時間など)を計測するだけでなく、取得したメトリクスをPull Requestへのレポートしたり、サポートしている任意のデータストアにメトリクスを送信したりすることができます。

私が所属するGMOペパボではデータストアとしてBigQueryを選択し各リポジトリで計測したコードメトリクスを集約しています。 さらに独自のダッシュボードを作成して、集約したコードメトリクスを可視化できるようにしています。

詳しくは以下のエントリをご覧ください。

tech.pepabo.com

データストアとしてMackerelをサポート

octocovにおけるデータストアとは取得したコードメトリクスを保存したり取得する先を指します。

サポートしているデータストアとしては次のようなものがあります。

そして、今回(コードメトリクスの保存先として)Mackerelにも対応しました。

具体的には次のようにMackerelのサービスメトリクスとして、各リポジトリのコードメトリクスを可視化することができます。

リポジトリのコードメトリクスがMackerelで確認できています。

test-execution-timeのグラフはグラフ定義をsecondsにするとわかりやすいです。

blog.arthur1.dev

設定方法

設定方法は2パターンあります。

今回は例として、 octocov という名前のサービスにコードメトリクスを送信することにします。

1. 各リポジトリから直接Mackerelにメトリクスを送信するパターン

一番単純な方法です。

MackerelのAPIキーは環境変数 MACKEREL_API_KEY もしくは OCTOCOV_MACKEREL_API_KEY で読める必要があります。 事前にリポジトリのSecretsに登録しておきます。

octocov-actionを呼び出す際に環境変数を設定します。

-
    uses: k1LoW/octocov-action@v0
    env:
      MACKEREL_API_KEY: ${{ secrets.MACKEREL_API_KEY }}

今回は octocov というサービスにメトリクスを登録するので、.octocov.yml の設定には report.datastores:mackerel://octocov を追加します。

report:
  datastores:
    - mackerel://octocov

これで終わりです。

2. Central repoで一旦各リポジトリのメトリクスを収集して、まとめてMackerelに送信するパターン

パターン1は、各リポジトリMACKEREL_API_KEY を設置する必要があります。

これを解決するのが、Central repoからまとめてMackerelに送信するパターンです。

Central repo、Central modeについては次のエントリをご覧ください。

k1low.hatenablog.com

Central modeで収集したメトリクスをまとめて別のデータストアに送信する方法として、central.reReport: を使います。

具体的には私のOSSのCentral repoである k1LoW/octocovs に設定があります。

github.com

github.com

定期的に各リポジトリGithub Actions Artifactsに保存されているコードメトリクスレポートをpullして収集した後、各最新のコードメトリクスをまとめてMackerelに送信しています。

これで終わりです。

メトリクス情報の値だけを送信して可視化するのは便利そう

octocovとMackerelを連携させるアイデアは半年以上前からアドベントカレンダーネタとして構想していたのですが、これ、実は便利ですね。

時系列にみるデータはカジュアルにそれの可視化が得意なところに渡してしまうのが便利なのかー。

勉強になりました。


明日6日目は @tomotomobooksさんです

octocovで実現できる3つのレポートコメントの方法

octocovはコードメトリクスを取得してPull Requestにレポートをコメントしたり、設定したデータストアに記録することができます*1

今回はoctocovで実現できる3つのレポートコメントの方法を紹介します。

Pull Requestへのレポートコメント

Pull Requestへレポートをコメントします。複数回レポートされる場合は過去レポートコメントを隠すようにしています。

octocov init で生成される .octocov.yml にも設定されるデフォルトのレポートコメントです。

設定は以下のような感じです。

comment:
  if: is_pull_request
  # hideFooterLink: false # レポートのフッタのリンクを消す
  # deletePrevious: true # 前回のレポートコメントを隠すのではなくて消す

GitHub Actions Job Summariesへのレポート

GitHub ActionsのJob Summariesにレポートを追加します。

github.blog

設定は以下のような感じです。

summary:
  if: true # 毎回Job Summariesにレポートを追加する

Pull Requestのボディへのレポートの差し込み

Pull Requestのコメントではなくボディに差し込む(随時差し込んだ内容を更新する)ようなレポートも可能です。

GtiHubとSlackを連動させているときにPull RequestコメントによるSlack通知がなくなるのがメリットかもしれません。

body:
  if: is_pull_request

以上、ちょっとしたTipsでした。

*1:設定上はデータストアへの記録を report: と表現しますが今回はコードメトリクスのレポートコメントの方を指します

tagprで実現するPull Request上で進めるOSSのリリースマネジメント

私の趣味は少し実用的で小さなOSSを書くことです。

今までも多くの小さなOSSを書いてきました。そして、エコシステム的にリリースすべきものはリリースしてきました。

ここで言うリリースと言うのはバージョンをつけてパッケージとしてPublishすることです。 PHPであればpackagist.orgに、Rubyであればrubygems.orgに、JavaScriptであればnpmjs.comにPublishするまでのことを指します。 Goであれば、バージョンのタグをつけてGitHubリポジトリにプッシュすればリリース完了です。必要であればアセットをGitHubのリリースページにアップロードします。

(自分にとって)適当で心地よいリリースマネジメント

私は基本的にすぐにリリースします。修正1つでもバージョンタグを打ってすぐにリリースすることが多いです。

これはリリースされることで初めて各言語のエコシステムに綺麗にのって利用できるようになるからであり、Pull RequestやIssueで貢献してくれた人(私を含む)にできるだけその結果をフィードバックしたいからです。

なのでバージョンが上がることには何も感じずどんどん上げていきます。

と、ここまで「ぽい」ことを書いてきましたが、なかなか上げないこともあり、それは自分でも言語化できていません。なんでだろう?

ようは適当なんだと思います。

関わる人にとって適当で心地よいリリースマネジメント

では私だけではなく関わる人にとって良いリリースマネジメントというのはどういうものか考えてみました。

  • リリースフローが自動化できていて
  • リリース権限を持っている人がいつでもリリースできるようになっていて
  • 自由にリリースして良いことが明らかになっている

なぜこのようなことを考えたかというと、tagprという便利なツールが現れて、かつ、私が作成したOSSに積極的にコントリビュートしてくれる方が現れたからです。前から考えていたわけではなく「なるほどそういうリリースマネジメントがあるのかも」と思ったのでした。

songmu.jp

リリースマネジメントビフォーアフター

さっそく環境を整備してみました。対象はGoのパッケージ/ツールのリリースマネジメントです。

Before

  • リリース ... GoReleaser
  • リリースアセット作成 ... GoReleaser
  • Dockerイメージ作成 ... GoReleaser
  • HomebrewのFormulaの更新 ... GoReleaser
  • CHANGELOG更新 ... ghch
  • 次のバージョン決定 ... git-semv
  • リリース環境 ... ローカル

基本は手元でmakeコマンドを叩いてリリースしていました。

After

  • リリース ... tagpr
  • リリースアセット作成 ... GoReleaser
  • Dockerイメージ作成 ... GoReleaser
  • HomebrewのFormulaの更新 ... maltmillを使ってPull型に
  • CHANGELOG更新 ... tagpr
  • 次のバージョン決定 ... tagpr
  • リリース環境はGitHub Actions

具体的なGitHub Actionsのワークフローは以下のようになっています。なんとなく雰囲気はわかるかと思います。

name: tagpr
on:
  push:
    branches:
      - main

jobs:
  tagpr:
    runs-on: ubuntu-latest
    outputs:
      tagpr-tag: ${{ steps.run-tagpr.outputs.tag }}
    env:
      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    steps:
      - name: Check out source code
        uses: actions/checkout@v3

      - id: run-tagpr
        name: Run tagpr
        uses: Songmu/tagpr@v1

  release:
    needs: tagpr
    if: needs.tagpr.outputs.tagpr-tag != ''
    runs-on: macos-latest
    env:
      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    steps:
      - name: Setup docker
        uses: docker-practice/actions-setup-docker@master

      - name: Login to ghcr.io
        uses: docker/login-action@v1
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Check out source code
        uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Setup
        run: |
          brew uninstall go@1.17
          brew install go
          brew install goreleaser
          brew install sqlite3
          brew install messense/macos-cross-toolchains/x86_64-unknown-linux-gnu
      - name: Release
        run: |
          make release

結果

思惑通りになったし、tagpr開発者(であるSongmuさん)の思惑通りでもあったみたいです。

環境を整備してよかったです。私も良い体験でした。

GitHub上で構築するコードメトリクス計測基盤

TL;DR

長いので要約すると

  • octocovは計測したコードメトリクスをGitHub Actions Artifactsに保存すると、単体リポジトリでメトリクスの比較レポートなどもしてくれて便利
  • さらに octocovs-template を使って、各リポジトリのArtifactsに保存されているメトリクスを収集する専用リポジトリを作るとバッジも生成・配布できて便利

となります。


GitHub」というキーワードでお声かけいただき、「TECH STAND #9 GitHub」にて、本エントリと同名タイトルで発表させてもらいました。

standfm.connpass.com

GitHubの中の開発の仕方を知ることができたり、GitHubを使った様々な生産性向上のアプローチを知ることができたり、何よりいろんな方に octocov やペパボでの取り組みを知ってもらえてよかったです。

今回は、個人的にずっと模索していたことがTECH STANDでの発表やアフタートーク、その後フィードバックを通じて気づきを得て解決することができたのでそれを紹介したいと思います。

GitHub "のみで" 構築するコードメトリクス計測基盤

octocovはPull Requestへのコードメトリクスレポート機能やCLIによるカバレッジ確認機能などがあります。

なお、CLIによるカバレッジ機能については次のエントリをぜひ。

k1low.hatenablog.com

バッジ生成機能

その中でも面白い(しかし本人はいたって真面目に作った)機能として、バッジ生成機能があります。

せっかくCIで計測しているコードカバレッジやCode To Test Ratioやテスト実行時間をバッジにしてREADME.mdに貼りたいわけです。

↑こういうのです

そのためにパッケージも書いたりしています。

octocov/pkg/badge at main · k1LoW/octocov · GitHub

ただ、これには1つ個人的なこだわりで課題を持っていました。

CIで計測したコードメトリクスのバッジを生成したとして、そのバッジを誰が配布するのか

CIで計測した結果、その場でバッジの生成はできます。

しかしREADME.mdにそれを更新される状態で貼るには、バッジを常に更新されても固定のURLで公開する必要があるわけです。

その実現方法について満足していませんでした。

CI上で生成したバッジをそのままリポジトリのコミットしてしまう

実現方法の1つは、CI上で生成したバッジをそのままリポジトリのコミットしてしまう方法です。

コミットさえしてしまえばそれをREADME.mdから読むことは可能です。

# octocov

![coverage](docs/coverage.svg) ![ratio](docs/ratio.svg) ![time](docs/time.svg)

最近まで、リポジトリとしてのoctocovもこの方法をとっていました。

https://github.com/k1LoW/octocov/blob/v0.41.0/README.md?plain=1#L5

ただ、これには欠点があって「バッジのコミットが積まれてしまう」というものです。これがうざい。テスト実行時間も取得していることから結構な頻度でコミットが積まれていまいます。

Central modeを使う

もう1つはCentral modeを使う方法です。

octocovにはCentral modeというコードメトリクスを複数のリポジトリから収集するモードがあります。

現在は収集したコードメトリクスと、生成したバッジの一覧を生成する機能があります。Central modeを使えばバッジの配布が可能です。

このCentral modeを使う方法にも(今までは)「GitHubのみで構築するコードメトリクス基盤としては、Central modeのリポジトリ(Central repo)に各リポジトリのメトリクスデータを集約する構成の決定打がない」という課題がありました。

従来の実現方法としてはCentral repoに対して各リポジトリGitHub Actionsからコミットをするというものでした。

以下のような感じです。

図をみるとわかるようにCentral repoへコミットするためのPermissionが必要になってしまいます。

できれば、リポジトリにある secrets.GITHUB_TOKEN のみでいい感じに他リポジトリにコミットできる仕組みが欲しいところですが、今のところはありません*1。Parsonal Access Tokenが必要になってしまいます。

なんとかできないものかと思っていたのですが、現状は解決を諦めていました。

GitHub Actions Artifacts

ところで、

octocovに最近追加された機能として、「計測したコードメトリクスのデータをArtifactsに保存する」というものがありました。

これによってリポジトリ単体の機能の範囲で過去メトリクスを保存できるようになり、Pull Requestへのレポート時に「前回メトリクスとの比較」もレポートできるようになりました*2

作者である私自身のoctocovに対する機能の理解としてもここまでだったのですが、先日のイベント登壇からの流れでふと

リポジトリのArtifactsにあるコードメトリクスレポートをCentral repoから収集すればいいのでは?

と思い付いたのです。

そして、実際に設定してみると出来たのでした。

既に機能としては実現していたのに作者が気づいていなかったという...*3

実現イメージとしては以下のような感じです。

GitHub のみで コードメトリクスバッジ基盤を構築する方法

さて、具体的な設定方法です。前提として既にoctocovを利用してGitHub Actions Artifactsにコードメトリクスを保存しているPublicなリポジトリを持っている必要があります。

次にCentral repoを作ります。こちらはテンプレートリポジトリを用意しました。

github.com

このリポジトリの "Use this template" ボタンを押して完成です。終わり。

あとは .octocov.yml の central.reports.datastores: にコードメトリクスを収集したいリポジトリを追加していけば良いです。サンプルとして octocov のメトリクスを収集するようになっています。

central:
  reports:
    datastores:
      - artifact://k1LoW/octocov # delete this line
      # - artifact://owner/repo
      # - artifact://owner/other-repo
      # - artifact://owner/another-repo
  badges:
    datastores:
      - local://badges
  push:
    enable: true

実際にバッジを生成している私のリポジトリこちらです。

まとめ

やっと「GitHub上で構築するコードメトリクス計測基盤」を真の意味で実現できる道筋ができました。

Central modeは、現状は最新のコードメトリクスとバッジの一覧の配布のみに対応していますが、将来的にはメトリクスを蓄積して便利そうなダッシュボードなどをGitHubの機能のみでつくれるところまで実現したいとは思っています。今のところキーワードとなっているGitHubの機能は「FlatData」と「ActionsからPagesへの直接デプロイ」です。

ただ、まあ、、、

ぜひ皆さんも使ってみてください。「(個人や会社で)使っているよ」というフィードバックが一番嬉しいです。機能リクエストやPull Requestもお待ちしています。

*1: @kyanny さんにブログエントリ経由でリポジトリ間のアクセスについてまとまっている https://docs.github.com/ja/actions/security-guides/security-hardening-for-github-actions#considering-cross-repository-access を教えてもらいました

*2:データストアを使えば今までもできていましたが、リポジトリ単体で実現できるようになったのがポイントです

*3:なぜ既に機能として実現していたかというと、octocovがサポートするデータストアはREADは全て io/fs.FS インターフェースで揃えていたからです。詳しくは Go Conference 2021 Autumn の発表資料をご覧ください https://speakerdeck.com/k1low/go-conference-2021-autumn-online