Automate Atlassian Add-on Management Part One


What a beautiful sunny morning! I started my day with 9KM run, then followed by cold shower and a cup of hot coffee. Feel great! 🤘🏽OK, lets get down to business 🙂

I got a new idea for my next open source project (also my August challenge). It is to automate Atlassian add-on management. Just a bit background on Atlassian add-ons – like many other software vendors, Atlassian has its own eco systems (known as Atlassian Market Place) where partners can build 3rd party plugins that can extend Atlassian products’ capabilities (Jira, Confluence, Bitbucket, Bamboo…). Just name a couple of my favourites: Automation for Jira, ScriptRunner for Jira.

Atlassian products have a built in tool that is called UPM (Universal Plugin Manager), which itself is a plugin too (preinstalled). Application admins are able to enable/disable/install/uninstall/update plugins in the UPM interface. Also admins get notified if the plugins have a newer version or there is a compatility issue. A nice tool, isn’t it?

But in real life, it is a bit challenging to keep all plugins in a consistent state across different environments (dev/uat/stage/prod) if solely use the UPM UI. Especially when you manage multiple Atlassian applications, and each application has a few plugins. As human errors are inevitable. The only way I think to achieve that is to source control the plugins metadata, and automate the management process.

I did a quick proof of concept, and it proves this idea is achieve. Here are two key components that used:

Below is how my POC looks:

Code snippet:

# a3 = Automate Atlassian Addons
def get_server_info(server, auth):
''' Check application version on the server '''
print("\n>>> Checking server information")
server_application = server.split('.')[0].split('-')[0]
url = "https://{}/rest/applinks/1.0/manifest".format(server)
headers = {'content-type': 'application/xml'}
response = requests.get(url, auth=auth, headers=headers)
response.raise_for_status()
manifest = etree.fromstring(response.text.encode('utf-8'))
server_version = manifest.xpath('/manifest/version').pop().text
print("{} is on {} {}".format(server, server_application, server_version))
return {"application": server_application, "version": server_version}
def parse_plugins_details(file):
''' Get plugin details from the var file '''
try:
with open(file) as f:
plugins_details = yaml.load(f, Loader=yaml.FullLoader)["plugin_details"]
return plugins_details
except:
print("Error:", sys.exc_info()[0])
raise
def get_plugin_info_by_version_from_marketplace(plugin):
''' Get plugin info by version from Atlassian Marketplace '''
print("\n>>> Checking {} {}".format(plugin["desc"], plugin["version"]))
url = "{}/addons/{}/versions/name/{}?hosting=datacenter"\
.format(market_place_path_url, plugin["key"], plugin["version"])
headers = {'Accept': 'application/json'}
response = requests.get(url, headers=headers)
if response.status_code==404:
print(u'\u274c', "{} seems not compatible with datacenter version, please double check the version number.".format(plugin["version"]))
return False
else:
response.raise_for_status()
plugin_info = json.loads(response.text)
return plugin_info
def get_latest_plugin_info_from_marketplace(server_application, plugin):
''' Get latest plugin info from Atlassian Marketplace '''
url = "{}/addons/{}/versions/latest?application={}&afterVersion={}&hosting=datacenter"\
.format(market_place_path_url, plugin["key"], server_application, plugin["version"])
headers = {'Accept': 'application/json'}
response = requests.get(url, headers=headers)
if response.status_code==404:
print("This plugin is already on the latest version.")
return False
else:
response.raise_for_status()
plugin_info = json.loads(response.text)
print("Latest version {} is available".format(plugin_info["name"]))
return plugin_info
def check_plugin_compatibility(server_application, server_version, plugin_info):
''' Check plugin compatibility against server version '''
if plugin_info:
for supported_platform in plugin_info["compatibilities"]:
if supported_platform["application"]==server_application:
support_min_version = supported_platform["hosting"]["dataCenter"]["min"]["version"]
support_max_version = supported_platform["hosting"]["dataCenter"]["max"]["version"]
if (version.parse(support_min_version) <= version.parse(server_version)) and (
version.parse(server_version) <= version.parse(support_max_version)):
print(u'\u2713', "{} is compatible with {} {}".format(plugin_info["name"], server_application, server_version))
return True
else:
print(u'\u274c', "{} is not compatible with {} {}, the supported version is between {} and {}"\
.format(plugin_info["name"], server_application, server_version, support_min_version, support_max_version))
return False
else:
return False
view raw a3.py hosted with ❤ by GitHub

One thought on “Automate Atlassian Add-on Management Part One

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s