How to find all workflows which are using postfunctions of a plugin

We need to upgrade a JIRA, but one of the plugins is not compatible.
How can we find all the workflows which are using the workflow functions from this plugin ?

6 answers

1 accepted

Accepted Answer
3 votes

You could use the Script Runner plugin to search for more detailed uses. I wrote a script to create a list which than can be used e.g. in Excel for further investigations.

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.workflow.JiraWorkflow
import com.atlassian.jira.workflow.WorkflowManager
import java.util.regex.Matcher

String searchText = 'com.googlecode.jsu.workflow.'

WorkflowManager workflowManager = ComponentAccessor.getWorkflowManager()
Collection<JiraWorkflow> workflows = workflowManager.getWorkflows()

String result = "Workflow;Function;Type;Action;Step\r\n"

workflows.each{workflow ->
    workflowXml = workflow.descriptor.asXML()
    Matcher m = workflowXml =~ /${searchText}/
    if (m.find()) {
        String workflow_name = "${workflow.name}${if(!workflow.isActive()){"(inactive)"} else ''}${if(workflow.isDraftWorkflow()){"(draft)"} else ''}"
        def wf = new XmlParser().parseText(workflowXml)
        List<Node> wf_flat = wf.depthFirst()
        wf_flat.each{
            if (it.text() ==~ /.*${searchText}.*/){
                result += "$workflow_name;${getNodeInfo(it,searchText)}\r\n"
            }
        }
    }
}
result

String getNodeInfo(Node n, String search) {
    String nodetext = ''
    nodetext += "${n.text() - search}"
    def p = n.parent()
    while (p) {
        switch (p.name()) {
            case 'post-functions':
                nodetext += ";post-function"; break
            case 'validators':
                nodetext += ";validator"; break
            case 'conditions':
                nodetext += ";condition"; break
            case 'action':
                nodetext += ";${p.attribute('name')} (${p.attribute('id')})"; break
            case 'step':
                nodetext += ";${p.attribute('name')} (${p.attribute('id')})"; break
            case 'global-actions':
                nodetext += ";GLOBAL"; break
            case 'initial-actions':
                nodetext += ";INITIAL"; break

        }
        p = p.parent()
    }
    return nodetext
}

You have to adapt the searchText to match the plugin.

Henning

 

That's a cool approach, not requiring to access JIRA 'behind the scenes'
Certainly a candidate for a build-in script (IMO)

Henning - this a beautiful solution. Thanks for sharing!

@Henning Tietgens  – quick question. in the getNodeInfo method – why are you using the minus operator here:

 nodetext += "${n.text() - search}"

 

It looks like it's removing the search term from nodetext...?  Not sure why you are doing that. Any tips / insight much appreciated!

Henning Tietgens Community Champion Apr 21, 2016

You're right. It's only for shorter list entries.

We are currently using a query on the database, but I'm wondering if there is another approach.
The query is something like

select workflowname
from jira.jiraworkflows
where descriptor like '%iamhuy%'

You could export all workflows as xml-files and then search in these files for that plugin (e.g. com.googlecode.jsu). But I guess searching in in the database is faster.

Hi there,

When I run the above code in the ScriptRunner Console I get the following error:

 

Error

startup failed: Script45.groovy: 13: expecting '}', found '-' @ line 13, column 25. workflows.each{workflow -&gt; ^ 1 error

org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed: Script45.groovy: 13: expecting '}', found '-' @ line 13, column 25. workflows.each{workflow -&gt; ^ 1 error 

 

Any idea how to resolve?

Regards

Dave 

Henning Tietgens Community Champion Aug 20, 2018

Please try copying the source again. There were some html conversion problems while converting from Atlassian answers to the community site.

Henning

Many thanks Henning

I noticed some warnings as shown below

warning.PNG

and when ran it seemed to picked up everything instead of just the lines with 'customfield' listed.

output.PNGAny idea what the problem is?

Regards

Dave

0 votes

Hi,

here is a refined version of my script.

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.workflow.JiraWorkflow
import com.atlassian.jira.workflow.WorkflowManager
import java.util.regex.Matcher

String searchText = 'customfield'

WorkflowManager workflowManager = ComponentAccessor.getWorkflowManager()
Collection<JiraWorkflow> workflows = workflowManager.getWorkflows()

String result = "Workflow;Function;Type;Action;Source-Step<br>"

workflows.each{workflow ->
def workflowXml = workflow.descriptor.asXML()
Matcher m = workflowXml =~ /${searchText}/
if (m.find()) {
String workflow_name = "${workflow.name}${if(!workflow.isActive()){"(inactive)"} else ''}${if(workflow.isDraftWorkflow()){"(draft)"} else ''}"
def wf = new XmlParser().parseText(workflowXml)
List<Node> wf_flat = wf.depthFirst()
wf_flat.each{
if (it.text() ==~ /.*${searchText}.*/){
def nodeInfo = getNodeInfo(it,searchText)
if (nodeInfo){
result += "$workflow_name;$nodeInfo<br>"
}
}
}
}
}
result

String getNodeInfo(Node n, String search) {
String nodetext = ''
def valid_action = false
def valid_function = false
def valid_step = false
if (n.name() == 'function') {
def m = n.value() =~ /[^\[{]*/ + search + /[^\]}]*/
if (m) {
nodetext += m[0].toString() + ";"
}
def p = n.parent()
while (p) {
switch (p.name()) {
case 'post-functions':
valid_function = true
nodetext += "post-function;"; break
case 'validators':
valid_function = true
nodetext += "validator;"; break
case 'conditions':
valid_function = true
nodetext += "condition;"; break
case 'action':
valid_action = true
nodetext += "${p.attribute('name')} (${p.attribute('id')});"; break
case 'step':
valid_step = true
nodetext += "${p.attribute('name')} (${p.attribute('id')})"; break
case 'global-actions':
valid_step = true
nodetext += "GLOBAL"; break
case 'initial-actions':
valid_step = true
nodetext += "INITIAL"; break
}
p = p.parent()
}
}
if (valid_action && valid_function && valid_step) {
return nodetext
} else {
return ""
}
}

Dave, please try this.

Henning

Hi Henning

Many thanks for all your efforts

I'm getting the error shown below

error.PNGThis links https://community.atlassian.com/t5/Jira-questions/Scriptrunner-for-jira-Copy-Project-Error-Timeout-No-stack-trace/qaq-p/209892 says this can be expected and the routune still runs. If so, is there a directory location  ca search for the output?

Regards

Dave  

Henning Tietgens Community Champion Aug 22, 2018

In this case you have to replace the line 

result += "$workflow_name;$nodeInfo<br>"

with

log.error "$workflow_name;$nodeInfo"

Or you can add this line below the above line if you want both outputs. This way the output is in the atlassian-jira.log (you can view the location of the atlassian-jira.log in the 'File Paths' section of the system information page.).

Henning

Many thanks Henning, that seemed to work

All the best

Dave

Sorry Henning, but it seems to be case sensitive as is correctly matching the lowercase "customfield"  text. 

When I try to run for "CustomField" it runs iis a split second and does not produce any output.

Any idea?

Regards

Dave

Henning Tietgens Community Champion Aug 24, 2018

Hi Dave,

Yes, the search is case sensitive. It's searching for workflow postfunctions, conditions and validators from specific plugins by parsing the XML output of the workflow.

If you know what you are searching for and you know a workflow which uses the functionality you can export this workflow as XML and try to find the specific identifier of it. This identifier can than be used in my script to find all workflows using it.

What are you searching for while searching for "CustomField"?

Best regards,
Henning

Hi Henning,

I'm trying to identify all references to a custom fields that use the native number extension (e.g. customFieldManager.getCustomFieldObject(11203L)).

In your script I am using:

String searchText = 'getCustomFieldObject'

but all I'm getting back in a sub-second response In the Results tab is 

Workflow;Function;Type;Action;Source-Step

Because I've have now also searched the XML export with no luck I presume the problem is that the code is references within Post Functions the ScriptRunner workflow function - Custom script post-function (inline script).

Any idea how to search through this?

Regards

Dave

Henning Tietgens Community Champion Aug 26, 2018

Hi Dave, the scriptrunner parameters are base64 encoded since 4.3.3, see https://scriptrunner.adaptavist.com/4.3.3/jira/releases/current-release.html#_base64_encoding_for_workflow_function_arguments. On this page is a link to a script to decode workflow XMLs containing scriptrunner base64 encoded parameters. You could try to incorporate this script into my script to decode all parameters after getting the XML and before searching, between those lines.

    def workflowXml = workflow.descriptor.asXML()
Matcher m = workflowXml =~ /${searchText}/

Henning

Suggest an answer

Log in or Sign up to answer
Community showcase
Posted Sep 25, 2018 in Jira

Atlassian Research Workshop opportunity on Sep. 28th in Austin, TX

We're looking for participants for a workshop at Atlassian! We need Jira admins who have interesting custom workflows, issue views, or boards. Think you have a story to sha...

439 views 7 5
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