Custom Script Field

Use custom script fields to create custom fields from a Groovy script. Custom script fields are designed to calculate values based on other issue fields.

Possible examples of information that could be displayed using the custom script field include:

  • Link to another project

  • Due date based on the priority of the issue

  • Link to another platform based on a combination of the issue fields

  • Calculate priority based on a combination of issue fields

Limitations to custom script fields

Script fields that use data external to the issue, such as stock prices or today's temperature, will change their value every time the issue is viewed (because they are recalculated when an issue is viewed). However, their values will not be stored in the JQL index unless the issue you are viewing is edited or transitioned. Therefore, JQL searches that use the values of these types of script fields may be inaccurate, as the index value can be out of sync with the live calculated value.

Detailed example: Display linked issues

More examples

Check out our Custom Script Field Examples page for more examples. 

The following is a detailed example that guides you through setting up a custom script field. This field will display information from the issues linked to it. This field will be useful for JQL filters and overviewing linked issue information.

In order to create this field, we want to do all of the following:

  • Fetch all the issues that make up an Epic
  • Collect a certain set of information, such as the issue's Key, Summary, and Status
  • Display that information in a table within the issue in a Script field

In the end, you will have a script field that displays linked issues, for example:

Example of the result of this script

This field will allow you to fetch this information in a filter:

Example of this custom script field displayed in a jql

Below we describe how to create this custom script field and how to set up this custom script field.

Creating the custom script field script

Final script

You can copy the following script example into a custom script field and it will display linked issues, as shown above:

import com.atlassian.jira.component.ComponentAccessor
import groovy.xml.MarkupBuilder

def issueLinkManager = ComponentAccessor.getIssueLinkManager()
def links = issueLinkManager.getOutwardLinks(issue.id)

def writer = new StringWriter()
def xml = new MarkupBuilder(writer)


if (!links) {
    return null
}

xml.style(type: "text/css",
    '''
         #scriptField, #scriptField *{
                border: 1px solid black;
            }
          
            #scriptField{
                border-collapse: collapse;
            }
        ''')

xml.table(id: "scriptField") {
    tr {
        th("Key")
        th("Summary")
        th("Status")
    }
    links.each { issueLink ->
        def linkedIssue = issueLink.destinationObject
        tr {
            td(linkedIssue.key.toString())
            td(linkedIssue.summary.toString())
            td(linkedIssue.status.getName().toString())
        }
    }
}

return (writer.toString())

Steps for creating this script

Below are the steps we took to get to the final script above.

1) Get the linked issues

You can use the following code to get the necessary imports for our script to work, and to get the links to the other issues from our Epic:

import com.atlassian.jira.component.ComponentAccessor
import groovy.xml.MarkupBuilder

def issueLinkManager = ComponentAccessor.getIssueLinkManager()
def links = issueLinkManager.getOutwardLinks(issue.id)

def writer = new StringWriter()
def xml = new MarkupBuilder(writer)

In the above script we are doing the following:

  • Using IssueLinkManager to access issue links.
  • Utilizing the issue variable to get links from the current issue.
  • Using MarkupBuilder to generate HTML safely.

    MarkupBuilder is used to avoid using HTML syntax in Groovy code, and to avoid possible injection attacks.

2) Create the table with HTML templating

You can check out this tutorial to learn more about HTML tables. For the examples below we developed our tables using HTML and then wrote them using MarkupBuilder.

You can use the following code to define basic CSS for table styling:

xml.style(type: "text/css",
    '''
         #scriptField, #scriptField *{
                border: 1px solid black;
            }
          
            #scriptField{
                border-collapse: collapse;
            }
        ''')

To this styling, you can add our table layout. The headers are Key, Summary and Status:

xml.table(id: "scriptField") {
    tr {
        th("Key")
        th("Summary")
        th("Status")
    }

3) Get the relevant information, and place a new row into the table

You can update the current table using MarkupBuilder to get the relevant information, as follows:

xml.table(id: "scriptField") {
    tr {
        th("Key")
        th("Summary")
        th("Status")
    }
    links.each { issueLink ->
        def linkedIssue = issueLink.destinationObject
        tr {
            td(linkedIssue.key.toString())
            td(linkedIssue.summary.toString())
            td(linkedIssue.status.getName().toString())
        }
    }
}

In the above script we are doing the following:

  • Using a Closure to go through every link that is collected within the variable links in our script, and getting the relevant information that we want to display
  • Getting the issue object by calling the property destinationObject.
  • Extracting issue key, summary and status information. 
4) Return of the html element and edge cases

When crafting a script, you should always take into consideration your edge cases, the cases that would make your script break. For example, what happens when an epic has no links? If you analyze the flow of the code, you will be able to tell that if we leave the script as is, when our epic task has no links, this script will just output a header, which will not look very well on its own.

You can use the following to evaluate our variable links right at the very beginning of our code, to check if it contains anything before we add the header. If it doesn’t, we will simply return null and finish the script early:

groovy
if (!links) { return null }

In addition, all of this time, the xml variable has been linked to the writer. To return this HTML, you can use the following:

groovy
return (writer.toString())

All of these examples make the above final script

Setting up the custom script field

  1. From ScriptRunner, select the Fields tab.
  2. Select Create Script Field.
  3. Select Custom Script Field.
  4. Enter the name for the custom script field. In this example, we enter Linked issues
  5. Optional: enter a description. In this example, we enter Show all linked issues
  6. Optional: add a field note. 
  7. Select the Text field (multi-line) template.
  8. Enter the following script into the script editor:
    import com.atlassian.jira.component.ComponentAccessor
    import groovy.xml.MarkupBuilder
    
    def issueLinkManager = ComponentAccessor.getIssueLinkManager()
    def links = issueLinkManager.getOutwardLinks(issue.id)
    
    def writer = new StringWriter()
    def xml = new MarkupBuilder(writer)
    
    
    if (!links) {
        return null
    }
    
    xml.style(type: "text/css",
        '''
             #scriptField, #scriptField *{
                    border: 1px solid black;
                }
              
                #scriptField{
                    border-collapse: collapse;
                }
            ''')
    
    xml.table(id: "scriptField") {
        tr {
            th("Key")
            th("Summary")
            th("Status")
        }
        links.each { issueLink ->
            def linkedIssue = issueLink.destinationObject
            tr {
                td(linkedIssue.key.toString())
                td(linkedIssue.summary.toString())
                td(linkedIssue.status.getName().toString())
            }
        }
    }
    
    return (writer.toString())
  9. Optional: enter an issue key and select Preview to preview this custom script field
  10. Select Add.
    Image showing this custom script field filled in
  11. Configure the context and screens for this custom script field.

    Test your script field

    You can now test your script field displays as expected in your issues. 


If you check the script field, you will notice the following line:

groovy
... issueLinkManager.getOutwardLinks(issue.id) ...

This line retrieves the Outward links of the issue, not the Inward links. Understanding this distinction is crucial in Jira, as links between issues are categorized as Inward or Outward based on the link's origin.

  • Outward link: Created from within the issue you're referencing, indicating the link originates from that issue.
  • Inward link: Created from another issue, indicating the link originates from outside the issue you're referencing.

For example, if stories were linked to an epic from the stories themselves, rather than from the epic, the table above would display nothing because the links would be Inward, not Outward.



Related content


On this page