Jira Webhooks
this is an example of a simple Webhook that creates a .json file. The goal is to pass ticket data from JIRA to some other system and run scripts on that system to parse this data.
JIRA v7.1.6
Sept 29, 2016
Process breakdown:
whenever a JIRA ticket is submitted, JIRA has a webhook that sends out a POST request to a URL on some other server (or on itself, in this example its localhost)
a Client is listening on this URL and certain Port # and then runs a shell script if it hears anything come in from JIRA
Shell script takes the entire message packet and dumps it into a .json file
From there, you can do whatever to that .json file
This example shows a shell script pushing information from the Json file to a Git repository via AP
Setup JIRA to handle webhooks
login as Admin to Jira
click on Administration > System > Webhooks, create a new Webhook
Give name, URL of the server thats running a Client to listen to this webhook + Port #
Can also give qualifiers to kick off the webhook, for example all projects called POC and only if the custom field ID 10208 is not null
Save the webhook
Setup Client
on a separate server (or the JIRA server itself), setup a client, it can be any type. This example uses a Golang client found here,
https://github.com/adnanh/webhook
to setup client:
setup Golang environment (make sure to have $GOPATH env set
run "go get github.com/adnanh/webhook" to pull in the project
the Client binary is located in /bin
create a new "hook.json" that tells the Client what to do, place this file in same directory as where you Client is at.
[root@green ~/golang]# pwd
/root/golang
[root@green ~/golang]# ls
bin hooks.json jira_out.sh pkg src tickets
[root@green ~/golang]# vi hooks.json
[
{
"id": "jira-new",
"execute-command": "/root/golang/jira_out.sh",
"command-working-directory": "/root/golang",
"pass-arguments-to-command":
[
{
"source": "entire-payload"
}
]
}
]
create a new shell script to process incoming JIRA data, this script will simply dump the JSON output into a file
[root@green ~/golang]# cat jira_out.sh
#!/bin/sh
echo $1 > tickets/`date +"%m-%d-%y-%s"`.json
Make sure the JIRA Admin page details match up with your "hooks.json" file (webhook name, port #)
Refer to the Github link for more documentation
Run the Webhook Client on localhost, custom port 7788, verbose
./bin/webhook -hooks hooks.json -ip 127.0.0.1 -port 7788 -verbose &
[root@green ~/golang]# [webhook] 2016/09/29 15:21:52 version 2.4.0 starting
[webhook] 2016/09/29 15:21:52 setting up os signal watcher
[webhook] 2016/09/29 15:21:52 attempting to load hooks from hooks.json
[webhook] 2016/09/29 15:21:52 os signal watcher ready
[webhook] 2016/09/29 15:21:52 found 1 hook(s) in file
[webhook] 2016/09/29 15:21:52 loaded: jira-new
[webhook] 2016/09/29 15:21:52 serving hooks on http://127.0.0.1:7788/hooks/{id}
on JIRA, update a ticket that matches your Webhook filter, you should see the client grab it and create a JSON file in /tickets folder
[webhook] 2016/09/29 15:22:57 Started POST /hooks/jira-new
[webhook] 2016/09/29 15:22:57 jira-new got matched
[webhook] 2016/09/29 15:22:57 jira-new hook triggered successfully
[webhook] 2016/09/29 15:22:57 Completed 200 OK in 805.1µs
[webhook] 2016/09/29 15:22:57 executing /root/golang/jira_out.sh (/root/golang/jira_out.sh) with arguments ["/root/golang/jira_out.sh" "{\"comment\":{\"author\":{\"active\":true,\"avatarUrls\":{\"16x16\":\"https://green.vagrant.local/secure/useravatar?size=xsmall\\u0026avatarId=10341\",\"24x24\":\"https://green.vagrant.local/secure/useravatar?size=small\\u0026avatarId=10341\",\"32x32\":\"https://green.vagrant.local/secure/useravatar?size=medium\\u0026avatarId=10341\",\"48x48\":\"https://green.vagrant.local/secure/useravatar?
LONG JSON DATA HERE
LONG JSON DATA HERE
LONG JSON DATA HERE
LONG JSON DATA HERE
LONG JSON DATA HERE
avatarId=10341\"},\"displayName\":\"green.admin\",\"emailAddress\":\"admin@green.com\",\"key\":\"green.admin\",\"name\":\"green.admin\",\"self\":\"https://green.vagrant.local/rest/api/2/user?username=green.admin\",\"timeZone\":\"US/Eastern\"},\"body\":\"a\",\"created\":\"2016-09-29T15:22:57.279 /root/golang as cwd
[webhook] 2016/09/29 15:22:57 command output:
[webhook] 2016/09/29 15:22:57 finished handling jira-new
OPTIONAL
an example of a webhook Python client - if you dont want to use a Golang binary, this collects data from the incoming JIRA json , parses it, and then sends it a shell script for further actions.
start the webhook client by running
./listener.py &
this will listen on port 5000 for any incoming POST requests
#!/usr/bin/env python
import json, re, flask, os, subprocess
from sys import platform as _platform
from flask import Flask
from flask import request
app = Flask(__name__)
@app.route('/webhook', methods=['GET', 'POST'])
def tracking():
if request.method == 'POST':
data = request.get_json()
## JIRA stuff here:
# set custom fields:
field_ssh_port = "customfield_10102"
field_ssh_key = "customfield_10208"
field_requester_id = "customfield_10200"
field_integration = "customfield_10205"
content = {} # dictionary of all key:val pairs
# Firm ID
value = data['issue']['fields'][field_requester_id]
if not value:
exit("Need to provide a Firm ID in JIRA json")
else:
requester_id = value.lower()
# SSH Port
if data['issue']['fields'][field_ssh_port]:
value = data['issue']['fields'][field_ssh_port]
value = "[%s" % value + "]"
ssh_port = { "ports" : value }
content.update(ssh_port)
# SSH Key Field
value = data['issue']['fields'][field_ssh_key]
key = { "key" : value }
content.update(key)
# Integration Field
if data['issue']['fields'][field_integration]:
integration_val = data['issue']['fields'][field_integration]['value']
if integration_val:
integration = { "tunnels" : integration_val.lower() }
content.update(integration)
# SSH Type
ssh_type = { "type" : "sshkey" }
content.update(ssh_type)
# Save JSON outfile
json_file='ssh%s.json' % requester_id
currdir =os.getcwd()
sshpath =os.path.join(currdir + '/file',json_file)
with open(sshpath,'w') as outfile:
json.dump(content,outfile,sort_keys=False, indent=4)
outfile.close()
# call Bash script to create new branch and pull request
subprocess.Popen(['./gitpush.sh',requester])
if _platform == "darwin":
from pync import Notifier
Notifier.notify('wrong OS - running Darwin')
else:
print 'Webhook received! '
return 'OK'
else:
return displayHTML(request)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
Once the JSON file is generated, you can run additional scripts to do something to this data. This example parses the data, pushes fields to Git version control and also creates a Pull Request via API
#!/bin/sh
# this script takes an argument from a Python script 'listener.py', creates a new git branch
# and adds a new ssh file to version control. Do not run this manually!!
## set params
base_dir=$(pwd)
requester_id=$1
git_user=myUser
git_pw=myPassword
git_server="bitbucket.server.local"
git_project="MyPROJECT"
git_repo="myRepo"
ssh_json_dir="${base_dir}/${git_repo}/json_dir"
# check if Project repository present
test -d "${base_dir}/${git_repo}" || { echo "puppet git repository not present at ${base_dir}/${git_repo}, exiting.." 1>&2 ; exit 1; }
# check if CURL is installed
test -f "/usr/bin/curl" || { echo "Curl is not installed on this system, exiting.." 1>&2 ; exit 1; }
cd "${base_dir}/${git_repo}"
# check Project repo has .git directory present
if [ -d .git ]
then
# check if Project repo remote is present
if [ ! $(git remote -v | grep push) ]
then
echo "no remote configured"
exit 1
fi
else
echo "Project repository path does not have git initialized"; exit 1
fi
if [ "${requester_id}" ]
then
echo "workin on json"
jsonfile="${requester_id}.json"
# strip Port value of double quotes
sed -i -e 's/"ports": "/"ports": /g' "${base_dir}/file/${jsonfile}"
sed -i -e 's/]"/]/g' "${base_dir}/file/${jsonfile}"
# Git work - pull latest
git checkout master
git pull origin master
##### add ssh file branch to repo as a new branch
cd "${ssh_json_dir}" && git checkout -b "ssh-${requester_id}"
git checkout "ssh-${requester_id}"
cp "${base_dir}/file/${jsonfile}" "${ssh_json_dir}"
git add "${jsonfile}"
git commit -m "new SSH key request: ${requester_id}"
git checkout master
git push origin "sshkey-${requester_id}"
# create pull request
api_data="{\"title\":\"ssh-${requester_id}\",\"description\":\"SSH Key Request for - ${requester_id}\",\"fromRef\":{\"id\":\"refs/heads/ssh-${requester_id}\",\"repository\":{\"slug\":\"${git_repo}\",\"name\":null,\"project\":{\"key\":\"${git_project}\"}}},\"toRef\":{\"id\":\"refs/heads/master\",\"repository\":{\"slug\":\"${git_repo}\",\"name\":null,\"project\":{\"key\":\"${git_project}\"}}}}"
curl -u $git_user:$git_pw -H "Content-Type: application/json" https://$git_server/rest/api/1.0/projects/$git_project/repos/$git_repo/pull-requests -X POST --data "${api_data}"
else
echo "No Requester ID set, exiting.."
exit 1
fi