如何在Python中接收Github Webhooks

40
Github提供Post-receive hooks功能,可以在您的存储库上发生活动时将其发送到您选择的URL。我想编写一个小型的Python命令行/后台(即无GUI或Web应用程序)应用程序,在我的计算机(稍后在NAS上)上持续侦听这些传入的POST请求,一旦从Github接收到POST,则处理其中包含的JSON信息。只要我有JSON,就没有问题处理它。
POST可以来自Github给出的少量IP地址;我计划/希望指定我的计算机上应该发送的端口。
问题是,我对Web技术了解不够,无法处理搜索时找到的众多选项...我是否使用Django、Requests、sockets、Flask、微框架等?我不知道大多数涉及的术语是什么意思,大多数听起来提供了太多/太大的解决方案,我感到不知所措,不知道从哪里开始。
我能找到的大多数关于POST/GET的教程似乎都关注于发送或直接请求网站数据,而不是持续侦听它。

我觉得这个问题并不是很难,一旦我知道该去哪里/如何做,它就会简化成几行代码。有人可以提供指针/教程/示例代码吗?


1
web.py 是我开始的地方。 - ford
4
问题在于,我不想/不需要提供网页服务。 - Christoph
然后使用纯werkzeug(这是flask用作其后端的内容)。 - Ian Stapleton Cordasco
我自己在做这件事。我可能会使用Tornado来完成它,主要是因为需要监听的系统上已经安装了Tornado。任何微型HTTP服务器框架都可以。我的一个朋友很喜欢webobj - pcurry
我该如何从Bash获取这个POST数据? - winn j
5个回答

45

首先,网络是基于请求-响应的。因此,会有某些东西请求您的链接,然后您将作出相应的回应。您的服务器应用程序将持续侦听一个端口;这是您不必担心的。

以下是我选择的微框架Flask中的类似版本:

from flask import Flask, request
import json

app = Flask(__name__)

@app.route('/',methods=['POST'])
def foo():
   data = json.loads(request.data)
   print "New commit by: {}".format(data['commits'][0]['author']['name'])
   return "OK"

if __name__ == '__main__':
   app.run()

以下是使用github示例进行的样本运行:

运行服务器(以上代码保存在sample.py中):

burhan@lenux:~$ python sample.py 
 * Running on http://127.0.0.1:5000/

这里是对服务器的请求,基本上就是github要做的事情:

burhan@lenux:~$ http POST http://127.0.0.1:5000 < sample.json
HTTP/1.0 200 OK
Content-Length: 2
Content-Type: text/html; charset=utf-8
Date: Sun, 27 Jan 2013 19:07:56 GMT
Server: Werkzeug/0.8.3 Python/2.7.3

OK # <-- this is the response the client gets

这是服务器上的输出:

New commit by: Chris Wanstrath
127.0.0.1 - - [27/Jan/2013 22:07:56] "POST / HTTP/1.1" 200 -

我认为 Github 示例的链接不正确。 - BoltzmannBrain
写作时是正确的(三年以上前)。 - Burhan Khalid

26

以下是一个接收通过POST提交的数据并对其进行操作(在本例中,只是将其打印到标准输出)的基本web.py示例:

import web

urls = ('/.*', 'hooks')

app = web.application(urls, globals())

class hooks:
    def POST(self):
        data = web.data()
        print
        print 'DATA RECEIVED:'
        print data
        print
        return 'OK'

if __name__ == '__main__':
    app.run()

我使用 hurl.it 将一些数据POST到它上面(在我的路由器上转发8080端口),并看到了以下输出:

$ python hooks.py 
http://0.0.0.0:8080/

DATA RECEIVED: 
test=thisisatest&test2=25

50.19.170.198:33407 - - [27/Jan/2013 10:18:37] "HTTP/1.1 POST /hooks" - 200 OK
你应该能够用你的JSON处理替换掉打印语句。
为了指定端口号,请使用额外参数调用脚本:
$ python hooks.py 1234 

4
好的,我接受了这个答案,因为这是我尝试的第一个答案,并且对于第一次实现来说可以令人满意。以后我可能会按照问题评论中建议的使用普通的Werkzeug进行替换。 - Christoph
我对Webhooks和Python都很陌生,我想知道,我是否需要使用Webhook提供者给出的URL,这些URL是否与普通API不同?在托管此应用程序后,持续监听的调用机制是什么? - Khushi4.net

2
我会使用: https://github.com/carlos-jenkins/python-github-webhooks 您可以配置一个Web服务器来使用它,或者如果您只需要在那里运行一个进程而没有Web服务器,您可以启动集成的服务器:
python webhooks.py

这将使您能够完成您所需要的所有操作。但是,这需要在您的存储库和钩子中进行一些设置。
晚来了一步,有些自我推销,抱歉。

我正在尝试使用这个例子部署一个测试github提交的Web应用程序,具体来说是为了运行Bamboo构建计划并报告状态。有什么建议或意见吗?非常感谢您能提供的任何帮助。 - BoltzmannBrain
2
如果我们在这里推广自己的东西,这是我的 GitHub -> 木偶适配器,它使用 AWS Lambda。我还想出了如何处理 HMAC 标头的方法 https://github.com/vorsprung/github-to-aws-puppet-webhook - Vorsprung

1
如果您正在使用Flask,这是一个非常简洁的代码来监听Webhooks:
from flask import Flask, request, Response

app = Flask(__name__)

@app.route('/webhook', methods=['POST'])
def respond():
    print(request.json) # Handle webhook request here
    return Response(status=200)

同样的示例使用Django的方式如下:

from django.http import HttpResponse
from django.views.decorators.http import require_POST

@require_POST
def example(request):
    print(request.json) # Handle webhook request here
    return HttpResponse('Hello, world. This is the webhook response.')

如果需要更多信息,这里有一份关于如何使用Python监听Webhooks的绝佳教程:how to listen for webhooks with Python

0

如果您想要监视任何存储库的更改...

1. 如果您拥有要监视的存储库

  • 在您的存储库页面,转到设置
  • 单击网络钩子,新建网络钩子(右上角)
  • 提供您的 IP/端点并根据您的喜好设置所有内容
  • 使用任何服务器来获取通知

2. 不是您的存储库

response = requests.get("https://github.com/fire17/gd-xo/commits/master.atom").text
response.split("<updated>")[1].split("</updated>")[0]
'2021-08-06T19:01:53Z'
创建一个循环,定期检查此项,如果该字符串已更改,则可以启动克隆/拉取请求或执行任何您喜欢的操作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接