Created
May 10, 2015 07:23
-
-
Save joewiz/66b74c4ea445930556bf to your computer and use it in GitHub Desktop.
Receive payloads from BitBucket.org POST hooks with eXist
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
xquery version "3.1"; | |
(: | |
Receive payloads from BitBucket.org POST hooks with eXist | |
Prerequisites: | |
1. A post-January 2015 build of the develop branch of eXist, which adds support | |
for XQuery 3.1's JSON parsing and serialization features. | |
a) Check out and `build.sh` from: | |
https://github.com/exist-db/exist | |
b) Or install a nightly from http://static.adamretter.org.uk/exist-nightly/ | |
(these seem to have stopped in February, but that should still do.) | |
2. A BitBucket account and repository. | |
Setup: | |
1. Save this script as /db/apps/bbxq/payload.xq in your eXist database. Set | |
execute permissions on the script to world-executable, because BitBucket will | |
need to call this service via HTTP POST request. (Assuming you're using eXide, | |
do this via File > Manager, select payload.xq, select the "i" (info) icon, | |
and check all of the "execute" checkboxes. Then select the Apply button, then | |
the Close button.) | |
Now the script should be accessible in your browser via: | |
http://localhost:8080/exist/apps/bbxq/payload.xq | |
You should see this message: | |
<response status="fail"> | |
<message>No post data received</message> | |
</response> | |
This is to be expected. | |
2. Open monex to view the console logging output | |
http://localhost:8080/exist/apps/monex/console.html | |
Reload payload.xq in the browser, and you should see some logging of your | |
request's headers and the the same <response> as before in the console window. | |
3. You need a public URL for your eXist server. If you don't have one, install | |
ngrok from https://ngrok.com/. This gives you a publicly reachable domain name, | |
that tunnels to your computer on a port you determine. The ngrok command for | |
opening port 8080 is | |
ngrok http 8080 | |
This command then displays the URL that ngrok has assigned you. Now pull up | |
payload.xq via this URL: | |
https://YOUR-NGROK-ID.ngrok.io/exist/apps/bbxq/payload.xq | |
Confirm that you see the same results as in steps 1 and 2 above. | |
4. Configure a POST hook on your BitBucket repository, using these directions: | |
https://confluence.atlassian.com/display/BITBUCKET/POST+hook+management | |
When prompted for the URL where Bitbucket should send its update messages, | |
enter the publicly reachable URL for your payload.xq. | |
5. Push a commit to your repository. You should see the following console logs: | |
<response status="success"> | |
<message>Payload received from Bitbucket.org.</message> | |
</response> | |
{ | |
"repository": { | |
"website": "", | |
"fork": false, | |
"name": "test", | |
"scm": "git", | |
"owner": "joewiz", | |
"absolute_url": "/joewiz/test/", | |
"slug": "test", | |
"is_private": true | |
}, | |
"truncated": false, | |
"commits": [{ | |
"node": "fb2a7271e09a", | |
"files": [{ | |
"type": "modified", | |
"file": "README.md" | |
}], | |
"raw_author": "Joe Wicentowski <joewiz@gmail.com>", | |
"utctimestamp": "2015-05-10 04:17:18+00:00", | |
"author": "joewiz", | |
"timestamp": "2015-05-10 06:17:18", | |
"raw_node": "fb2a7271e09a4e393213c770330daf3d648423a1", | |
"parents": ["f809e677d8e7"], | |
"branch": "master", | |
"message": "README.md edited online with Bitbucket", | |
"revision": null, | |
"size": -1 | |
}], | |
"canon_url": "https://bitbucket.org", | |
"user": "joewiz" | |
} | |
6. That's it! With this info, you can then use BitBucket's REST API to fetch | |
the changed files. | |
:) | |
import module namespace console="http://exist-db.org/xquery/console"; | |
declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization"; | |
let $post-data := request:get-data() | |
let $log := console:log(string-join(request:get-header-names() ! concat(., ': ', request:get-header(.)), ' -- ')) | |
let $json-serialization-parameters := | |
<output:serialization-parameters> | |
<output:method>json</output:method> | |
<output:indent>yes</output:indent> | |
</output:serialization-parameters> | |
let $response-and-data := | |
if (not(empty($post-data))) then | |
if (request:get-header('Content-Type') = 'application/x-www-form-urlencoded') then | |
if (request:get-parameter-names() = 'payload') then | |
try { | |
let $payload := request:get-parameter('payload', '') | |
let $json-data := parse-json($payload) | |
return | |
if (starts-with(request:get-header('User-Agent'), 'Bitbucket.org')) then | |
( | |
<response status="success"> | |
<message>Payload received from Bitbucket.org.</message> | |
</response> | |
, | |
serialize($json-data, $json-serialization-parameters) | |
) | |
else | |
<response status="fail"> | |
<message>Bitbucket User-Agent check failed: {request:get-header('User-Agent')}.</message> | |
</response> | |
} catch * { | |
<response status="fail"> | |
<message>There was an unexpected problem. {concat($err:code, ": ", $err:description, ' (', $err:module, ' ', $err:line-number, ':', $err:column-number, ')')}</message> | |
</response> | |
} | |
else | |
<response status="fail"> | |
<message>Expected a POST Parameter named 'payload', but only received '{string-join(request:get-parameter-names(), ', ')}'.</message> | |
</response> | |
else | |
<response status="fail"> | |
<message>Expected a Content-Type header of 'application/x-www-form-urlencoded', but received '{request:get-header('Content-Type')}'.</message> | |
</response> | |
else | |
<response status="fail"> | |
<message>No post data received</message> | |
</response> | |
return | |
( | |
$response-and-data[1], | |
console:log($response-and-data)[1], | |
console:log($response-and-data)[2] | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment