pythonで毎週レビュワーのローテーションを通知するslack botを作成した
概要
自分が参加しているプロジェクトでは,みんなができるだけコード全体をキャッチアップできるように, PRの内容に詳しい人に加えて,ローテーションで1人レビュワーを追加するようにしています. 毎週どの人のPRをどの人がみるかを変えていたのですが,今どの組み合わせかをいちいち覚えておくのが面倒なので, 毎週自動でslackに通知してくれるbotを作成しました.こちらはその際の備忘録となります.
開発環境
- MacOS Catalina - python 3.8.7 - crontier==1.0.6 - python-crontab==2.5.1 - slacker==0.14.0 - heroku
slack botはslacker
で作成し,
特定の時刻に処理を行うためにpython-crontab
を用いてタスクのスケジューリングをしています.
ディレクトリ構造
以下のようなディレクトリ構造を想定しています.
(GitHubのレポジトリにコードを上げるため,.gitignore
を追加しています.)
. ├─ .gitignore ├─ Procfile ├─ README.md ├─ requirements.txt ├─ run.py ├─ runtime.txt ├─ send_rotation.py └─ setting.py
slack botの作成
API Tokenの取得
https://my.slack.com/services/new/botから,slack botを作成します.
botを作成したら,API tokenをコピーし,setting.py
に記述します.
API_TOKEN = "xxxxx" # コピーしたAPI token CHANNEL = "#general" # botに投稿させたいチャンネルの名前
CHANNEL
には投稿したいチャンネル名を記入します.
slacker
を用いて今週のローテーションを投稿するbotの作成(send_rotation.py
)
このファイルの流れは以下です.
本日のISO準拠の週番号を取得 -> get_rotation
でその週のレビュワーローテーションを取得 -> その結果を整形してslackへ投稿
from datetime import datetime from slacker import Slacker from setting import API_TOKEN, CHANNEL NAME2GITHUB = { "Aさん": "githubA", "Bさん": "githubB", "Cさん": "githubC", "Dさん": "githubD", "Eさん": "githubE", "Fさん": "githubF", } MEMBER_LIST = [k for k in NAME2GITHUB.keys()] def get_rotation(nth_week): n_members = len(MEMBER_LIST) res = {} for i, m in enumerate(MEMBER_LIST): reviwer_idx = (i + 1 + (nth_week - 1) % (n_members - 1)) % n_members reviwer_name = MEMBER_LIST[reviwer_idx] res[m] = f"{reviwer_name} ({NAME2GITHUB[reviwer_name]})" return res def send_rotation(): today = datetime.now() _, nth_week, _ = today.isocalendar() res = get_rotation(nth_week) message = "今週のreviewer対応表\nYou\t-\tReviewer\n" for k, v in res.items(): message += f"{k:<3}\t-\t{v}\n" slack = Slacker(API_TOKEN) slack.chat.post_message(CHANNEL, message, as_user=True) if __name__ == "__main__": send_rotation()
まず,datetime
というライブラリを用いて,ISO準拠の週番号を取得します.
today = datetime.now() _, nth_week, _ = today.isocalendar()
次にget_rotation
という関数で,指定された週で,誰が誰のレビューを見るのかを辞書型で取得しています.(keyがPRを作成する人で,valueがそのレビューをする人)
具体的にはISO準拠の週番号nth_weekから,自分が何個先の人にレビューしてもらうかを計算しています.<br>
例えば,Aさん(0番目の人)は,週番号2週目に
(0 + 1 + (2 - 1) % 5) % 5 = 2`で,Cさん(2番目)の人にレビューをしてもらいます.
つまり自分から見て2個先の人のレビューをしてもらうことになります.
これは他の人でも同様で,例えばBさん(1番目の人)は,2つ先のDさん(3番目の人)にレビューを行ってもらうようになっています.
このように週番号から,それぞれの人が何個先に人に見てもらうかを計算し,その結果を返す関数になっています.
for i, m in enumerate(MEMBER_LIST): reviwer_idx = (i + 1 + (nth_week - 1) % (n_members - 1)) % n_members reviwer_name = MEMBER_LIST[reviwer_idx]
最後に,get_rotation
で得られた結果を,stringに変形し,slacker
を用いてメッセージを送っています.
message = "今週のreviewer対応表\nYou\t-\tReviewer\n" for k, v in res.items(): message += f"{k}\t-\t{v}\n" slack = Slacker(API_TOKEN) slack.chat.post_message(CHANNEL, message, as_user=True)
試しに,作成したbotをチャンネルに招待して,python send_rotation.py
を実行してみると,メッセージが送信されることが確認できるかと思います.
定期的にslackにメッセージを送る
ここまででslackのチャンネルにレビュワーの対応を送ることができました.
しかし,現状ではpython send_rotation.py
を実行した時にメッセージを送信するだけで,
定期的な通知はしてくれません.
そこで,今回はpython-crontabというライブラリを用いて,タスクスケジューリングを行いました.
実装にあたって,以下の実装を参考にさせていただきました.詳しい説明はこちらを参照していただけたらと思います.
run.py
を以下のようにします.
注意点としては,herokuサーバー内の時刻がPSTになっているため,
sheduleを指定する際には,PSTで記述する必要があります.
from crontab import CronTab class CrontabControl(object): """ Reference: https://miyabikno-jobs.com/slack-regularly-weather/ """ def __init__(self): self.cron = CronTab() self.job = None self.all_job = None # write jobs to file def write_job(self, command, schedule, file_name): self.job = self.cron.new(command=command) self.job.setall(schedule) self.cron.write(file_name) # read all jobs from file def read_jobs(self, file_name): self.all_job = CronTab(tabfile=file_name) # monitoring job def monitor_start(self, file): self.read_jobs(file) for result in self.all_job.run_scheduler(): continue def main(): command = "python3 send_rotation.py" # 3 p.m. every Sunday (PST) -> 8 a.m. every Monday (JST) schedule = "* 15 * * 0" output_file = "output.tab" c = CrontabControl() c.write_job(command, schedule, output_file) c.monitor_start(output_file) if __name__ == "__main__": main()
GitHubへpush
ここまで完成したら,あとは他の設定ファイルを追加して,GitHubへpushします.
.gitignore
__pycache__ .DS_Store output.tab
Procfile
... herokuの設定ファイル.実行するコマンドを指定. Procfile | Heroku Dev Center
pbot: python run.py
requirements.txt
... 必要なパッケージを記述するファイル
croniter==1.0.6 python-crontab==2.5.1 slackbot==1.0.0 slacker==0.14.0
runtime.txt
... herokuでpythonのバージョンを指定するファイル
python-3.8.7
上記のファイルを作成し,GitHubに適当なレポジトリを作成して,これまでの内容をpushします.
git init git add . git commit -m "first commit" git branch -M main # 自分のレポジトリのURLに変更してください git remote add origin https://github.com/XXXXXX/XXXXXX git push -u origin main
herokuでデプロイ
herokuにログイン(アカウントを持っていない場合は作成)し, https://dashboard.heroku.com/apps から新しいアプリを作成します. 作成したアプリから,Deploy -> Deployment methodでGitHubを選択し, 先ほど作成したレポジトリと接続します. こんな感じで接続されればオーケーです.
そのページの下のManual Deployから,mainブランチを選択して,Deploy Branchを実行します.
最後にOverviewから,pbot python run.py
をオンにすれば完了です!
まとめ
slacker
とpython-crontab
,herokuを用いて,簡単にslack botを作成することができました.
このような定期配信ではなく,特定のキーワードに反応するようなbotを作成したい場合は,pythonのslackbot
というライブラリを使うと簡単にできるみたいです.