Advanced cleanup
Support for Server licenses ended on February 15, 2024. Discover your options.
If you have completed your basic cleanup, you can proceed to more advanced cleanup activities. To complete advanced cleanup, you'll need to run a few scripts.
Additional mandatory cleanup process
Recommended frequency: once per year
Skills required: Advanced Jira admin skills
Note: The APIs used in the scripts below might not work with your Jira version. Please make sure to use the correct API compatible with your Jira version. You may refer to our developer documentation for the complete list of the available Java APIs for different Jira versions.
Task 1: Delete any unused or inactive workflows
How do I identify what to clean up?
Use Admin Toolbox for Jira to quickly find inactive workflows.
How do I go about the cleanup?
Delete any inactive or unused workflows and their schemes from the system. Before doing so, make sure that the Validators and Post-functions are not configured with custom fields. Fewer workflows are easier to maintain and support. For more on workflows, see Working with workflows.
The best way to delete inactive workflows and workflow schemes is to get the ScriptRunner app and run the following scripts.
Please note that these feature links and 3rd party plugins are outside our Support Offerings
Start with unused workflow schemes. To delete all inactive workflow schemes, run the script below:
import com.atlassian.jira.component.ComponentAccessor
def schemeManager = ComponentAccessor.workflowSchemeManager
def sb = new StringBuffer()
sb.append("Deleted inactive workflow schemes:\n")
schemeManager.schemeObjects.each {
try{
if(schemeManager.getProjectsUsing(schemeManager.getWorkflowSchemeObj(it.id)).size() == 0) {
schemeManager.deleteScheme(it.id)
sb.append("${it.name}\n")
}
}
catch(Exception e) {
//noop
sb.append("Error: " + e + "\n");
}
}
return "<pre>" + sb.toString() + "<pre>"
To delete unused or inactive workflows, run the following script:
import com.atlassian.jira.component.ComponentAccessor
def workflowManager = ComponentAccessor.workflowManager
def schemeManager = ComponentAccessor.workflowSchemeManager
def sb = new StringBuffer()
sb.append("Deleted inactive workflows:\n")
workflowManager.workflows.each {
if(!it.systemWorkflow) {
def schemes = schemeManager.getSchemesForWorkflow(it)
if (schemes.size() == 0) {
workflowManager.deleteWorkflow(it)
sb.append("${it.name}\n")
}
}
}
return "<pre>" + sb.toString() + "<pre>"
Task 2: Delete unused screens and screen schemes
How do I identify what to clean up?
The ScriptRunner app will help you identify and delete unused screens and screen schemes. Config Insights for Jira that will help you visualize relationships between various Jira artifacts.
It's a good idea not to delete the default screen schemes and default screens.
How do I go about the cleanup?
Delete all Issue Type Screen Schemes without any associated projects:
import com.atlassian.jira.component.ComponentAccessor
def schemeManager = ComponentAccessor.issueTypeScreenSchemeManager
def defaultScheme = schemeManager.defaultScheme;
def sb = new StringBuffer()
sb.append("Deleted issue type screen schemes with no associated projects:\n")
schemeManager.issueTypeScreenSchemes.each {
try{
if(it == defaultScheme) {
//do not delete the default scheme
return;
}
if(it.projects.size() == 0) {
//remove any associations with screen schemes
schemeManager.removeIssueTypeSchemeEntities(it);
//remove the issue type screen scheme
schemeManager.removeIssueTypeScreenScheme(it);
sb.append("${it.name}\n")
}
}
catch(Exception e) {
//noop
sb.append("Error: " + e + "\n");
}
}
return "<pre>" + sb.toString() + "<pre>"
2. Delete Screen Schemes not used by any Issue Type Screen Schemes, or only used by deleted Issue Type Screen Schemes.
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.fields.screen.FieldScreenSchemeManager
def fssm = ComponentAccessor.getComponent(FieldScreenSchemeManager.class)
def itssm = ComponentAccessor.issueTypeScreenSchemeManager
def sb = new StringBuffer()
sb.append("Deleted screen schemes with no associated issue type screen schemes:\n")
fssm.fieldScreenSchemes.each { fss ->
try {
def itssCollection = itssm.getIssueTypeScreenSchemes(fss);
// find field screen schemes that are still associated with deleted issues type screen schemes
def allDeleted = true;
itssCollection.each { itss ->
if(itss != null) {
allDeleted = false;
return;
}
}
//remove field screen schemes with no (valid) associated issue type screen schemes
if(itssCollection.size() == 0 || allDeleted == true) {
//remove association to any screens
fssm.removeFieldSchemeItems(fss);
//remove field screen scheme
fssm.removeFieldScreenScheme(fss);
sb.append("${fss.name}\n");
}
}
catch(Exception e) {
//noop
sb.append("Error: " + e + "\n");
}
}
return "<pre>" + sb.toString() + "<pre>"
3. Delete unused screens. Note that the code differs, depending on your Jira version:
If you're using Jira 8.20 or later, run the code below.
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.fields.screen.FieldScreenFactory
import com.atlassian.jira.issue.fields.screen.FieldScreenManager
import com.atlassian.jira.issue.fields.screen.FieldScreenSchemeManager
import com.atlassian.jira.bc.issue.fields.screen.FieldScreenService
import com.atlassian.jira.web.action.admin.issuefields.screens.ViewFieldScreens
import com.atlassian.jira.workflow.WorkflowManager
import com.atlassian.webresource.api.assembler.PageBuilderService
def fieldScreenManager = ComponentAccessor.getFieldScreenManager()
def fieldScreenFactory = ComponentAccessor.getComponent(FieldScreenFactory.class)
def fieldScreenSchemeManager = ComponentAccessor.getComponent(FieldScreenSchemeManager.class)
def fieldScreenService = ComponentAccessor.getComponent(FieldScreenService.class)
def workflowManager = ComponentAccessor.getWorkflowManager()
def authenticationContext = ComponentAccessor.getJiraAuthenticationContext()
def pageBuilderService = ComponentAccessor.getComponent(PageBuilderService.class)
def viewFieldScreens = new ViewFieldScreens(fieldScreenManager, fieldScreenFactory, fieldScreenSchemeManager, fieldScreenService,
workflowManager, authenticationContext, pageBuilderService)
// use StringBuffer to spit out log to screen for ScriptRunner Console
def sb = new StringBuffer()
sb.append("Delete unused screens:\n");
fieldScreenManager.getFieldScreens().each {
fieldScreen ->
//find all screens with no (or only null/previously deleted) screen schemes or workflows
def allEmptyOrNull = true;
viewFieldScreens.getFieldScreenSchemes(fieldScreen).each {
fieldScreenScheme ->
if (fieldScreenScheme != null) {
allEmptyOrNull = false;
return;
}
}
if (!allEmptyOrNull) {
return;
}
viewFieldScreens.getWorkflows(fieldScreen).each {
workflow ->
if (workflow != null) {
allEmptyOrNull = false;
return;
}
}
if (allEmptyOrNull) {
fieldScreenManager.removeFieldScreen(fieldScreen.getId())
sb.append("${fieldScreen.getName()}\n")
}
}
return "<pre>" + sb.toString() + "<pre>"
If you're using a version earlier than Jira 8.20, run the code below.
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.fields.screen.FieldScreenFactory
import com.atlassian.jira.issue.fields.screen.FieldScreenManager
import com.atlassian.jira.issue.fields.screen.FieldScreenSchemeManager
import com.atlassian.jira.web.action.admin.issuefields.screens.ViewFieldScreens
import com.atlassian.jira.workflow.WorkflowManager
def fieldScreenManager = ComponentAccessor.getFieldScreenManager()
def fieldScreenFactory = ComponentAccessor.getComponent(FieldScreenFactory.class)
def fieldScreenSchemeManager = ComponentAccessor.getComponent(FieldScreenSchemeManager.class)
def workflowManager = ComponentAccessor.getWorkflowManager()
def viewFieldScreens = new ViewFieldScreens(fieldScreenManager, fieldScreenFactory, fieldScreenSchemeManager, workflowManager)
// use StringBuffer to spit out log to screen for ScriptRunner Console
def sb = new StringBuffer()
sb.append("Delete unused screens:\n");
fieldScreenManager.getFieldScreens().each { fieldScreen ->
//find all screens with no (or only null/previously deleted) screen schemes or workflows
def allEmptyOrNull = true;
viewFieldScreens.getFieldScreenSchemes(fieldScreen).each { fieldScreenScheme ->
if(fieldScreenScheme != null) {
allEmptyOrNull = false;
return;
}
}
if(!allEmptyOrNull) {
return;
}
viewFieldScreens.getWorkflows(fieldScreen).each { workflow ->
if(workflow != null) {
allEmptyOrNull = false;
return;
}
}
if(allEmptyOrNull) {
fieldScreenManager.removeFieldScreen(fieldScreen.getId())
sb.append("${fieldScreen.getName()}\n")
}
}
return "<pre>" + sb.toString() + "<pre>"
Task 3: Review resolutions
Resolutions in Jira are shared globally—consolidating them whenever possible will reduce clutter.
How do I identify what to clean up?
Run a JQL query such as "Resolution = 'whatever'" to find how many issues (if any) use a particular resolution.
You can also create an issue statistics gadget grouping a JQL query by Resolution. For more on gadgets, see Using dashboards gadgets.
How do I go about the cleanup?
From the Resolutions page in the administration panel, click Delete on the resolution you wish to get rid of. Jira will tell you how many issues currently have that resolution and also ask you to pick a different resolution from the list for those issues.
Task 4: Clean up field configurations
Field Configuration tells Jira which fields are available to each Project (and Issuetype). Even if the fields aren't present in any screen, they are considered in the reindex process.
By default, Jira adds every newly created custom field to all Field Configurations available. So the performance might decline if you have a lot of custom fields.
How do I identify what to clean up?
For this task, you don't have to delete things, but hide the custom fields and enable only the ones you want for a project. So, this is a fairly safe way of cleaning up.
How do I go about the cleanup?
Create an "empty" Field Configuration (FC) with no fields associated with it. Use it as a template, and add all your custom fields to this configuration, and disable those. When you create new projects, you can enable only the desired fields you want to use in these projects (or issue types).
Next use the ScriptRunner app and run the following script. It will make all custom fields in a particular Field Configuration hidden, which, in turn, will make them invisible and not editable in all Projects that use that field configuration.
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.fields.layout.field.FieldLayoutManager
import com.atlassian.jira.issue.fields.layout.field.EditableFieldLayout
import com.atlassian.jira.issue.fields.layout.field.FieldLayoutItem
FieldLayoutManager fieldConfigurationManager = ComponentAccessor.getComponent(FieldLayoutManager)
EditableFieldLayout fieldConfiguration = fieldConfigurationManager.getEditableFieldLayout(18000L)
List<FieldLayoutItem> items = fieldConfiguration.getFieldLayoutItems()
items.each {
try {
fieldConfiguration.hide(it)
} catch (ignored) {}
}
fieldConfigurationManager.storeEditableFieldLayout(fieldConfiguration)
Task 5: Audit your apps
Uninstalling unused apps will help keep your Jira from using unnecessary RAM, keep your marketplace costs down, and save you time upgrading them to newer versions.
How do I identify what to clean up?
Unfortunately, apps vary widely in the way they work, and it's not really possible to determine how they're getting used in a one-size-fits-all approach.
The best idea is to manually check each app for usage.
How do I go about the cleanup?
Disable the apps with low usage and/or the ones you have doubts about in the test environment and observe the outcomes.
How do I automate?
For each of the tasks, it's a good idea to monitor for new entities being created (Advanced audit log can help here) and run regular reviews.