How does atlassian format workflows programatically? Edited

Hey there,

i am importing workflows via my own scriptrunner restendpoints (including xml-parsing, statusmapping etc.) programatically into an jira instance.

So far works like a charm. Problem is the visual workflow designer displays all the status and transitions nearly unreadable under each other.

I was wondering if i could somehow programatically format them.

I came across the fact that the jira default workflow (atlassian-jira/WEB-INF/classes/jira-workflow.xml) is formatted well, but that there are no styling information in the xml file. Because of that i searched the whole atlassian-jira sources, but could not find anything that does that formatting.

If anyone knows how-/where it´s done, please share.

2 answers

1 accepted

If you have the JIRA Sources (I'm currently working with atlassian-jira-software-7.6.1-source), have a look at the following files:

  • jira-project/jira-components/jira-core/src/main/osworkflow/jira-workflow.xml
  • jira-project/jira-components/jira-core/src/main/java/com/atlassian/jira/upgrade/tasks/
  • jira-project/jira-components/jira-core/src/main/resources/system-classic-workflow-layout.json

They are mapping a JSON layout file on a XML workflow file...

If I will manage to get the JSON for an existing workflow, I will let you know. 

So, here we go:

* Create a workflow based on an exported workflow XML file.
* You can provide a layout file in layout format v5 with the following pattern:
* - my-workflow.xml (workflow XML file)
* - my-workflow-format.json (workflow JSON format file)
* @param name the workflow name
* @param description the workflow description
* @param pathXml the path to the workflow xml file
* @return the created workflow
public JiraWorkflow createWorkflowFromXML(
@Nonnull final String name,
@Nonnull final String description,
@Nullable final String pathXml) {

if (pathXml == null || pathXml.isEmpty() || !pathXml.endsWith(".xml")) {
return null;

final String xml = readFile(pathXml);
if (xml == null) {
return null;

final String layoutKey = DigestUtils.md5Hex(name);
final String pathFormatJson = pathXml.replace(".xml", "-format.json");
final String formatJson = readFile(pathFormatJson);

try {
final WorkflowDescriptor descriptor = WorkflowUtil.convertXMLtoWorkflowDescriptor(xml);
final ConfigurableJiraWorkflow workflow = new ConfigurableJiraWorkflow(name, descriptor, workflowManager);
workflowManager.createWorkflow(authenticationContext.getLoggedInUser(), workflow);

eventPublisher.publish(new WorkflowImportedFromXmlEvent(workflow));

if (formatJson != null) {
final Map<String, Object> entryFields = ImmutableMap.of(
"entityName", "com.atlassian.jira.plugins.jira-workflow-designer",
"entityId", 1,
"propertyKey", "jira.workflow.layout.v5:" + layoutKey,
"type", 6);
final Long layoutId = ofBizDelegator.createValue("OSPropertyEntry", entryFields).getLong("id");
final Map<String, Object> textFields = ImmutableMap.of(
"id", layoutId,
"value", formatJson);
ofBizDelegator.createValue("OSPropertyText", textFields);

return workflow;
} catch (FactoryException e) {
String message = "Error parsing workflow XML: " + e.getMessage();
log.error(message, e);
} catch (WorkflowException e) {
String message = "Error saving workflow: " + e.getMessage();
log.error(message, e);

return null;

* Find the layout for a designed workflow.
* This json layout file can be used to format a workflow that is exported as XML
* @param name the workflow name
* @return the json layout
public String getWorkflowFormatJson(
@Nonnull final String name) {

String layoutKey = DigestUtils.md5Hex(name);

Map<String, String> filter = ImmutableMap.of(
"entityName", "com.atlassian.jira.plugins.jira-workflow-designer",
"propertyKey", "jira.workflow.layout.v5:" + layoutKey);

Optional<Long> layoutId = ofBizDelegator.findByLike("OSPropertyEntry", filter).stream()
.map(gv -> gv.getLong("id"))

if (layoutId.isPresent()) {
GenericValue osPropertyText = ofBizDelegator.findById("OSPropertyText", layoutId.get());

if (osPropertyText != null) {
return (String) osPropertyText.get("value");

return null;

private String readFile(String filename) {
InputStream stream = getClass().getClassLoader().getResourceAsStream(filename);

try {
return IOUtils.toString(stream, "utf-8");
} catch (IOException e) {
log.error("Could not read file" + filename, e);
} finally {

return null;

Note that replaced some custom stuff and did not test the code again. Also note that there are different format versions for the workflows and this code currently only works with version v5.


That's handy!

Thanks @Patrick Hobusch for sharing your knowledge. I will give it a shot. 

0 vote

I've never seen a way to format the workflow diagram programmatically

Suggest an answer

Log in or Sign up to answer
How to earn badges on the Atlassian Community

How to earn badges on the Atlassian Community

Badges are a great way to show off community activity, whether you’re a newbie or a Champion.

Learn more
Community showcase
Published Thursday in Jira Service Desk

How the Telegram Integration for Jira helps Sergey's team take their support efficiency to the bank

...+ reading Fantasy). The same is true for him at the bank he works for: Efficiency is key when time literally equals money. Read on to learn how Sergey makes most of the time he has by...

241 views 0 3
Read article

Atlassian User Groups

Connect with like-minded Atlassian users at free events near you!

Find a group

Connect with like-minded Atlassian users at free events near you!

Find my local user group

Unfortunately there are no AUG chapters near you at the moment.

Start an AUG

You're one step closer to meeting fellow Atlassian users at your local meet up. Learn more about AUGs

Groups near you