Goでつくったもの 2023年

はじめに

『Goでつくるインタプリタ』を写経した、という記事を半年ほど前に書いた。

n-seki.hatenablog.com

この記事の最後で、

この本を読み進めながら、Slack APIを叩くCLIか何か作ろうかな。

と書いており、アンサー記事ということで、Goでつくったものをつらつらと紹介していく。

コードの公開・非公開問わず、ツールっぽいものを4つ作ったよ。

slack2md

github.com

過去24時間で投稿されたSlackのメッセージをMarkdown形式のファイルにしてくれるツール。 個人Slackを日記代わりにしたくて作った。

オプションとして、Markdownに含めるチャンネルやユーザーを指定できる。

実装はあまりがんばっておらず、たとえばページングには対応していない。なので過去24時間で1チャンネルあたり100件以上の投稿があった場合には取りこぼしが発生する。直したいとは思っている(が、唯一のユーザーである自分が困っていないので......)。

Slackメッセージの取得には https://github.com/slack-go/slack を使っているが、一部RichTextが未対応なものがあり、自分で実装する必要があった。

自分はこのツールをMacAutomatorで定時実行することで日記(というかバックアップに近い)を自動生成している。

emv-go

EMVで定義されるTLVデータ(文字列)をデコードして、ヒューマンリーダブルな形式で標準出力してくれるツール。これはコードは公開していないのだけれど、特別な理由があるわけではなく、単に大量のタグを定義するのに飽きてしまい開発が止まっているため。

EMVやTLVについてはこの記事がとても分かりやすいのでおすすめ。

qiita.com

このツールを実装しているときに、EMVでTLVがどのように定義されているか確認したのだけれど、L = Length 部について誤解していたことがあった。

Length部は固定長だと思っていたのだけど、なんと可変長だった。Length部の最初の2バイトを見たときに、先頭ビット(0x10000000)が立っている場合には下位7ビットが Length 部の長さを表す。

たとえば Length に相当するデータが次のような2進数で表現できる値であった場合、

1000 0010 00011 1001

最初の2バイトの先頭ビットが立っているので、0x01111111とマスクすることで得られる 0x0010 がLength部の長さになる。 0x0010は10進数では2なので、以降の2バイトが長さを表している。この例だと、0x000111001 がData部の長さになる。

なるほどなと思った。これによってデータ部が長くても対応できる。

あとは、LTVのV = Value部はさらに別のLTVを含んでいる場合があるために再帰的にパースを行ったりと面白いトピックがあって、実装するのは楽しかった。

slack2bsky

Slackでスタンプを付けた投稿をBlueskyに投稿するツール。 Google Cloud Functionsで動かしている。

SlackのWebhookでリアクションイベントでClound Functionsがリクエストされるようにして、Function側ではリクエストの検証などを経て投稿内容をBlueskyに投稿する。Blueskyとの通信では indigo を使っている。

github.com

当初はライブラリを使わずにAT ProtocolのAPIを直接叩く実装をしていた。AT Protocolの仕様に触れられてよかった。

atproto.com

indigoで完全に書き換えたらコード公開したい。

repo-pr-stat

github.com

GitHub RepositoryのPull Requestに関する以下の情報を、指定された期間で算出するツール。

  • PRの数
  • PRが作成されてからマージされるまでの平均時間
  • PRがオープンになってからマージされるまでの平均時間
  • コントリビューター毎のPR作成数

これらをJSON形式で標準出力に出力する。

似たようなツールはいろいろあるのだが、「PRがオープンになってからマージされるまでの平均時間」を出してくれるものがなかったので作った、という感じ(あまり頑張っては探してないので、そういうツールはあるかもしれない)。

実は、GitHub APIで得られるPRを表すJSONには「オープンされた時刻」という情報は含まれていない。

ではどうしているのかというと、issueのイベントを取得するエンドポイントを利用している。

docs.github.com

Pull Requestなのに issue のエンドポイント?と疑問に思ったかもしれない。自分も思った。

しかしこのエンドポイントでは、パラメータ issue_number にPRのnumberを渡すと、ちゃんとPRのイベントを返してくれる。 (参考 https://docs.github.com/ja/rest/issues/events?apiVersion=2022-11-28#about-events

で、イベントを取得したら ready_for_review のイベントを探す。あったらそのイベント発生時刻がPRがオープンされた時刻だ。

実装はあまり頑張らず、100件固定でイベントを取得している(ページングなし)。この100件にready_for_review がなかったら Draft の期間なしでPR作成時にOpenされた、とみなしている。

イベントにはコミットやコメントなどが含まれるので、1つのPRで100件を超えることは普通にありそうだが、ready_for_reviewが101件目以降に現れるというのは稀なケースだろうと思って妥協している。