GitHubに1コマンドでいろいろPUTできるツールghputを作った

ghput pr-comment ghput issue-comment のデフォルトの挙動について注意点を追記しました

最近はGitHubやGH:Eといったサービスのリポジトリと、そのリポジトリと連携するCI/CD環境がある前提で、様々なパイプラインを作ることが普通になってきています。

git push や Pull Request をトリガーにCI/CD環境で実行されるのもテストの実行だけではなく、master mergeのタイミングでのプロダクションデプロイやプロビジョニング、その前段階としてPull Requestタイミングでのdry-runやplanの実行など。

GitHubは便利ですし、それと連携するCI/CD環境があるとその2つだけで様々なものの自動化ができて便利です*1

そんなGitHub+CI/CDな環境で使えるであろう ghput というツールを作りました。

github.com

使い方

インストールはこちらにある通りです。

MacだとHomebrewでインストールできます。

$ brew install k1LoW/tap/ghput

ghput は「GitHubにいろいろPUTできる」ツールなのでその名前にしたのですが、どう使えるのかわかりにくいので以下に例で示します。

例1: Pull Requestのイベントトリガーで terraform plan などのCIの実行結果をそのPull Requestに貼り付ける

インフラの構成やIAMをTerraformCodenize toolsを使ってコードにして、それをGitHubで管理するというプラクティスは良く取られると思います。

インフラのコードをGitHubで管理しているのですから、おそらく構成変更はPull Requestベースで行われるでしょう。

そのPull RequestをトリガーにCIで terraform planmiam --apply --dry-run を実行。そして実行結果を確認してからマージするというサイクルの構築は容易に考えられます。

その実行結果を毎回CIのWeb UIで確認するのではなく、Pull Requestにコメントで貼り付けてあると視認性もあがり記録もGitHubに残り便利です(そしてそのようなものを書いている方は多そうです)。

ghput pr-comment を使うと、1からGitHub連携のスクリプトを書くよりかは簡単に実現できます。

例えば terraform plan の結果を github.com/myname/myrepo の #2 の Pull Requestにコメントするには以下のようなコマンドをCIで実行すればOKです。

$ terraform plan | tee plan.txt
$ cat plan.txt | sed -n -e "/---/","/---/p" | \
GITHUB_TOKEN=XXXXXxxxxxXXxxxx \
ghput pr-comment \
--owner myname \
--repo myrepo \
--number 2 \
--header='```\n' \
--footer='\n```'

ghput pr-comment は標準入力をPull Requestにコメントします。terraform plan の出力をそのままコメントすると表示が崩れるので、コードブロックにするために --header--footer で囲っています。

例えばRubyならOctokitですぐに書ける内容ですが、CI環境にRubyを用意するのがどうしても難しいときなどに便利です。

もしIssueにコメントしたいときは ghput issue-comment で可能です。

ghput pr-comment ghput issue-comment のデフォルトの挙動の注意点

ghput pr-commentghput issue-comment はデフォルトでは「前回のコメントを削除して、新規コメント登録する」という動きをします。

これは、Pull Requestでコミットを積むようなユースケースを想定している(CI経由でコメントされまくるのがイヤだ)からなのですが、これは --key オプションを使うことで変更できます。

ghput pr-commentghput issue-comment--key で指定される値で一意を保とうとします。

なので、

  • どんどんコメントを積み重ねて欲しい場合は --key=$RANDOM などとしてkeyをユニークにする
  • A、B2種類のコメントそれぞれ最新だけ残したい場合は、--key=A --key=B などとしてコメントする

といった形で使い分けてください。

例2: 1コマンドでGitHubリポジトリにcommitして、CIで次のアクションを実行する

私は「1コマンドでGitHubリポジトリにcommitできる」と、面白いことができると考えています。

例えば

  • 定期的に各サーバのインストール済みパッケージ一覧を1つのリポジトリに集約してcommit。CIで脆弱性チェック。
  • データベースのスキーマ情報を tbls out -t json -o schema.jsonJSON化しcommit。CIで tbls doc json:///path/to/schema.json を実行してドキュメント生成。
  • メインはCIのテンポラリな実行環境としての利用。empry commitでイベント発火して実行。発火の記録はコミットログとして残る。

など。

ghput commit を使うと、事前のgit cloneなどなしにリポジトリにcommitができます。

$ GITHUB_TOKEN=XXXXXxxxxxXXxxxx \
ghput commit \
--owner myname \
--repo myrepo \
--branch master \
--file file.txt \
--path path/to/file.txt 
--message 'Commit file !!'

--file --path 指定がなければ empty commit になります。

GitHub+CI/CDを前提にする

GitHubはもはやインフラですし、それと連携するCI/CD環境もそうなってきていると思います。

GitHub1つではなくGitHubとCI/CI環境の2つを前提として考えるといろいろ面白い仕組みが作れそうです。

その時にghputが使えると嬉しいですし、ghput自体ももう少しPUTできるものを増やそうかなと思っています。

*1:つまり、GitHub ActionsがGH:Eに来ることを切望しています

Cacooのデータベーススキーマ機能で、例えばBigQueryのER図を出力する

Cacooで「データベーススキーマを自動生成できる」という素晴らしい機能が先週発表されました。

cacoo.com

Cacooが提供するSQLクエリをデータベースで実行して、その結果をCSVファイルとしてエクスポートしてCacooにアップロードするだけでER図が生成されるというものです。

現時点で公式サポートされているのはMySQLPostgreSQLですが、

ということなので、tbls out のサポートフォーマットにCacooのデータベーススキーマ機能用のCSVcacoo )を追加しました。tbls v1.33.0で試すことができます。

MySQLのデータベーススキーマ

まずはMySQLのデータベースで試してみましょう。

対象として、tblsのテストケースやサンプル生成で利用しているDDLを利用します。

Cacoo SQL:

Cacoo提供のSQLで生成されるER図は以下です。

f:id:k1LoW:20200420012025p:plain
cacoo sql

tbls out:

tbls out に新たに追加されたフォーマット cacoo を使うことでCacooのデータベーススキーマ機能用のCSVを出力できます。

$ tbls out my://root:mypass@localhost:33306/testdb -t cacoo -o schema.csv

f:id:k1LoW:20200420011447p:plain
tbls out

違いは以下のような感じです。

  • character_maximum_lengthの取り扱い
  • enumの取り扱い
  • VIEWテーブルの取り扱い

Cacooとtbls out との差はありますが、十分に使えそうです。

また、tblsにはVirtualなリレーションを .tbls.yml で拡張できる機能があります。

$ tbls out my://root:mypass@localhost:33306/testdb -c tbls.yml -t cacoo -o schema.csv

f:id:k1LoW:20200420012614p:plain
tbls out with .tbls.yml

リレーションを表すエッジが増えました。

現時点ではCacooのCSVの仕様上 FK としてVirtualなリレーションを追加していますが*1、追加でリレーションを表すエッジが引かれていることがわかるかと思います。

例えば、BigQueryのER図を出力する

tbls out で出力したCSVでもCacooでER図が生成できるということはつまり、tblsがサポートしている全てのDBMSでCacooでER図が生成できる ということですね。

試しにBigQueryのデータセットのER図を生成してみます。

対象とするのはtblsのサンプルドキュメントでも利用している bigquery-public-data/crypto_bitcoin です。

$ tbls out bq://bigquery-public-data/crypto_bitcoin?creds=client_secrets.json -c crypto_bitcoin_tbls.yml -t cacoo -o schema.csv

f:id:k1LoW:20200420013434p:plain
bq

普通に生成できました。 tbls.ymlによるVirtualなリレーションも再現されています。

というわけで

つまり、Cacooのデータベーススキーマ機能は実質

に対応しているわけですね。Cacoo便利!

是非試してみてください。簡単にCacoo上にER図が生成されるの、感動ものですよ。

*1:CSVのCONSTRAINT_TYPEのカラムが"FOREIGN KEY"でなくてもREFERENCED_*なカラムにちゃんと値が入っていたらnon-FKでリレーションを引いてくれるようになると嬉しいです!Cacooの中の人よろしくご検討ください!

データベースドキュメント生成コマンド tbls 更新情報 ( PostgreSQL publicスキーマ表示仕様変更/Amazon DynamoDB対応/goccy ware etc)

ここ最近tblsのアップデートエントリを書いていなかったのですが、最近変更をいくつか行いました。

このまま放置するとちょっと紹介しきれなくなりそうなので、ここら辺で放出しておこうと思います。

紹介時点のtblsのバージョンはv1.29.0です。

PostgreSQLでの public. スキーマ表示仕様変更

tblsでは、もともとPostgreSQLpublic. スキーマschema_name.table_name.column_nameschema_name )だけ特別に非表示にしていました。

こうなっていた理由は、私がPostgreSQLでのスキーマを意識した運用経験がなかったことに寄る部分が大きいです。「デフォルトだから非表示で良いだろう」と。

ところで、tblsにはlintの機能があります。「テーブルカラムにコメントが書かれているか?」とか「外部キーの参照元にINDEXが張られているか?」とか。

そのlint機能に対して「public. スキーマだけexcludeしたいができない」というIssueが立てられました。

github.com

tbls lint が提供しているルール*1には「このテーブル名/カラム名の場合だけ除外する」という除外設定があるのですが、tblsでは publc. が非表示なので、 exclude: public.* みたいな書き方ができないというものです。

なるほど。。。確かに。。。ということで「時間をください」とだけ伝えて検討することにしました。

とはいえ上記で書いたように私には経験がないのでいろいろ悩んだ挙句、有識者のいるであろうSlackのpostgresql-jpで質問してみることにしました*2

わかったことは

  • スキーマは積極的に、有効に使われていることがわかりました。スキーマを利用して様々な意図でグルーピング(Namespaceを切るようなもの?)をしているとのことでした。また、 public. を意図して使わない方も。
  • そもそも public.厳密にはデフォルトではない"5.8.3. スキーマ検索パス" )ということも教えていただきました。

ということで、完全にtblsの実装が良くないと判断できたので public. スキーマも他のスキーマと同様に表示するように変更しました。

v1.28.0から適用されています。

Amazon DynamoDBに対応

Amazon DynamoDBにも対応しました。

DSNは

dynamodb://[aws_region]

とシンプルです。

そして、Amazon DynamoDBに対応するために、合わせて次に紹介する2つの機能をリリースしました。

include: テーブルをフィルタリングする機能を追加

Amazon DynamoDBにはテーブルをグルーピングする「データベース」や「PostgreSQLスキーマ」のようなくくりはありません。同一リージョンであれば、aws dynamodb list-tables コマンドなどで全てのテーブルがリストされます。

今時はAWSアカウントをアプリケーション分作成することが多いと思うのですが、例えば同一アカウント同一リージョンで複数のアプリケーション用のDynamoDBテーブルの運用をしているときなど、tblsでドキュメント化するテーブルを絞り込みたいことがあるだろうと考えました。

そこで、もともとあったテーブルフィルタリング機能 exclude: に加え include: を設定できるように機能を追加しました。

include:exclude: との関係は以下の図のようになっています。

f:id:k1LoW:20200314142527p:plain

これを利用することで、tblsで管理するテーブルを柔軟に絞り込むことが可能になっています。

dict: ドキュメントタイトルやテーブルヘッダの文字列を変更する機能を追加

これもAmazon DynamoDB対応を契機に設計をしたものです。

Amazon DynamoDBにおいて、TableTable なのですが、RDBにおける Column はDynamoDBでは Attribute 、制約( Constraints ) もPrimary Keyしかないですし、 Index も正確には Secondary Index です。

DynamoDBのドキュメントも上記の単語を使いたいと考えていました。

また、ユーザも表記を変えたいことがあるだろうと考えて dict: を追加しました。

これは、単語と単語の変換用辞書を設定できるというものです。例えば以下のように .tbls.yml に設定すると tbls doctbls out -t xlsx で出力されるドキュメントが日本語化されます。

# .tbls.yml
---
dict:
  Tables: テーブル一覧
  Description: 概要
  Columns: カラム一覧
  Indexes: INDEX一覧
  Constraints: 制約一覧
  Triggers: トリガー
  Relations: ER図
  Name: 名前
  Comment: コメント
  Type: タイプ
  Default: デフォルト値
  Children: 子テーブル
  Parents: 親テーブル
  Definition: 定義
  Table Definition: テーブル定義

上記に加え、各データベースへ接続するためのドライバにもデフォルトの辞書を内部に持たせるようにすることでAmazon DynamoDBのドキュメントの場合だけ AttributeSecondary Indexes と表記できるようにしました。

distance: ER図として表示する隣接するテーブルの距離を設定できる機能を追加

tbls doc で生成されたドキュメントの各テーブル定義のmdには、そのテーブルを中心として隣接したテーブルをレンダリングしたER図を表示しています。

ただ、ここの表示が隣のテーブルまで(距離1)で固定でした。

PlantERDというCLIツールがあります。

github.com

データベースに接続し情報取得しER図を出力するのですが、出力フォーマットにPlantUMLを選択することで 文字列なのに視覚的にいい感じに 、 それをGitで管理することによって スキーマ変更前後の差分もいい感じに 把握できるという特徴があります。

このPlantERDの作者の sue445 さんのPlantERDリリースと実装(経緯とか方針とか)についての紹介エントリを読んで、tblsと近い部分(複数DBのつらみとか)に共感しつつ、

sue445さんの「特定のテーブルに隣接するテーブルのみを抽出して実装把握のための情報にする *3 」という手法に「なるほど!」と納得しつつ、「distance良いな」と、tblsにも実装しました。

.tbls.yml での設定は以下のような感じです(デフォルトは 1 )。

# .tbls.yml
er:
  distance: 2

また、 tbls out コマンドにも --distance オプションを追加していますので、以下のようなテーブルのER図を出力するような場合には有効になります。

$ tbls out -t svg --table users --distance 2 -o users.svg

Graphvizdot コマンド依存の脱却

tblsはER図の生成にGraphvizdot コマンドを外部コマンドとして利用していましたが goccy さんの goccy/go-graphviz を利用することでtbls内にER図生成機能を内包できるようになりました。

github.com

これによりtblsのポータビリティがさらに上がりました。

これ、上記紹介だとたった3行ですけど、go-graphvizが実現していること相当すごいですよね...

READMEの"How it works"にgo-graphvizアーキテクチャが簡単に紹介されていますので興味ある人は是非。

YAMLパッケージ goccy/go-yaml の採用

go-graphviz に続き goccy ware です。

なぜ goccy/go-yaml なのか

tblsは設定ファイル .tbls.yml のフォーマットにYAMLを採用しています。

そして実際にtblsでプロダクションレベルのデータベースのドキュメントを運用すると、その .tbls.yml がどんどん肥大化していきます。

これについては課題と考えており、その解決方法としてYAMLのアンカーやエイリアスの機能だけでなくYAMLファイル分割のサポートが必要になりそうだと考えていました。

そして、この課題を解決してくれそうなポテンシャルを持っているYAMLパッケージとして goccy/go-yaml を採用しました。

詳しくは以下のQiitaのエントリが(作者本人の紹介ということもあり)詳しいです。

qiita.com

v1.29.0時点ではまだgo-yaml/yamlからgoccy/go-yamlに差し替えただけですが、これからの機能開発時に真価を発揮すると思っています。


というわけで、駆け足でtblsの最近のアップデートの紹介でした(紹介していない機能追加もあります)。

tblsの利用分布はGitHub Starを見ると日本だけに集中しているわけでもなく世界中でまんべんなく使われている(?)ようです。これは嬉しい事実です。

データベースドキュメント*4がCIで最新であり続ける状態が普通になると良いなと思っています。

まだ実装したい機能はあるので、引き続きじっくり開発を進めたいと思います。

*1:RubocopのCopみたいなものです

*2:postgresql-jpのみなさん、突然の私の質問に知識や経験を共有していただいて本当にありがとうございました

*3:実はtblsも "tbls out -t plant_uml --table users" でPlantUMLを出力できるのですが、v1.29.0時点ではINDEX情報が出力されないなど、PlantERDが持つ「PlantUMLのみで把握する」という目的はカバーできません

*4:私はスキーマ情報だけでなくそれに付随する情報も合わせて初めてドキュメントだと考えています

いつの間にか https://play.golang.org/ でサードパーティパッケージをimportできるように、なんならgo.modでバージョンやコミットハッシュを指定できるようになっていた(続きあり)

結論は最後に書いてあります。

PTFという社内勉強会で、私が端々が間違っていたりするちょっと微妙な紹介をしてしまったので、改めてエントリに記載しておこうと思います。

PTFについては以下をご覧ください。

tech.pepabo.com

The Go Playgroundでいつの間にかサードパーティパッケージをimportできるようになっていた。

私が気づかなかっただけで結構前からそうだったみたいです。

https://play.golang.org/p/w0uRS17zhjR

上記URLのコードでは github.com/goccy/go-yaml を importしているのがわかると思います。

go.mod でパッケージバージョンを指定できるようになっていた

さらに、go.modでパッケージバージョンを指定できるようになっていました。

https://play.golang.org/p/AtA0pdyvMpf

下部に

-- go.mod --
module play.ground

require github.com/goccy/go-yaml v1.1.0

と書いている箇所ですね。

標準パッケージだけの時と比べて、用途は広がります。すぐ思いつくのはバージョン差の動作を示したりとか。

積極的に使っていこうと思います。


で、ここまでが私が気づいたことで、実はThe Go Playgroundは以下のようにもっともっと便利になっていたというのが事実でした。気づかなかったー!!

qiita.com

gp 便利!

PHPerKaigi 2020で開発開始までのオーバーヘッドとその削減について発表をした #phperkaigi

PHPerKaigiに初参加してきました。

phperkaigi.jp

噂に違わぬ面白さでした。発表もとても面白かったのですが、それ以外の充実度が際立っていたカンファレンスでした。

まず、なんといってもトレーディングカードです。

f:id:k1LoW:20200221020111j:plain

まさか自分がカードになるとは思わなかった。

白黒アイコン組の@hiro_yさんと「もっとクリーチャーっぽいアイコンに変えておけば良かったですねー」と話したり(あと、正しく使われているZend Frameworkの良さについて話したり)。

今後、PHP系カンファレンスには持って行こうと思います。

それ以外にもTrack Cというスペースでのイベントが充実していて、本当に楽しかったです。フリープロジェクターが設置してあって突然のゲリラ発表が行われたり、Ask the Speakerで話し込んだり、ゲリラIRTで@sizuhikoさんにずっと質問し続けたり、PHPerトークンを探している人の挙動不審具合を眺めたり。

あ、コート掛け!めっちゃ助かりました!バックパックはノートPCを持ち歩くので手に持っているのですがジャケットは脱いでおきたい。これは嬉しかったです。

発表

「知らないWebアプリケーションの開発に途中からJOINしたとき、どこから切り込むか?」というタイトルで発表をしてきました。

「プロジェクトに途中JOINしたとき(受け入れた時)のノウハウ」というフワッとしたモノを「開発開始までのオーバーヘッドの削減」と言い換えることで、体系化に挑戦してそして削減手法について考えてみるという内容です。

今回の発表で共有したかったことをは以下の2点です。

  • 開発までのオーバーヘッド削減について、もし体系化をすることができたら、組織としてより戦略的な手段を取れるのではないか
  • 「オーバーヘッド」という視点で見ることで技術的に解決できる範囲があるのではないか

伝えたいことは伝わったと感じられた反面、TwitterSpeaker Deckについたはてブ、ブログなどでのフィードバックをみるとまだまだ体系化するに当たって「自分自身の知見や経験が足りない」と感じたのと(非常に良いフィードバックをもらえました!)、もう少し後半戦の「技術的に解決する」という箇所を強調しても良かったかなと思いました。

ここらへんは私が解決したい領域でもあるので、継続してブラッシュアップしていきたいなと思っています。

とても有意義な発表になりました。

というわけで

私のPHPerKaigi 2020はこのエントリをもって終了です。

ありがとうございました!

MacBookの電源やWi-Fi、Bluetoothの接続が切れたのをトリガーにコマンドを実行しつづけるCLIツールを作った

2週に1度くらいFukuoka Growth Nextコワーキングスペースを使わせてもらっています*1

その時ちょっとだけ席を立ちたいときに、展開しているMacBookバックパックを「置いておくか」「持っていくか」いつも悩みます。

バックパックはワイヤーを持ち歩いているので机に縛ってしまえばいいのですが、MacBookはそうもいかないので少しだけ安心できるような仕組みが欲しいなと思っていました。プライベートのMacBookとはいえ、盗まれたら家計に大打撃です*2

日本ですしコワーキングスペースという出入りが限定されているエリアなのでそこまで気にする必要はないんですが。

「そういえば昔そんなこと考えていたなー」と思ったら、アイデアをエントリに残していました。

k1low.hatenablog.com

なるほど。アプリとまでいかないまでもシェルスクリプトとかCLIツールで作れば良さそうと思って作ってみました。

github.com

これは何?

電源ケーブル、もしくはWi-FiBluetoothを指定して実行しておくと、その接続が切れたことを検知して、接続が切れている間指定のコマンドを 実行し続ける というだけのCLIツールです。

インストール

macOSというかMacBook専用コマンドなのでHomebrewでのインストールがオススメです。

$ brew install k1LoW/tap/connected

使い方

コワーキングスペースなどでちょっと席を立つときに、電源ケーブルを電源に繋いだ状態で以下のようなコマンドを実行しておきます。

$ connected watch -- say "電源ケーブルが外れています"

そうすると、電源ケーブルが外れたときに say コマンドが実行され続けます。

音量を下げられても対応できるようにosascriptでボリュームを最大にするのも良いかもしれません。

$ connected watch -c 'osascript -e "set Volume 10"; say "電源ケーブルが外れています"'

実行するコマンドは任意のものを指定できるので、Slackに通知したりTwilio経由で電話をかけたりすることも可能です。

電源ではなくWi-Fiの接続を利用したいときは--wifi オプション、Bluetoothバイスとの接続を利用したいときは --bluetooth オプションを指定します。

$ connected watch --wifi -- sh ./slack_notify.sh
$ connected watch --bluetooth -- sh ./twilio_call.sh

というわけで

なんとなく作ってみました。

特に抑止力にはならなそうですが、ちょっとした安心が欲しい方はどうぞ。

*1:平日もfgnで業務をすることもできるのですが、私の場合は主に休日の趣味プログラミングのためです

*2:そういえばキーボードの効きが悪くなったと思っていたらキーボード修理プログラムの対象でした

2019年の振り返りと2020年の抱負

明けていました

2019年の振り返り

嵐のように過ぎ去った1年でした。

と言っても残念ながら私が何かを成し遂げたわけではなく、子供の成長についていくのと仕事面でも周りの変化/進化についていくのに精一杯だった受動的な1年だったような気がします。

その結果、おそらく1年前の私ならブログエントリやツイートに残していたであろう数々のイベントがスルーされています。イベント消化で精一杯。

2019年の目標は「変化に適応することを楽しむ」でした。

確実に変化を楽しめてはいたと思うのですが、その変化が予想以上でした。

24時間3-4時間おきにミルクを飲ませておけば瞬殺で寝ていた子が、保育園に行き、離乳食を食べ、喋りだし、歩きだし、踊り、生えた歯で噛みつき、おもちゃをぶん投げるところまできました*1

最近知ったのですが、これから「夜泣き」というものがはじまるらしいですね。もうそういう深夜インシデントは落ち着いたものかと思っていたので戦々恐々としています。

これからも楽しみでしょうがないです。

OSS活動

いろいろ作りました

やはりGo製のものが多くなっています。Sheer Heart AttackHarvestfiltなど、サーバオペレーションをサポートするようなOSSが作れたと思います。

個人的には、Sheer Heart Attackはサーバオペレーションにおけるデバッグツール?として、ニッチな領域を攻めることができたなと思っていて、もう少し広めたい気持ちです。

発表

Go Conference ‘19Summer in Fukuokaは緊張しました

2020年の抱負

今年は「視座を上げる」です。

これは私の特性で弱点でもあるのですが、目の前の課題に対してはいろいろなアプローチがとれるのですが、もっと大きな視点で物事を考えて行動に移すことができません。

これについてはエンジニアとしてだけでなくヒトとしてもです。

「壮大なビジョンを持って〜」とはいいませんが、せめて様々な行動の点と点をもう少し早めに、意識的に結べるようになりたい。

そのためにはもっと視点の背伸びが必要かなと考えています。

とはいえ、何をどうはじめていけばいいのかどうにも見当がつかず、実はこのエントリも出せずにずっと下書きでした。

今年のうちに何かきっかけだけでも見つけられればと思います。

*1:私の写真が各所で出るたびに「痩せた?」と言われるのですが5kg痩せました。