Custom Script Field Examples
This page contains a number of custom script field examples:
- Calculate a number based on other fields
- Show the total time this issue has been In progress
- Show the number of attachments the issue has
- Show all previous versions in a given project
- Display an information message
- Show the component lead
- Show multiple component leads
- Show the work remaining in linked issues
- Show the work remaining in all issues in an epic
Examples
Don’t forget to reindex if you want your newly created scripted custom field to appear in existing issues.
For the examples below, you must first navigate to the Custom Script Field page:
- From ScriptRunner, select the Fields tab.
- Select Create Script Field.
- Select Custom Script Field.
- Create a custom script field based on the examples provided below.
Calculate a number based on other fields
You can calculate a number based on other fields. In the following example, we already have a number field called Severity, and we want a new value that is the product of the Priority and Severity:
- Enter the name for the custom script field. In this example, we enter Critical Points.
- Optional: enter a description. In this example, we enter Calculate critical points based on Priority and Severity.
- Optional: add a field note.
- Select the Number Field template.
Enter the following script into the script editor:
groovydef severity = getCustomFieldValue("Severity") if (severity) { return severity * Integer.parseInt(issue.priority.id) } else { return null }
- Optional: enter an issue key and select Preview to preview this custom script field
- Select Add.
- Configure the context and screens for this custom script field.
Be careful and test this against an issue with no Severity value set.
Show the total time this issue has been In Progress
You can create a custom field that shows the total time an issue has been in the In Progress
state—summing up multiple times if necessary:
- Enter the name for the custom script field. In this example, we enter Time In Progress.
- Optional: enter a description. In this example, we enter Total time this issue has been In Progress.
- Optional: add a field note.
- Select the Duration template.
Enter the following script into the script editor:
import com.atlassian.jira.component.ComponentAccessor import com.atlassian.jira.issue.history.ChangeItemBean def changeHistoryManager = ComponentAccessor.getChangeHistoryManager() def inProgressName = "In Progress" List<Long> rt = [0L] def changeItems = changeHistoryManager.getChangeItemsForField(issue, "status") changeItems.reverse().each { ChangeItemBean item -> def timeDiff = System.currentTimeMillis() - item.created.getTime() if (item.fromString == inProgressName) { rt << -timeDiff } if (item.toString == inProgressName) { rt << timeDiff } } def total = rt.sum() as Long (total / 1000) as long ?: 0L
- Optional: enter an issue key and select Preview to preview this custom script field
- Select Add.
Make sure the Search Template/Searcher for this custom field is Duration Searcher.
You can edit the Searcher by selecting the configured searcher on the Script Fields page.
- Configure the context and screens for this custom script field.
Show the number of attachments the issue has
This example is superseded by the JQL function hasAttachments
.
You can create a custom script field to show the number of attachments. This could easily be modified to show the number with a specific extension etc.
- Enter the name for the custom script field. In this example, we enter Number of Attachments.
- Optional: enter a description.
- Optional: add a field note.
- Select the Number Field template.
Enter the following script into the script editor:
groovydef numberAttachments = issue.attachments.size() // use the following instead for number of PDFs // def numberAttachments = issue.attachments.findAll {a -> // a.filename.toLowerCase().endsWith(".pdf") // }.size() return numberAttachments ? numberAttachments as Double : null
- Optional: enter an issue key and select Preview to preview this custom script field
- Select Add.
Make sure the Search Template/Searcher for this custom field is Number Searcher.
You can edit the Searcher by selecting the configured searcher on the Script Fields page.
- Configure the context and screens for this custom script field.
Show all previous versions in a given project
You can create a custom script field to display every version in a given project prior to the oldest fix version:
- Enter the name for the custom script field. In this example, we enter Previous Versions.
- Optional: enter a description.
- Optional: add a field note.
- Select the Version Picker template.
Enter the following script into the script editor:
package com.onresolve.jira.groovy.test.scriptfields.scripts import com.atlassian.jira.component.ComponentAccessor import com.atlassian.jira.issue.comparator.VersionComparator def versionManager = ComponentAccessor.getVersionManager() def versions = versionManager.getVersions(issue.projectObject) def comparator = new VersionComparator() def lowestFixVersion = issue.fixVersions.min(comparator) def returnedVersions = versions.findAll { comparator.compare(it, lowestFixVersion) < 0 } log.debug("All prior versions: ${returnedVersions}") (lowestFixVersion ? returnedVersions : null)
The script returns a list ofVersion
objects.- Optional: enter an issue key and select Preview to preview this custom script field
- Select Add.
Make sure the Search Template/Searcher for this custom field is Version Searcher.
You can edit the Searcher by selecting the configured searcher on the Script Fields page.
- Configure the context and screens for this custom script field.
Display an information message
As an admin, you might want to display extra information about an issue, and not be able to search it. You can create a custom script field where your script can output HTML, and you effectively don’t use a velocity template.
In the following example we want to draw attention to an issue when it is blocked by other issues that are not resolved, and not assigned.
- Enter the name for the custom script field. In this example, we enter Blocking Issues Warning.
- Enter a description.
- Optional: add a field note.
- Select the Text Field template.
Enter the following script into the script editor:
In the code below we use a MarkupBuilder, in order to avoid cross-site forgery attacks. In addition, we return null if there are no blocking issues so the field is not displayed at all.
groovyimport com.atlassian.jira.component.ComponentAccessor import groovy.xml.MarkupBuilder import com.atlassian.jira.config.properties.APKeys def blockingIssues = issue.getInwardLinks() .findAll { issueLink -> issueLink.issueLinkType.name == "Blocks" } .collect { issueLink -> issueLink.sourceObject } .findAll { linkedIssue -> !linkedIssue.assignee && !linkedIssue.resolution } if (blockingIssues) { def baseUrl = ComponentAccessor.getApplicationProperties().getString(APKeys.JIRA_BASEURL) def writer = new StringWriter() def builder = new MarkupBuilder(writer) builder.div(class: "aui-message aui-message-error shadowed") { p(class: "title") { strong("This issue is blocked by the following unresolved, unassigned issue(s):") } ul { blockingIssues.each { anIssue -> li { a(href: "$baseUrl/browse/${anIssue.key}", "${anIssue.key}: ${anIssue.summary} (${anIssue.status.name})") } } } } return writer.toString() } else { return null }
- Optional: enter an issue key and select Preview to preview this custom script field
- Select Add.
Make sure the Search Template/Searcher for this custom field is Free Text Searcher.
You can edit the Searcher by selecting the configured searcher on the Script Fields page.
- Configure the context and screens for this custom script field.
The field appears as follows:
Show the component lead
As an admin, you might want to display the lead for the component selected for an issue, making use of the User display template.
- Enter the name for the custom script field. In this example, we enter Component Lead.
- Enter a description.
- Optional: add a field note.
- Select the User Picker (single user) template.
Enter the following script into the script editor:
groovydef components = issue.components if (components) { return components.first().componentLead }
We return a User object, and use the User Picker template so the user is displayed with a clickable link and mouseover popup.
Make sure you return an
ApplicationUser
object and not aUser
. If you do the latter the template will show Anonymous.- Optional: enter an issue key and select Preview to preview this custom script field
- Select Add.
Make sure the Search Template/Searcher for this custom field is User Picker Searcher.
You can edit the Searcher by selecting the configured searcher on the Script Fields page.
- Configure the context and screens for this custom script field.
The field appears as follows:
Show multiple component leads
As an admin, you might want to display all unique component leads for the component selected for an issue:
- Enter the name for the custom script field. In this example, we enter Component Leads.
- Enter a description.
- Optional: add a field note.
- Select the User Picker (multiple users) template.
Enter the following script into the script editor:
groovyissue.components*.componentLead .unique() .findAll()
Optional: enter an issue key and select Preview to preview this custom script field
Select Add.
Make sure the Search Template/Searcher for this custom field is Multi User Picker Searcher.
You can edit the Searcher by selecting the configured searcher on the Script Fields page.
- Configure the context and screens for this custom script field.
The field appears as follows:
Show the work remaining in linked issues
In this example, we create a custom script field to show the work remaining in issues that are blocked by other issues.
Sometimes you may break down tasks by usings a link type, such as Blocks, rather than using subtasks. However, when you do this you can’t see the rolled up remaining estimate. The following custom field shows the amount of time remaining on all issues that this issue is blocked by, and includes any time remaining on the current issue.
The outbound link is is blocked by
and the inbound link is Blocks
. See the Atlassian documentation for Configuring issue linking if you want to create your own custom links.
- Enter the name for the custom script field.
- In this example, we enter Work remaining.
- Enter a description.
- Optional: add a field note.
- Select the Duration (time-tracking) template. This makes the display of the custom field match that of the Estimate field.
Enter the following script into the script editor:
// Sum up estimates of comprising issues. // Inward links are used in this example, // but can be updated to use outward links if required. def sumOfChildIssueEstimates = issue .getInwardLinks { excludeSystemLinks = false } .sum(0) { link -> // If the linked ticket is not the type we want, // do not calculate an estimate for it if (link.issueLinkType.name != "Blocks") { return 0L } // If you replace .getInwardLinks() with .getOutwardLinks(), // you must also replace "sourceObject" with "destinationObject" // Otherwise, you will point back to the target issue def estimate = link.sourceObject.getEstimate() ?: 0L def sumOfSubTasksEstimates = link .sourceObject .subTaskObjects .sum(0) { it.estimate } as long estimate + sumOfSubTasksEstimates } as long def sumOfParentSubTasksEstimates = issue .subTaskObjects .sum(0) { it.estimate ?: 0 } as long // If there are no estimates in the comprising tickets, the result is just the // same as the remaining estimate, so let's not display it. if (!sumOfChildIssueEstimates && !sumOfParentSubTasksEstimates) { return } // Add the estimate from the base ticket. long parentIssueEstimate = issue.getEstimate() ?: 0L parentIssueEstimate + sumOfChildIssueEstimates + sumOfParentSubTasksEstimates
It is important this script returns a
Long
, so that we can search on it.Optional: enter an issue key and select Preview to preview this custom script field
Select Add.
Make sure the Search Template/Searcher for this custom field is Duration Searcher.
You can edit the Searcher by selecting the configured searcher on the Script Fields page.
- Configure the context and screens for this custom script field.
The field appears as follows:
Indexing
You may notice a further problem. When work is logged on one of the linked issues, the issues that link to it don’t get reindexed, so a search won’t return the correct results.
To handle this, we use a custom Script Listener to follow Blocks
links and reindex those issues:
- From ScriptRunner, select the Listeners tab.
- Select Create Listener.
- Select Custom Listener.
- Enter the name for the listener. In this example, we enter Reindex related issues.
- Select the projects for this listener to be applied to
- Select the Issue Updated, Work Logged On Issue, Issue Worklog Updated, and Issue Worklog Deleted events.
Enter one of the following scripts into the editor:
If you use
getInwardsLinks
in the script above, you will want to use thegetOutwardLinks
example below. If you usegetOutwardLinks
in the script above, you will want to use thegetInwardsLinks
example belowgroovyevent.issue.getInwardLinks() { excludeSystemLinks = false } // event is an IssueEvent .each { issueLink -> if (issueLink.issueLinkType.name == "Blocks") { issueLink.getSourceObject().reindex() } }
or
groovyevent.issue.getOutwardLinks() { excludeSystemLinks = false } // event is an IssueEvent .each { issueLink -> if (issueLink.issueLinkType.name == "Blocks") { issueLink.getDestinationObject().reindex() } }
- Select Add.
Show the work remaining in all issues in an epic
In this example, we create a custom script field to show the work remaining in all issues in an epic. We have other requirements for this script field:
- We only want this custom script field to display on Epic issues.
- We want to include sub-tasks of issues in an epic in the total work remaining.
- We want to include any time remaining on the epic itself.
Proceed with the example as follows:
- Enter the name for the custom script field.
- In this example, we enter Work remaining in all issues in this epic.
- Enter a description.
- Optional: add a field note.
- Select the Duration (time-tracking) template. This makes the display of the custom field match that of the Estimate field.
Enter the following script into the script editor:
package com.onresolve.jira.groovy.test.scriptfields.scripts if (issue.issueType.name != "Epic") { return } // Sum up the estimates from comprising issues. def sumOfChildIssueEstimates = issue.getOutwardLinks { excludeSystemLinks = false } .sum(0) { link -> if (link.issueLinkType.name != "Epic-Story Link") { return 0L } def estimate = link.destinationObject.getEstimate() ?: 0L def issueSubtasks = link.destinationObject.subTaskObjects def sumOfSubTasksEstimates = 0L // Include subtask estimates, if any exist if (issueSubtasks) { sumOfSubTasksEstimates = issueSubtasks.sum(0) { subtask -> subtask.getEstimate() } as long } // Failsafe against tickets comprised only of subtask estimates estimate + sumOfSubTasksEstimates } as long // If there are no estimates in the comprising tickets, the result is just the // same as the remaining estimate, so let's not display it. if (!sumOfChildIssueEstimates) { return 0L } // Add the estimate from the base ticket. long parentIssueEstimate = issue.getEstimate() ?: 0L sumOfChildIssueEstimates + parentIssueEstimate
Sub-tasks
We do not include sub-tasks of the epic itself when calculating the work remaining.
It is important this script returns a
Long
, so that we can search on it.Optional: enter an issue key and select Preview to preview this custom script field
Select Add.
Make sure the Search Template/Searcher for this custom field is Duration Searcher.
You can edit the Searcher by selecting the configured searcher on the Script Fields page.
- Configure the context and screens for this custom script field.
The field appears as follows: Optional: If you notice issues with indexing, create a script listener that automatically indexes issues (as described in the Indexing section above).
If you use the script in the Indexing section above, make sure you replace the script with the following:
groovyevent.issue.getInwardLinks { excludeSystemLinks = false } // event is an IssueEvent .each { issueLink -> if (issueLink.issueLinkType.name == "Epic-Story Link") { issueLink.getSourceObject().reindex() } }
Further Examples
Show attachment links in issue navigator: https://answers.atlassian.com/questions/283908/answers/3350560