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

This widget could not be displayed.

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/UpgradeTask_Build6123.java
  • 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
*/
@Nullable
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);
workflow.setDescription(description);
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
*/
@Nullable
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"))
.findFirst();

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

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

return null;
}

@Nullable
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 {
IOUtils.closeQuietly(stream);
}

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.

Cheers

That's handy!

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

This widget could not be displayed.

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

Suggest an answer

Log in or Sign up to answer
Atlassian Summit 2018

Meet the community IRL

Atlassian Summit is an excellent opportunity for in-person support, training, and networking.

Learn more
Community showcase
Posted Wednesday in New to Jira

Are you planning to trial, or are currently trialling Jira Software? - We want to talk to you!

Hello! I'm Rayen, a product manager at Atlassian. My team and I are working hard to improve the trial experience for Jira Software Cloud. We are interested in   talking to 20 people planning t...

150 views 2 0
Join discussion

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