Subtasks Navigation for Jira migrates to cloud

22. July 2022

Well, our Subtasks Navigation plugin for Jira is already in the cloud, but to this point, there was no way how to migrate from the server version to the cloud. Since Atlassian no longer sells licenses of server versions and focuses more on the web application, many customers will eventually migrate to the cloud.

In order to make this process as hassle-free as it can be, we released a new version of Subtasks Navigation, that supports automatic migration from server/data center to cloud. This will ensure all your plugin-related settings will be transferred to the cloud Jira instance. In order to migrate, you will also need a free plugin Jira Cloud Migration Assistant. It will lead you through the process of selecting plugins that you need in the cloud, migration of Jira projects, and all other related data. It will also execute a migration process of all your selected plugins that support the migration using JCMA - which Subtasks Navigation does now.

If you run a newer version of server Jira, it will already have a JCMA plugin installed by default. Just follow the official Atlassian migration guide and Subtasks Navigation will migrate too. Alternatively, there is our own migration guide.

Technical details of the migration process

Even though this isn’t a technical post or tutorial, I think someone somewhere who is yet to implement the migration process using JCMA may appreciate a more technical overview of it.

The server plugin

  • The JCMA exposes a package of interfaces and classes your plugin has to import and use. In general, it provides methods for you to upload migration data and register your code, so the JCMA knows what to execute when your plugin is to be migrated (it usually means implementing the interface CloudMigrationListenerV1).

  • Atlassian provides several examples of how to register your code and how to upload migration data. Some examples are prone to failure when JCMA isn’t installed in the Jira, some of them are production ready. Our process is based on the Buffer Sample.

  • It’s time to gather your plugin-related data and upload them using CloudMigrationGateway. Atlassian is using AWS S3 in the background, but you don’t need to know it. Just call the method createAppData and use the provided OutputStream to write your data in. You can migrate user-uploaded files this way one by one, or gather the data to your custom JSON format and pass the bytes to the OutputStream by calling getBytes() on the JSON String.

  • If you need to know some entity ID in the cloud and you have the entity ID on the server version, you need to use a mapping table between the server and cloud IDs (since they are different). CloudMigrationGateway provides the method getMappingById, which returns the mapping table as Map<String, String>.

  • Don’t forget to correctly specify the server and cloud app key of your plugin by implementing methods getCloudAppKey and getServerAppKey.

The cloud plugin

  • Cloud Jira will call your cloud plugin when the file is uploaded. For that reason, the cloud plugin must provide an endpoint, that will be handling the event app-data-uploaded.

  • You must let the Jira know, where this endpoint is. This can be done only using a REST API, so when your plugin is installed, use the enabled lifecycle hook to register the endpoint to cloud Jira.

  • So the file was uploaded and cloud Jira is calling your plugin. Check if body attribute eventType is app-data-uploaded and if so, fetch the signed S3 URL - the body of the request contains attribute s3Key, that you are going to use in this call.

  • This call will finally return the S3 URL that you can use to fetch the resource (no token or signature is needed). In the Subtasks Navigation case, it is a JSON so we simply get it in JavaScript as an object by calling response.json(). Now it’s up to you to process your plugin-related data.

  • When you are finished, don’t forget to report the migration status back to cloud Jira using this API. This is very important because Jira tracks the rate of successful migrations and assigns a rating to your plugin, that is visible to users. You can even report back the progress in %.

Tips, tricks, and warnings

The implementation of migration wasn’t that hard, but the Atlassian documentation is’t compact or very consistent, so you can easily miss something important or understand some concept wrongly. So here are a few tips and warnings.

  • If Jira calls something a “webhook”, it doesn’t always work in the same way. For example, this documentation lists a few different ways, how to register a webhook - for example using atlassian-connect.json. When you are registering the migration endpoint to cloud Jira, it is also called a webhook, so you would think it can also be done using atlassian-connect.json. But NOPE. You can register that webhook only using this endpoint.

  • It’s tempting to register the migration webhook above in the installed lifecycle call. Don’t even try. The plugin installation isn’t finished at this point, so any call to Jira will fail. Use enabled lifecycle call.

  • Your every call to cloud Jira must be signed using the JWT generated by your plugin. Our recent blog post goes deep into the implementation of JWT.

  • During the development and testing, your server plugin doesn’t officially support the migration yet (you will do it later by setting the supported version using Atlassian Marketplace REST API), so JCMA won’t allow the migration of your plugin to happen. You can bypass it by enabling the dark feature This will execute the migration on all plugins, even if they aren’t selected for migration.

  • While the whole process is mostly event-driven, it can be useful to implement a scheduled job in your cloud plugin, that will iterate through all unfinished migrations and re-execute them. A network problem between your plugin and cloud Jira can for example lead to stuck migration. And the user could contact you to resolve this stuck migration. So it’s best practice to ensure all migrations are closed with state SUCCESS, FAILED, or INCOMPLETE.

  • So both versions of the plugin are released and the migration work flawlessly? But don’t forget to tell Atlassian Marketplace the version of the plugin that supports migrations and the page with public documentation. This can be done only using this API.

Author: Luděk Novotný