はじめに
研究室の先輩から次のようなお願いをされました。
「このリポジトリに新しいcommitがあったらslackに通知するようにして欲しい」と。
slackにはGitHubのアプリがあるので、簡単だろうと思っていましたが、
それには、GitHubのアカウントとslackのアカウントを連携させる必要があります。
がしかし、先輩が指定したのは赤の他人のリポジトリでした・・・。
つまり、アカウントの連携が出来ないっ!!!
着目した点
以下のようなURLに行くと、今までのcommitの履歴を確認することが出来ます。
https://github.com/ユーザーネーム/リポジトリネーム/commits/master
例えばこんな感じのページ
新しくcommitがあった場合はここのページが変わります。
これを利用すれば、うまくいきそうです。
例のページのHTMLを見てみると、次のようになっていました(長いので一部だけを切り取っています)。
~
<title>Recent Commits to googletest:master</title>
<updated>2018-07-27T19:15:11Z</updated>
<entry>
<id>tag:github.com,2008:Grit::Commit/00486476193b0c23334592749db3a77df7d1db40</id>
<link type="text/html" rel="alternate" href="https://github.com/google/googletest/commit/00486476193b0c23334592749db3a77df7d1db40"/>
<title>
Merge pull request #1688 from gennadiycivil/master
</title>
<updated>2018-07-27T19:15:11Z</updated>
<media:thumbnail height="30" width="30" url="https://avatars1.githubusercontent.com/u/12735026?s=30&v=4"/>
<author>
<name>gennadiycivil</name>
<uri>https://github.com/gennadiycivil</uri>
</author>
<content type="html">
<pre style='white-space:pre-wrap;width:81ex'>Merge pull request #1688 from gennadiycivil/master
Formatting changes for automatic code management</pre>
~
<title>
ので囲まれた部分がcommitのタイトルになっています。
これを使っていきたいと思います。
解決法
- commitの履歴が表示されてるページのHTMLを取得
- commitのタイトルだけを取得して、リストに格納
- 以前にテキストファイルとして保存しておいた、commitのリストを読み込む
- 以前のリストと今回のリストの差分を調べる
- 差分があればslackに通知する
以上の流れに沿ったプログラムをpythonで組みました。
slackに通知させる方法はWebHookを使いました。参考にしたサイトはここです。
ソースコード
#coding:utf-8
#!/usr/bin/env python
import requests, bs4, os
import json
def get_commits_list(repo_name, URL):
new_commit_list = [] # 新しく取得したcommitのタイトルを格納するリスト
old_commit_list = [] # 以前に保存したcommitのタイトルを読み込んで、格納するリスト
#GitHubのページをHTML形式で取得
res = requests.get(URL)
res.raise_for_status()
soup = bs4.BeautifulSoup(res.text, "html.parser")
elems = soup.select("a") #<a>のタグで囲まれた部分を抽出
file_path = "/path/to/text.txt" # 過去に保存したcommitのタイトルを保存しているパス
f_r = open(file_path, "r") # 過去に保存したcommitのタイトルをoldリストに格納していく
for x in f_r:
old_commit_list.append(x.rstrip("\n"))
f_r.close()
for elem in elems: # 今回取得したcommitのタイトルをnewリストに格納して行く
if elem.get("title") != None: #<title>タグの有無を確認
new_commit_list.append(elem.get("title")) #commitのタイトルをnewリストに格納
else:
pass
if new_commit_list == old_commit_list: #新しいcommitがなかった場合
print "There are no new commits."
return True
else: # 新しいcommitがあった場合
print "There are some NEW commits."
# commitのリストを更新して保存
f_w = open(file_path, "w")
for i in new_commit_list:
f_w.write(str(i) + "\n")
f_w.close()
return False
def slack_notice(repo_name, URL):
web_hook = "各自で取得してください"
message = "New Commits!\n" + repo_name + " : [" + URL + "]"
requests.post(web_hook, data = json.dumps({
'text': message, # 投稿するテキスト
'username': u'Ghost', # 投稿のユーザー名
'icon_emoji': u':ghost:', # 投稿のプロフィール画像に入れる絵文字
'link_names': 1, # メンションを有効にする
}))
def main():
repo_list = {
"googletest":"https://github.com/google/googletest/commits/master",
#"リポジトリの名前":"https://github.com/ユーザ名/リポジトリ名/commits/master"
}
for i in repo_list:
res = get_commits_list(i, repo_list[i])
if res == False:
#新しいcommitの通知
slack_notice(i, repo_list[i])
if __name__ == "__main__":
main()
終わりに
シンプルな方法ですが、無事に先輩の要望を叶えられるようなプログラムを作成できました。
Herokuを使って、1時間に1回プログラムを実行するようにしています。
下の様な感じでslackに通知が届くようになりました。