tblsをセットアップするGitHub Actionとしてsetup-tbls(を作るツールとしてgh-setup)を作った

タイトルが何を言っているのかよくわからないと思いますので順を追って紹介したいと思います。

tblsをセットアップするGitHub Actionとしてsetup-tbls を作った

setup-tblsはtblsをインストールしてくれるGitHub Actionです。

github.com

各所で「ないの?」とは言われており(最近Issueもたった)、いつか作らないとなと思っていたのですが、いろいろ重なって作りました。

github.com

私はGoで作ったツールのActionはDocker container actionを使うのですが、tblsでそうするとDockerコンテナ上で動くtblsからデータベースサーバの名前解決ができなかったりして、それも手を鈍らせている原因でした。

今回作成した setup-tbls はComposite actionで作っているので上記のような心配もありません。

なお余談ですが、ActionというかRunner上のJobの実行環境については次の資料にまとめてあります。

speakerdeck.com

使い方は簡単で紹介するまでもないですが、 uses: k1low/setup-tbls@v1 で呼び出せば終わりです。

# .github/workflows/doc.yml
name: Document

on:
  push:
    branches:
      - main

jobs:
  doc:
    runs-on: ubuntu-latest
    steps:
      -
        name: Checkout .tbls.yml
        uses: actions/checkout@v3
      -
        uses: k1low/setup-tbls@v1
      -
        name: Run tbls for generate database document
        run: tbls doc

setup-*GitHub Actionを作るためのツールとして gh-setup を作った

setup-*install-* というActionは、大抵は実行ファイルをPATHに設置してくれるものです。

Goであれば本当にバイナリポン置きでいいのですし、そのバイナリは大抵GitHub Releasesにあるのであとは設置するだけなのですが、意外にこれが面倒なのです。

  1. まず実行環境を特定する(OSやArch)
  2. GitHub Releasesから特定バージョンもしくはlatestなリリースを特定
  3. 1の実行環境に適したリリースアセットを特定
  4. 3のリリースアセットが圧縮ファイルだったら展開
  5. 4の展開したファイルから必要なもの(今回は実行ファイル)だけ取得
  6. 実行環境のPATHを特定し5のファイルを設置

また、GitHub Releasesへのアセットの置き方も開発者によって、リポジトリによって千差万別です。私個人でもバラバラです(その時々でマイブームがある)。

それをいい感じにしてくれるツールとして gh-setup を作りました。

github.com

使い方はいくつかあるのですが、今回はGitHub Actionとしての使い方を紹介します*1

例えば、tblsをインストールする場合は以下のように書けます。

# .github/workflows/doc.yml
[...]
    steps:
      -
        name: Setup k1LoW/tbls
        run: k1LoW/gh-setup@v1
        with:
          repo: k1LoW/tbls

これだけで、煩わしい「GitHub Releaseからアセットを取得して実行ファイルをPATHに設置」をやってくれます。 中身は結構泥臭い実装が入っています。気になる方は是非 gh-setup のソースコードをご覧ください。

また、泥臭い実装を信用できない人にもいろいろオプションを用意していますので、詳しくは action.ymlのinputs:セクション をご覧ください。

さて、ここまで来たら勘のいい方はわかるかと思いますが、setup-tblsはgh-setupを組み込んで作っています。

setup-tblsのaction.ymlは次のとおりです。

name: 'Setup tbls'
description: 'GitHub Action for tbls, a CI-Friendly tool for document a database, written in Go.'
branding:
  icon: 'box'
  color: 'blue'
inputs:
  github-token:
    description: The GitHub token
    default: ${{ github.token }}
    required: false
  version:
    description: Version of tbls
    default: latest
    required: false
  force:
    description: Enable force setup
    default: ''
    required: false
runs:
  using: 'composite'
  steps:
    -
      uses: k1LoW/gh-setup@v1
      with:
        repo: github.com/k1LoW/tbls
        github-token: ${{ inputs.github-token }}
        version: ${{ inputs.version }}
        bin-match: tbls
        strict: true
        force: ${{ inputs.force }}

これだけです。ほとんどの処理はgh-setupの中にあります。

setup-* というGitHub Actionを作りたい方へ

是非 gh-setup をご検討ください。うまく動かない、気に食わない挙動についてはフィードバックいただけると嬉しいです。

これで setup-* は作りたい放題!

*1:実はGitHub CLI extensionとしてもスタンドアローンCLIツールとしても使えます

データベースドキュメント生成コマンド 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さん)の思惑通りでもあったみたいです。

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