Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Add a web hook handler for Google Code push notifications #291

Merged
merged 2 commits into from

2 participants

@lopter
  • Supports authentication;
  • Only supports pushes on the `default' branch (Google Code doesn't send the branch name);
  • Google Code entirely sends the changes as an UTF-8 JSON dictionary (as opposed to something like a form-data);
  • Very similar to the GitHub web hook handler.
Louis Opter and others added some commits
Louis Opter Add a web hook handler for Google Code push notifications
- Supports authentication;
- Only supports pushes on the `default' branch (Google Code doesn't send
  the branch name);
- Google Code entirely sends the changes as an UTF-8 JSON dictionary (as
  opposed to something like a form-data);
- Very similar to the GitHub web hook handler.
350a3b0
@lopter lopter Document the Google Code Web Hook handler and make the branch returne…
…d an option

- You can now choose the branch returned by the web hook handler with
  the 'branch' option;
- Also, check if a 'branch' field exists in the JSON dictionary sent by
  Google Code (in the hope that they add it one day…);
- Adjust test accordingly.
0a812c5
@djmitche djmitche merged commit 0a812c5 into buildbot:master
@djmitche
Owner

Merged - thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Dec 18, 2011
  1. Add a web hook handler for Google Code push notifications

    Louis Opter authored
    - Supports authentication;
    - Only supports pushes on the `default' branch (Google Code doesn't send
      the branch name);
    - Google Code entirely sends the changes as an UTF-8 JSON dictionary (as
      opposed to something like a form-data);
    - Very similar to the GitHub web hook handler.
  2. @lopter

    Document the Google Code Web Hook handler and make the branch returne…

    lopter authored
    …d an option
    
    - You can now choose the branch returned by the web hook handler with
      the 'branch' option;
    - Also, check if a 'branch' field exists in the JSON dictionary sent by
      Google Code (in the hope that they add it one day…);
    - Adjust test accordingly.
This page is out of date. Refresh to see the latest.
View
97 master/buildbot/status/web/hooks/googlecode.py
@@ -0,0 +1,97 @@
+# This file is part of Buildbot. Buildbot is free software: you can
+# redistribute it and/or modify it under the terms of the GNU General Public
+# License as published by the Free Software Foundation, version 2.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Copyright 2011, Louis Opter <kalessin@kalessin.fr>
+
+# Quite inspired from the github hook.
+
+import hmac
+import logging
+import sys
+import traceback
+
+from twisted.python import log
+
+from buildbot.util import json
+
+class GoogleCodeAuthFailed(Exception):
+ pass
+
+class Payload(object):
+ def __init__(self, headers, body, branch):
+ self._auth_code = headers['Google-Code-Project-Hosting-Hook-Hmac']
+ self._body = body # we need to save it if we want to authenticate it
+ self._branch = branch
+
+ payload = json.loads(body)
+ self.project = payload['project_name']
+ self.repository = payload['repository_path']
+ self.revisions = payload['revisions']
+ self.revision_count = payload['revision_count']
+
+ def authenticate(self, secret_key):
+ m = hmac.new(secret_key)
+ m.update(self._body)
+ digest = m.hexdigest()
+ return digest == self._auth_code
+
+ def changes(self):
+ changes = []
+
+ for r in self.revisions:
+ files = set()
+ files.update(r['added'], r['modified'], r['removed'])
+ changes.append(dict(
+ who=r['author'],
+ files=list(files),
+ comments=r['message'],
+ links=[r['url']],
+ revision=r['revision'],
+ when=r['timestamp'],
+ # Let's hope Google add the branch one day:
+ branch=r.get('branch', self._branch),
+ revlink=r['url'],
+ repository=self.repository,
+ project=self.project
+ ))
+
+ return changes
+
+def getChanges(request, options=None):
+ try:
+ headers = request.received_headers
+ body = request.content.getvalue()
+ #logging.error('headers = {0}, body = {1}'.format(headers, body))
+
+ # Instantiate a Payload object: this will parse the body, get the
+ # authentication code from the headers and remember the branch picked up
+ # by the user (Google Code doesn't send on which branch the changes were
+ # made)
+ payload = Payload(headers, body, options.get('branch', 'default'))
+
+ if 'secret_key' in options:
+ if not payload.authenticate(options['secret_key']):
+ raise GoogleCodeAuthFailed()
+ else:
+ log.msg('Missing secret_key in the Google Code WebHook options: cannot authenticate the request!')
+
+ log.msg('Received {0} changes from Google Code'.format(payload.revision_count))
+ changes = payload.changes()
+ except:
+ logging.error("Can't parse the Google Code WebHook:")
+ for msg in traceback.format_exception(*sys.exc_info()):
+ logging.error(msg.strip())
+ # return something valid even if everything goes wrong:
+ changes = []
+
+ return changes, 'Google Code'
View
90 master/buildbot/test/unit/test_status_web_change_hooks_googlecode.py
@@ -0,0 +1,90 @@
+# This file is part of Buildbot. Buildbot is free software: you can
+# redistribute it and/or modify it under the terms of the GNU General Public
+# License as published by the Free Software Foundation, version 2.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Copyright 2011 Louis Opter <kalessin@kalessin.fr>
+#
+# Written from the github change hook unit test
+
+import StringIO
+
+import buildbot.status.web.change_hook as change_hook
+from buildbot.test.fake.web import MockRequest
+
+from twisted.trial import unittest
+from twisted.internet import defer
+
+# Sample Google Code commit payload extracted from a Google Code test project
+# {
+# "repository_path": "https://code.google.com/p/webhook-test/",
+# "project_name": "webhook-test",
+# "revision_count": 1,
+# "revisions": [
+# {
+# "added": [],
+# "parents": ["6574485e26a09a0e743e0745374056891d6a836a"],
+# "author": "Louis Opter \\u003Clouis@lse.epitech.net\\u003E",
+# "url": "http://webhook-test.googlecode.com/hg-history/68e5df283a8e751cdbf95516b20357b2c46f93d4/",
+# "timestamp": 1324082130,
+# "message": "Print a message",
+# "path_count": 1,
+# "removed": [],
+# "modified": ["/CMakeLists.txt"],
+# "revision": "68e5df283a8e751cdbf95516b20357b2c46f93d4"
+# }
+# ]
+# }
+googleCodeJsonBody = '{"repository_path":"https://code.google.com/p/webhook-test/","project_name":"webhook-test","revisions":[{"added":[],"parents":["6574485e26a09a0e743e0745374056891d6a836a"],"author":"Louis Opter \u003Clouis@lse.epitech.net\u003E","url":"http://webhook-test.googlecode.com/hg-history/68e5df283a8e751cdbf95516b20357b2c46f93d4/","timestamp":1324082130,"message":"Print a message","path_count":1,"removed":[],"modified":["/CMakeLists.txt"],"revision":"68e5df283a8e751cdbf95516b20357b2c46f93d4"}],"revision_count":1}'
+
+class TestChangeHookConfiguredWithGoogleCodeChange(unittest.TestCase):
+ def setUp(self):
+ self.request = MockRequest()
+ # Google Code simply transmit the payload as an UTF-8 JSON body
+ self.request.content = StringIO.StringIO(googleCodeJsonBody)
+ self.request.received_headers = {
+ 'Google-Code-Project-Hosting-Hook-Hmac': '85910bf93ba5c266402d9328b0c7a856',
+ 'Content-Length': '509',
+ 'Accept-Encoding': 'gzip',
+ 'User-Agent': 'Google Code Project Hosting (+http://code.google.com/p/support/wiki/PostCommitWebHooks)',
+ 'Host': 'buildbot6-lopter.dotcloud.com:19457',
+ 'Content-Type': 'application/json; charset=UTF-8'
+ }
+
+ self.changeHook = change_hook.ChangeHookResource(dialects={
+ 'googlecode': {
+ 'secret_key': 'FSP3p-Ghdn4T0oqX',
+ 'branch': 'test'
+ }
+ })
+
+ # Test 'base' hook with attributes. We should get a json string representing
+ # a Change object as a dictionary. All values show be set.
+ def testGoogleCodeWithHgChange(self):
+ self.request.uri = "/change_hook/googlecode"
+ d = defer.maybeDeferred(lambda : self.changeHook.render_GET(self.request))
+ def check_changes(r):
+ # Only one changeset has been submitted.
+ self.assertEquals(len(self.request.addedChanges), 1)
+
+ # First changeset.
+ change = self.request.addedChanges[0]
+ self.assertEquals(change['files'], ['/CMakeLists.txt'])
+ self.assertEquals(change["repository"], "https://code.google.com/p/webhook-test/")
+ self.assertEquals(change["when"], 1324082130)
+ self.assertEquals(change["who"], "Louis Opter <louis@lse.epitech.net>")
+ self.assertEquals(change["revision"], '68e5df283a8e751cdbf95516b20357b2c46f93d4')
+ self.assertEquals(change["comments"], "Print a message")
+ self.assertEquals(change["branch"], "test")
+ self.assertEquals(change["revlink"], "http://webhook-test.googlecode.com/hg-history/68e5df283a8e751cdbf95516b20357b2c46f93d4/")
+
+ d.addCallback(check_changes)
+ return d
View
4 master/docs/manual/cfg-changesources.rst
@@ -1125,8 +1125,8 @@ Change Hooks (HTTP Notifications)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Buildbot already provides a web frontend, and that frontend can easily be used
-to receive HTTP push notifications of commits from services like GitHub. See
-:ref:`Change-Hooks` for more information.
+to receive HTTP push notifications of commits from services like GitHub or
+GoogleCode. See :ref:`Change-Hooks` for more information.
.. bb:chsrc:: GoogleCodeAtomPoller
View
27 master/docs/manual/cfg-statustargets.rst
@@ -682,6 +682,33 @@ Note that there is a standalone HTTP server available for receiving GitHub
notifications, as well: :file:`contrib/github_buildbot.py`. This script may be
useful in cases where you cannot expose the WebStatus for public consumption.
+Google Code hook
+################
+
+The Google Code hook is quite similar to the GitHub Hook. It has one option
+for the "Post-Commit Authentication Key" used to check if the request is
+legitimate::
+
+ c['status'].append(html.WebStatus(
+ …,
+ change_hook_dialects={'googlecode': {'secret_key': 'FSP3p-Ghdn4T0oqX'}}
+ ))
+
+This will add a "Post-Commit URL" for the project in the Google Code
+administrative interface, pointing to ``/change_hook/googlecode`` relative to
+the root of the web status.
+
+Alternatively, you can use the :ref:`GoogleCodeAtomPoller` :class:`ChangeSource`
+that periodically poll the Google Code commit feed for changes.
+
+.. note::
+
+ Google Code doesn't send the branch on which the changes were made. So, the
+ hook always returns ``'default'`` as the branch, you can override it with the
+ ``'branch'`` option::
+
+ change_hook_dialects={'googlecode': {'secret_key': 'FSP3p-Ghdn4T0oqX', 'branch': 'master'}}
+
.. bb:status:: MailNotifier
.. index:: single: email; MailNotifier
Something went wrong with that request. Please try again.