From 5ade49f56ca8b51a742680cd4436f0cd80c4443a Mon Sep 17 00:00:00 2001 From: Alexandre Terrasa Date: Thu, 22 Jan 2015 12:03:07 +0100 Subject: [PATCH] lib/github: uses nitcorn to listen Github hook events. Signed-off-by: Alexandre Terrasa --- lib/github/hooks.nit | 150 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 lib/github/hooks.nit diff --git a/lib/github/hooks.nit b/lib/github/hooks.nit new file mode 100644 index 0000000..351042b --- /dev/null +++ b/lib/github/hooks.nit @@ -0,0 +1,150 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Github hook event listening with `nitcorn`. +# +# Usage: +# +# ~~~ +# import github::hooks +# +# # A simple hook listener that print received events in stdout. +# class LogHookListener +# super HookListener +# +# # Use double dispatch to implement log behavior. +# redef fun apply_event(event) do event.log_event(self) +# end +# +# redef class GithubEvent +# # Log this event. +# # +# # Do nothing by default. +# fun log_event(l: LogHookListener) do end +# end +# +# redef class CommitCommentEvent +# +# redef fun log_event(l) do +# print "new comment on commit {comment.commit.sha}" +# end +# end +# +# var api = new GithubAPI(get_github_oauth) +# var listener = new LogHookListener(api, "127.0.0.1", 8080) +# # listener.listen # uncomment to start listening +# ~~~ +module hooks + +import events +import nitcorn + +# A nitcorn listener for Github hooks. +class HookListener + + # Api client used to perform Github API requests. + var api: GithubAPI + + # Host to listen. + var host: String + + # Port to listen. + var port: Int + + # VirtualHost listened + private var vh: VirtualHost is noinit + + init do + vh = new VirtualHost("{host}:{port}") + vh.routes.add new Route("/", new HookAction(self)) + end + + # Verbosity level (0: quiet, 1: debug). + # Default: 0 + var verbosity = 0 + + # Print `message` if `lvl` <= `verbosity` + fun message(lvl: Int, message: String) do + if lvl <= verbosity then print message + end + + # Start listening and responding to event. + fun listen do + message(1, "Hook listening on {host}:{port}") + var factory = new HttpFactory.and_libevent + factory.config.virtual_hosts.add vh + factory.run + end + + # How to build events from received json objects. + fun event_factory(kind: String, json: JsonObject): GithubEvent do + if kind == "commit_comment" then + return new CommitCommentEvent.from_json(api, json) + else if kind == "create" then + return new CreateEvent.from_json(api, json) + else if kind == "delete" then + return new DeleteEvent.from_json(api, json) + else if kind == "deployment" then + return new DeploymentEvent.from_json(api, json) + else if kind == "deployment_status" then + return new DeploymentStatusEvent.from_json(api, json) + else if kind == "fork" then + return new ForkEvent.from_json(api, json) + else if kind == "issues" then + return new IssuesEvent.from_json(api, json) + else if kind == "issue_comment" then + return new IssueCommentEvent.from_json(api, json) + else if kind == "member" then + return new MemberEvent.from_json(api, json) + else if kind == "pull_request" then + return new PullRequestEvent.from_json(api, json) + else if kind == "pull_request_review_comment" then + return new PullRequestReviewCommentEvent.from_json(api, json) + else if kind == "push" then + return new PushEvent.from_json(api, json) + else if kind == "status" then + return new StatusEvent.from_json(api, json) + else + return new GithubEvent.from_json(api, json) + end + end + + # What to do when we receive an event from a hook? + fun apply_event(event: GithubEvent) is abstract +end + +# A nitcorn action dedicated to GitHub hook listening. +private class HookAction + super Action + + # Listener that contains this action. + # + # The `listener` is used for its `event_factory` method + # and the `apply_event`. + var listener: HookListener + + # Parse hook request then call `listener.apply_event`. + redef fun answer(request, uri) do + # get event type + var kind = request.header.get_or_null("X-GitHub-Event") + if kind == null then return new HttpResponse(403) + # get POST object + var obj = request.body.parse_json + if not obj isa JsonObject then return new HttpResponse(403) + # parse event + var event = listener.event_factory(kind, obj) + listener.apply_event(event) + return new HttpResponse(200) + end +end -- 1.7.9.5