Jan 21, 2014
JIRA Universal Plugin Manager API
Deploying JIRA plugins isn’t the most enjoyable process. You’re forced to go work through a UI that takes ~10 seconds to load a single page where you upload a .jar hoping that your request went through since there’s no feedback. What if you want to automate this process? What if you want to do continuous deployment of a certain plugin?
The functionality for this exists in JIRA and is fairly simple to use. It is also entirely undocumented therefore entirely subject to change. Yay JIRA :(.
JIRA’s UPM Documenation: https://ecosystem.atlassian.net/wiki/display/UPM/UPM+REST+API
Programatically Disable Modules You Don’t Need
To do this we’ll make a simple PUT request that changes the state of individual plugins or modules to disabled instead of enabled. Simple right? Sort of.
This header:
'Content-Type': 'application/vnd.atl.plugins.plugin.module+json'
tells JIRA that we’re sending plugin info. Without it your request will be ignored.
This header: 'X-Atlassian-Token': 'nocheck' tells JIRA not to check the CSRF token (???) because we’re a script and not a client.
To find what the URL for the component you would like to disable you can just make GET requests at higher levels to list the components at lower levels. So I would just curl -u user:password https://localhost:2990/rest/plugins/1.0/ and drill down the list based on the results.
import json
import requests
from requests.auth import HTTPBasicAuth
baseurl = 'http://localhost:2990/jira/rest/plugins/1.0/'
headers = {
# This is the only content-type the API will accept
'Content-Type': 'application/vnd.atl.plugins.plugin.module+json',
# This disables some token checking
'X-Atlassian-Token': 'nocheck'
}
# We use HTTPBasicAuth (equivalent to curl -u user:pass)
auth = HTTPBasicAuth('admin', 'admin')
# This very long URL is made of two pieces:
# 1. the plugin namespace and key
# 2. the module namespace and key
# You can discover this info with a GET request to these same endpoints.
module_url = 'com.atlassian.jira.plugin.system.issuetabpanels-key/modules/changehistory-tabpanel-key'
# first we grab the JSON representation of the module
data = requests.get(baseurl + module_url, auth=auth).json()
# now we just flip the enabled state in the json
# and PUT it back (with our fancy content-type headers)
data['enabled'] = False
requests.put(
baseurl+module_url,
headers=headers,
auth=auth,
data=json.dumps(data)
)
The API is actually very RESTful and you can discover a lot of the functionality by making GET requests to the same endpoints we’re sending these PUT requests. I’d say this is one of JIRA’s strong points.
Uploading A New Module
Luckily installing new plugins is similarly straightforward – with one additional caveat. JIRA’s universal plugin manager (UPM) requires you to pass in a request/session/authentication token with your request.
Let’s say I have a module called my-fancy-plugin.jar that I’ve made with atlas-package. I can easily upload this with a simple python script like the one below:
import requests
from requests.auth import HTTPBasicAuth
auth = HTTPBasicAuth('admin', 'admin')
url = 'http://localhost:2990/jira/rest/plugins/1.0/'
# tell it not to check XSRF stuff
headers = {'X-Atlassian-Token': 'nocheck'}
# we first GET the URL to get the UPM token
r = requests.get(url, auth=auth)
upm_token = r.headers.get('upm-token')
# lets grab our plugin file (created with atlas-package)
files = {'plugin': open('my-fancy-plugin.jar', 'rb')}
requests.post(
# shove that UPM token on the end of the URL
url+'?token='+upm_token,
files=files,
headers=headers,
auth=auth
)
This makes devops for jira plugins a lot easier!
You can even follow the status of the installation. The POST response has a links key that will link to the installation URL and you can ping that for status updates.
A huge shoutout to @miknight for all of his help with figuring this out!
JIRA is actually pretty cool – even though it has some rough spots.