みずぴー日記

月に行こうという目標があったから、アポロは月に行けた。飛行機を改良した結果、月に行けたわけではない。

複数列Slack

Slack のデスクトップアプリは、1つのチャンネルしか表示できないため一覧性が悪い。 そこで、複数のチャンネルを一度に表示できるアプリを作った。

f:id:mzp:20170430175855p:plain

📦ダウンロード

https://github.com/mzp/SlackStack

😫チャンネル切り替え作業の増加

Slack のデスクトップアプリは、チャンネルを1つしか表示できない。

そのため、参加するチャンネルに比例し、切り替え作業が増えていく。 さらに切り替え作業中に未読が増え、延々とチャンネルを切り替え続けることになる。

また同様の理由でメッセージを見落すことも増え、チャットのレスポンスも悪化していく。

📑Slack☆Stack

そこで一画面で複数チャンネルの内容を確認するためのアプリを作成した。 オフィスでは縦置きのモニタを使っているので、横方向にも縦方向にも重ねれるようになっている。

f:id:mzp:20170430181429p:plain

🔧開発の様子

ブラウザを並べる

f:id:mzp:20170430182842p:plain

Slackを開いたブラウザを複数並べて、複数のチャンネルを見れるようにした。 Magnet – Window manager for Macでウインドウを整列した上で、Slack: Hide sidebar when window is narrow | Userstyles.orgでチャンネルリストを非表示にした。

Slackアプリ

WebViewを貼りつけただけのアプリを作ったら、それなりに動くようになった。 Slackはすごい。

複数行化

そのまま横に並べて複数行化した。 また、読み込み時にカスタムCSSを読み込ませ、チャンネルリストを非表示にしている。

チャンネルの追加、削除に対応

f:id:mzp:20170430185017p:plain

メニューを実装し、チャンネルの追加・削除をできるようにした。

NSStackView

NSStackViewを使い、何個でも横に並べれるようにした。

行の追加

NSStackView自体をNSStackViewで重ねるようにし、縦方向にも重ねれるようにした。

fastlane

fastlane/gym at master · fastlane/fastlane · GitHubを使って、ビルド・署名するようにした。 LoveLiverのGymfileを参考にしている。

アイコン

StackのアイコンYosemite風のアイコンが簡単に作れるツール作った - Qiitaを組合せて、アイコンを作った。

f:id:mzp:20170430190045p:plain

配布用zip

Github releases にアップロードするためにzipファイルを作成したら、なぜか署名が破損した。 Finderから圧縮するようにしたら破損しなくなった。

😀 for zsh

github等で使える絵文字コード(:sushi: みたいなやつ)を入力するzaw のsourcesを作った。

f:id:mzp:20170401115250p:plain

コミットメッセージの先頭に絵文字をいれるようにしているので、それを入力するときに便利。

f:id:mzp:20170401115943g:plain

📦インストール

antigen でインストールする。

antigen bundle mzp/zaw-emoji

🛠絵文字コードの取得

文字コードと絵文字の対応はgemojiで生成している。

https://github.com/uasi/skk-emoji-jisyoを参考にした。

🐬Docker for Mac without qcow2

Docker for MacのファイルIOが遅い。VirtualBox上で動いているDockerと比較しても遅い。

これにはいくつかの原因があるが、その1つとしてディスクイメージのフォーマットとしてqcow2を用いていることがあげられる。

qcow2は書き込み時に必要な容量を確保するcopy on write方式のディスクイメージだが、これを事前に必要な容量をすべて確保するrawファーマットに差し替えたところ、パフォーマンスが改善した。

使い方

既存のDockerイメージは消えます

https://github.com/mzp/docker.img

curl https://raw.githubusercontent.com/mzp/Docker.img/master/install.sh | bash

ベンチマーク

fioを用いてベンチマークを行なったところ、Docker Machine(VirtualBox)と同程度のパフォーマンスはでるようになった。*1

読み込み

Average(MiB/s) Min(MiB/s) Max(MiB/s)
native 361 361 361
docker machine 105 105 105
qcow2 46 46 46
raw 147 147 147

書き込み

Average(MiB/s) Min(MiB/s) Max(MiB/s)
native 487 487 487
docker machine 51 51 51
qcow2 29 29 29
raw 45 45 45

やっていること

Docker for Machyperkitを使い、macOS上でLinuxを動かし、その上でDockerを動かしている。

hyperkitはrawフォーマットのイメージに対応しているので、Docker for Macが起動する際にhyperkitに渡す引数を変更することで、ディスクイメージをqcow2からrawに差し替えている。

ただ起動時に渡す引数を設定で変更することができないので、hyperkitのバイナリをシェルスクリプトに差し替えて、無理矢理変更している。

*1:実行したコマンド等は https://github.com/mzp/docker.img に書いた

ぺろぺろ - Github pull request bot framework -

名古屋Ruby会議03で発表した。

発表資料

関連記事

原稿

導入

自己紹介

f:id:mzp:20170305002426p:plain

こんにちは、mzpです。

大須はたまにくるので、この大須演芸場も気になってはいたんですが、なかなか入る機会がありませんでした。 まさかこっち側に立つのが最初だとは思っていませんでした。

よろしくお願いします。

会社紹介

f:id:mzp:20170305002429p:plain

仕事では、Misocaという会社でMisocaというWebサービスを作っています。この名古屋Ruby会議のスポンサーでもあるそうです。すごいですね。

Github

f:id:mzp:20170305002445p:plain

会社としてのMisocaはおいといて、サービスとしてのMisocaはGithubのプライベートレポジトリ上で開発を進めています。そのためGithubが開発の中心になります。

プルリクエスト

f:id:mzp:20170305002501p:plain

さらに言えばプルリクエストが中心になります。そのためプルリクエストにまつわるさまざまなルールや運用が生まれます。例えば「コンフリクトに気付いたら声をかけてあげようね」ですとか「githubでコメントしたらSlackでも教えてあげよう」などなどなどです。
 最初はこれでもよいのですが、だんだんと面倒になっていきますよね。

bot

f:id:mzp:20170305002521p:plain

そこでbotを作り、こういった運用を自動化しました。

このbotは機能を固定したものでなく、gemによって拡張できるbot frameworkとして作りました。 今日はそのbot frameworkを紹介したいと思います。

使い方

まずは簡単に使い方を話します。

Deploy to heroku

f:id:mzp:20170305002603p:plain

レポジトリに deploy to herokuボタンがあるので、押せばherokuにデプロイできます。

Webhookの設定

f:id:mzp:20170305002431p:plain

あとはGithubでWebhookの設定をすれば動きます。

カスタマイズ

f:id:mzp:20170305002438p:plain

デプロイされたgitレポジトリをcloneしてきてGemfileを更新すれば挙動を拡張できます。 例えば、コンフリクトしているプルリクエストにラベルを自動でつけるようにしたい場合は、Gemfileに gem ‘prpr-conflict_label’ と追記してpushすればOKです。

既存プラグインの紹介

次は各gemでできることを紹介していきます。

prpr-checklist

f:id:mzp:20170305002503p:plain

各プルリクエストに自動でチェックリストを投稿するgemです。

機能を更新したけどヘルプを更新するのを忘れた、とか、バリデーションルールを追加したら既存データと矛盾するようになってしまった、みたいな単純な失敗をしてしまうことありますよね。 そういうときは古来よりチェックリストを使うとよいと言われているので、それです。

チェックリストの内容

f:id:mzp:20170305002524p:plain

チェックリストの内容は、レポジトリ上にあるCHECKLIST.mdという名前のファイルを使うようにしているので、変更も容易ですし、バージョン管理もできます。

余談: これを作ったときにはなかったんですが、今のGithubにはプルリクエスト テンプレートがあるので、そっちつかってもいいかもしれませんね。

prpr-mention_comment

f:id:mzp:20170305002549p:plain

コメント中に「@xxx 」といった文字列が含まれていた場合は、そのままSlackに転送するgemです。

Githubの通知をSlackに流している方も多いと思うんですが、GithubコメントでメンションしてもSlackではメンションにはならないんですよね。 これだとなかなか気づけませんし、気付いてもらえません。

Slackの通知は気付いてくれる人が多いので、これで解決です。

アカウント名の対応

f:id:mzp:20170305002606p:plain

工夫ポイントとしては、Slackのユーザ名とGithubのユーザ名が違う人もいるので、ユーザ名の変換もやっていることです。 これはレポジトリのルートに以下のようなファイルを置くことでカスタマイズできるようになっています。

prpr-gemfile

f:id:mzp:20170305002440p:plain

gemGemfile.lockのdiffを確認して、メジャーバージョンアップとマイナーバージョンアップをしている箇所にコメントをいれるgemです。

定期的にbundle updateをしてプルリクエストを送るbotを飼っているんですが、毎回Gemfile.lockの差分を見ながら「ふむふむこれはbugfixだけだし、いれていいでしょ」「う、こっちはメジャーバージョンがあがってる。ちゃんと調べなきゃ」というのをやるのは面倒なので自動化しています。

prpr-conflict_label

f:id:mzp:20170305002443p:plain

何本もプルリクエストが並行して動いてる状況だと、ちょいちょいコンフリクトが発生します。ただ、Githubのプルリクエスト一覧ではどれがコンフリクトしているかがわからず、個別のプルリクエスト画面をひらいて初めてコンフリクトしていることがわかります。

マージイベントが発生するたびに全プルリクエストを確認し、コンフリクトラベルのつけはずしをするようにしましたgemです。

これで一覧をみるだけでどれがコンフリクトしているかが分かるようになります。

まとめ

f:id:mzp:20170305002450p:plain

以上が、標準的なprprのgemです。 たぶんだいたいのシチュエーションで便利だと思います。 ボクも自分のプライベートプロジェクトで使っていたりします。

Misoca開発フローとの統合

これらとは別にMisocaでの開発フローにあわせて作ったgemもあります。 次はこういったgemについて紹介していきたいと思います。

開発フロー

f:id:mzp:20170305002526p:plain

まずは、我々の開発スタイルについて簡単に説明します。

  1. 各開発者がプルリクエストを作る。このときはまだWIP(work in progress; 作業中)というラベルをつけておき、まだレビューしなくてもいいよ、ということを明示します。
  2. プルリクエストが完成したら、レビューを依頼する。 指摘がついたら対応する。
  3. 最低1人、できれば2人がOKを出したあとでマージする。
  4. いくつかマージされたプルリクエストがたまってきたらデプロイする。

その他の特徴

f:id:mzp:20170305002553p:plain

補足情報としては、

  • レビュー担当者などは特に固定せず、互いにプルリクエストレビューを行なう
  • 基本的にはSlackを使ってやりとりする

といった特徴もあります。

prpr-review_label

f:id:mzp:20170305002608p:plain

レビュー依頼部分を支援するgemです。 このgemはREVIEWというラベルがついた場合は、Slackに「レビュー待ちにしました」という通知を流します。

この通知にはラベルをつけた人の名前とアイコンを使うようにしているので、誰が依頼をしたかがすぐ分かるようになっています。

prpr-lgtm

f:id:mzp:20170305002452p:plain

次は「マージする」という部分を支援するgemです。最初は雰囲気でやっていたのですが、

  • プルリクエスト一覧では何人がOKをだしたかがわからない
  • プルリクエストを出した人が、二人にOKされたことに気づくのに時間がかかる
 という問題がありました。

そこで、 * OKの数をラベルとして表現する * 二人がOKをした場合は、プルリクエストにassignされている人にメンションを飛ばす というbotを作りました。

一覧をみるだけで何人がOKをだしているかがわかる、二人がOKを出いた瞬間に気づけるようになり、テンポよくマージしていけるようになりました。

自己

f:id:mzp:20170305002455p:plain

余談ですが、このgemを作る過程でうっかり暴走させてしまい、同僚に大量のメンションを飛してしまい、たいへん申し分けない感じになりました。ごめん。 これは自分のコメントに反応してさらにコメントをつけてしまい、それに反応して…という図です。

prpr-merged

f:id:mzp:20170305002458p:plain

「マージする」という部分を支援するgemはもう一つあります。

「マージする」という行為は影響が大きいので、できるだけみんなに把握しておいてほしいです。 そのため、マージが発生するとslackに通知されるgemを作りました。

もちろんslackのgithub連携機能でも同じ情報は流れてきますが、よりマージを目立たせるという効果があります。

デプロイ

f:id:mzp:20170305002508p:plain

最後はデプロイの支援です。

Misocaのデプロイはチャット経由でできるようになっています。

  1. チャットで「@bot デプロイしたい」と発言する
  2. botがデプロイ用の内容をまとめたプルリクエストを作る。 これはマージ先がmasterではなくリリース用ブランチになっています。
  3. デプロイ用のプルリクエストをマージすると、デプロイプロセスがはじまる
  4. デプロイされる

という流れです。

このうち、3の「デプロイ用のプルリクエストをマージすると、デプロイプロセスがはじまる」の部分はprprがやっています。

prpr-code_deploy

f:id:mzp:20170305002529p:plain

Misocaのデプロイ作業はAWSのCodedeployを使っています。 codedeployにコミットIDを送ると、デプロイしてくれます。

そこで、デプロイ用のブランチにマージされた場合は、AWS codedeployにそのコミットIDを送り、デプロイプロセスがはじまるようにしています。

まとめ

f:id:mzp:20170305002555p:plain

以上がMisoca開発におけるprprの使い方です。

あとはこのprprを作ったときの話をしていきたいと思います。

先行事例

作るときに参考ににしたものや、あとから見つけたやつなどがあるのでそれを紹介します。

クックパッド

f:id:mzp:20170305002511p:plain

チェックリストの投稿などはクックパッド開発ブログで紹介されています。 ただこれは自分たちで作っていこうな、という趣旨の記事なので、汎用のbotがあるわけではありません。

trailing space bot

f:id:mzp:20170305002513p:plain

Github上で動作するbotというのもいくつかあります。 たとえば、末尾のスペース(trainling space)を検知して修正するプルリクエストを作成するbotもいます。

これはそいつが送ってくるプルリクエストです。

しかしこれは挙動が固定されているため自分たちにあわせて機能を追加・削除していくのは困難です。

拡張可能なbot

f:id:mzp:20170305002516p:plain

プラグインで挙動を拡張できるbotは多数存在しており、開発関係だとhubotやrubotyなどが有名な気がします。

ただこれはチャット経由でなにかする、というものがほとんどで、プルリクエストに反応して何かをするものは見付けれませんでした。

設計

目標

f:id:mzp:20170305002531p:plain

自由に拡張できるgithubbotフレームワークはないことがわかったので、自分で作ることにしました。 作成時に標榜した目標は以下の通りです。

gemにより挙動を拡張できる。 コア部分と、自分たちの開発を便利にするための機能を切り離す。

botの設定変更は誰でもできるようにする。 これは先ほど紹介したチェックリスト投稿が分かりやすいと思うんですが、チェックリストの内容変更は管理者だけができる、ということになると、チェックリストへの追加作業のハードルがあがってしまいます。そこで、レポジトリ上のファイルが設定ファイルになるようにし、レポジトリにコッミトできる人間なら誰でも設定変更できるようにしました。 設定変更もgitで履歴管理されるようになるのもメリットです。

herokuで動く。 自分でちゃんとデプロイするの大変ですしね。

すばやく作る。 とりあえず日々の運用を楽にするのが先決なので、わりとさっさと作りたかったです。

構成

f:id:mzp:20170305002558p:plain

構成としては以下のようになっています。

  • どのイベントに反応するかを決めるHandler
  • 挙動を決めるAction
  • 環境変数やレポジトリ上のファイルから設定を読み込むsettings
  • Slack等に通知するpublisher

といった部分で構成されています。 またイベントを受け取る部分は通常のwebhookの他にテスト用のCLIもあります。

プラグインがやるのがhandler/actionあたりです。

例: Handler

f:id:mzp:20170305002613p:plain

マージ通知をするgemを例に、もうちょっとだけ具体的に説明します。

マージだけに反応するればいいので、handlerは以下のようになっておりプルリクエストのcloseに反応するようになっています。

例: Action(½)

f:id:mzp:20170305002533p:plain

Actionはこのようになっております。

  • 本当にマージされたかどうかの判定
  • publisher経由で通知する

例: Action(2/2)

f:id:mzp:20170305002536p:plain

送信するメッセージは、このように環境変数から読むようになっています。

やらなかったこと

f:id:mzp:20170305002538p:plain

prprは最初のバージョンを早めに出して、プルリクエストにまつわる運用を楽にしたかったので、割り切って作った部分もいくつかあります。

WebUIを作らない。 設定画面等をつけようかとも思ったんですが、認証とかを考えると面倒そうだったのと、Webhook受け取るだけでとりあえず動くだろ、ということでWebUIをつけるのはやめました。

Bitbucketのことは忘れる。 最初はGithubとbitbucketの両対応をしようかと思ったんですが、抽象レイヤーを作るのが面倒そうだったのと、bitbucketを使う予定がないので忘れることにしました。

命名

f:id:mzp:20170305002540p:plain

次は名前の話ですね。

コードを書きはじめる前に名前を決める派なので、けっこう初期からこの名前でした。 プルリクエスト=PRに反応するbotつくりたいけどなにがいいかなー?って相談しました。 よくみると夜中の12時くらいに決めてるので、まあそういうことだよなって気持ちになりました。

ヲタクっぽくて気にいっています。

よかったところ

f:id:mzp:20170305002544p:plain

あとは感想です。

  • gem化したのでどこでからがプラグインかが明確になって、クラス設計等がしやくなった
  • CLIでテストできるようにしたのでデバッグが楽
  • 外部のAPIを叩く部分をすべてプラグインにしたので、本体のspecでモックを作るのが簡単だった。

苦労したところ

f:id:mzp:20170305002601p:plain

  • githubの新機能(Approve/Project/…)などの機能がなかなかAPIにおりてこない。 ReviewのApproveのAPIがくるまで一ヶ月ほど待ちました。
  • PreviewAPIはoctokitにはいってこないので、わりと無理矢理呼ぶことになる。 こんな感じです。
  • gemに分割したのでgemspecを書いたり、レポジトリを大量に作るのが面倒だった。

まとめ

f:id:mzp:20170305002615p:plain

まとめます。

  • プルリクエストに関する運用を自動化するためのbotフレームワークを作った
  • Misocaの開発フローにあわせるためのgemがいくつかある
  • 拡張しやすいようにいくつかのコンポーネントにわけて設計している。

今朝書いたシェルスクリプト

こんなシェルスクリプトをいくつか書いてレポジトリにコミットした。

./bin/docker/bundle

#!/bin/sh
docker-compose run --rm app bundle "$@"

./bin/docker/rails

#!/bin/sh
docker-compose run --rm app bundle exec rails "$@"

できること

./bin/docker/bundle install

とか

./bin/docker/rails db:migrate

とかができるようになって便利。

今までは docker-compose run app bash してその中で実行していたが、履歴が残らず不便だったのが解消された。 docker-compose run app .... を毎回打ってもいいんだけど、長くてダルい。

全部

https://github.com/mzp/fumifumi/tree/master/bin/docker

⛄️飛騨・高山旅行

雪と合唱造りの組合せが見たかったので行ってきた。

f:id:mzp:20170123091615j:plain

道中

向う途中でひるがの高原に寄ったが、冗談みたいな量の雪が積もっていた。

f:id:mzp:20170121142443j:plain

f:id:mzp:20170121142454j:plain

古い町並み(昼)

高山市内の古い町並みは予想通りいい感じだった。

f:id:mzp:20170123103446j:plain f:id:mzp:20170121170412j:plain

謎の器具で雪を落している。 f:id:mzp:20170122100354j:plain

寿司はうまい。

f:id:mzp:20170121165334j:plain

団子もうまい。

f:id:mzp:20170121165756j:plain

牛串も当然うまい。

f:id:mzp:20170122100242j:plain

古い町並み(夜)

夜になるとさらにいい感じになる。

f:id:mzp:20170121172100j:plain

f:id:mzp:20170121171948j:plain

⛄️

f:id:mzp:20170121191650j:plain

ものすごく寒いのでうっかりラーメンを食べる。めっちゃうまい。

f:id:mzp:20170121182238j:plain

合掌造り

本当は白川郷に行くつもりが雪が怖くて断念した。かわりに、高山駅近くの飛騨の里に行った。

立ち入り禁止の札が埋まってて迫力がある。

f:id:mzp:20170122163420j:plain

日が落ちるとライトアップがはじまる。

f:id:mzp:20170122173044j:plain

f:id:mzp:20170122174419j:plain

f:id:mzp:20170122172401j:plain

f:id:mzp:20170122174859j:plain

めちゃくちゃ寒いので火に集まる。

f:id:mzp:20170122172428j:plain

氷菓 舞台巡り

氷菓の舞台巡りをしたが「劇中だとこんなに雪が降ってなかったよな?」という疑問がついて回った。

いろいろな箇所に貼ってあったポスター。

f:id:mzp:20170121160533j:plain

図書館。

f:id:mzp:20170121162558j:plain

劇中で二人で閉じ込められていた神社。ここに放置されたら死ぬのでは?

f:id:mzp:20170123125321j:plain

君の名は 舞台巡り

君の名はの舞台になった飛騨古川も見てきた。

アピールしている。

f:id:mzp:20170122133422j:plain

「君の名はを見て来ました」と言ったら、伝票に書かれた。

f:id:mzp:20170122141642j:plain

近くの美術館で君の名は展をやっていたので見てきた。

f:id:mzp:20170122144618j:plain

等身大パネルより背景の雪の量が気になる。

f:id:mzp:20170122144807j:plain

感想

  • 雪が大量にあってたのしい
  • 寒い。痛いくらい寒い。
  • 日がたつにつれどんどん体調が悪化していき、帰ってきてから風邪を引いた

🙆prpr-lgtm

会社ではPull Requestに対して2人がApproveしたのちにマージするという運用をしているので、これを補助するbotを作った。 2人がApproveしたときに、Assigneeに対してメンションが飛ばす。

f:id:mzp:20170103092252j:plain

bot

prprへのプラグインとして実装した: https://github.com/mzp/prpr-lgtm

解決したい問題

Pull Requestに対して2人がApproveしたのちにマージするという運用には以下の2つの問題点があった。

  • Approveした人数がPullRequest一覧では分からない。
  • Approveした人数が2人に達したことに担当者が気付きづらい。

prpr-lgtm

ラベルによるApprove件数の表示

Approveの件数にあわせてラベルの追加・削除を行なう。

  • LGTM:1: 1人がApproveしている
  • LGTM:2+: 1人以上がApproveしている

f:id:mzp:20170103093644p:plain

メンション

2人がApproveしたときに、Assigneeに対してメンションが飛ばす。 このとき本文にしている「Let's Get This Merged」は Rebuild: Aftershow 133: Let's Get This Merged (gfx) が由来。

f:id:mzp:20170103092252j:plain

余談

Pull Request Review CommentのAPIがでるまでは「LGTM」というコメントに反応するようにしていた。 そのせいで「LGTMではないです」といったコメントにも反応してちょっと大変だった。

また、開発中には自分のコメントにも反応して、だいぶ面倒なことになった。