Skip to content

Instantly share code, notes, and snippets.

@joewiz
Created May 10, 2015 07:23
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joewiz/66b74c4ea445930556bf to your computer and use it in GitHub Desktop.
Save joewiz/66b74c4ea445930556bf to your computer and use it in GitHub Desktop.
Receive payloads from BitBucket.org POST hooks with eXist
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