It's not the same without you

Join the community to find out what other Atlassian users are discussing, debating and creating.

Atlassian Community Hero Image Collage

Continuous cleanup for Jira. Part 2.

Hi awesome community! 

 

This is the second iteration from series of article about Continuous Jira cleanup which I have tried to implement automation scripts for my Jira instance. (first one here)

Today, I would like to share a few scripts related to clean up configuration of the project. 

 

Disclaimer,  as usual, everything should be tested in the test-environment first.

Also, I'll be happy if you share or provide advice for the related small scripts. All scripts were tested and executed on Jira 7 Server releases (7.6.10, 7.13.0).

Well, you can use for execute groovy on Jira one of these apps (add-ons) - Scriptrunner for Jira (commercial) , MyGroovy (Opensource BSD-2) , Groovioli (Opensource BSD-2)

 

And scripts based on this scheme

image.png

 

Well, let's next step is cleanup our Jira instance.

 

1. Cleanup UnAssociated Issue Type

boolean isPreview = true

import
com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.config.IssueTypeManager
import org.apache.log4j.Logger
import org.apache.log4j.Level

def log = Logger.getLogger("com.gonchik.scripts.groovy.cleanupUnAssociatedIssueType")
log.setLevel(Level.DEBUG)

// Cleanup of the cleanupUnAssociatedIssueType
def issueTypeManager = ComponentAccessor.getComponent(IssueTypeManager)
def sb = new StringBuilder()

sb.append("Deleted issue type schemes with no associated projects:<br/><br/>\n")
issueTypeManager.issueTypes.each {
try {
if (!issueTypeManager.hasAssociatedIssues(it)) {
sb.append("${it.name}<br/>\n")
if (!isPreview) {
// Set the Default of Task Id
String replaceIssueTypeId = "1"
if (it.isSubTask()){
// Id of Sub-Task
replaceIssueTypeId = "5"
}
issueTypeManager.removeIssueType(it.id, replaceIssueTypeId)
}
}
}
catch (Exception e) {
sb.append("Error: " + e + "<br/>\n")
}
}

return sb.toString()

 

2. Cleanup unused Issue Type Schemes.

boolean isPreview = false
import com.atlassian.jira.component.ComponentAccessor
import org.apache.log4j.Logger
import org.apache.log4j.Level

def log = Logger.getLogger("com.gonchik.scripts.groovy.cleanupUsUsedIssueTypeSchemes")
log.setLevel(Level.DEBUG)

def schemeManager = ComponentAccessor.issueTypeSchemeManager
def sb = new StringBuilder()

sb.append("Deleted issue type schemes with no associated projects:<br/><br/>\n")
schemeManager.allSchemes.each {
if (schemeManager.isDefaultIssueTypeScheme(it)){
return
}
try {
if (it.associatedProjectIds.size() == 0) {
sb.append("${it.name}<br/>\n")
if (!isPreview) {
schemeManager.deleteScheme(it)
}
}
}
catch (Exception e) {
sb.append("Error: " + e + "<br/>\n")
}
}

return sb.toString()

 

3. Cleanup Issue Type Screen Schemes.

boolean isPreview = true
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.fields.screen.issuetype.IssueTypeScreenSchemeManager
import org.apache.log4j.Logger
import org.apache.log4j.Level

def log = Logger.getLogger("com.gonchik.scripts.groovy.cleanupUsUsedIssueTypeScreenManager")
log.setLevel(Level.DEBUG)

def schemeManager = ComponentAccessor.issueTypeScreenSchemeManager
def sb = new StringBuilder()

sb.append("Deleted issue type screen schemes with no associated projects:<br/><br/>\n")
schemeManager.issueTypeScreenSchemes.each {
if (it.isDefault()) {
return
}
try {
if (schemeManager.getProjects(it).size() < 1) {
sb.append("${it.name}<br/>\n")
if (!isPreview) {
schemeManager.removeIssueTypeScreenScheme(it)
}
}
}
catch (Exception e) {
sb.append("Error: " + e + "<br/>\n")
}
}

return sb.toString()

 

4. Cleanup Un Associated Issue Type Screen

boolean isPreview = true

import
com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.fields.screen.issuetype.IssueTypeScreenSchemeManager
import org.apache.log4j.Logger
import org.apache.log4j.Level

def log = Logger.getLogger("com.gonchik.scripts.groovy.cleanupUnAssociatedIssueTypeScreen")
log.setLevel(Level.DEBUG)

def schemeManager = ComponentAccessor.issueTypeScreenManager
def sb = new StringBuilder()

sb.append("Deleted issue type screen schemes with no associated projects:<br/><br/>\n")
schemeManager.issueTypeScreenSchemes.each {
if (it.isDefault()) {
return
}
try {
if (schemeManager.getProjects(it).size() == 0) {
sb.append("${it.name}<br/>\n")
if (!isPreview) {
schemeManager.removeIssueTypeScreenScheme(it)
}
}
}
catch (Exception e) {
sb.append("Error: " + e + "<br/>\n")
}
}

return sb.toString()

 

5. Cleanup unused Field Screens.

boolean isPreview = true

import
com.atlassian.jira.component.ComponentAccessor
import org.apache.log4j.Logger
import org.apache.log4j.Level

def log = Logger.getLogger("com.gonchik.scripts.groovy.cleanupUnUsedFieldScreens")
log.setLevel(Level.DEBUG)

def schemeManager = ComponentAccessor.fieldScreenSchemeManager
def sb = new StringBuilder()

sb.append("Deleted issue type screen schemes with no associated projects:<br/><br/>\n")
schemeManager.fieldScreenSchemes().each {
if (it.isDefault()) {
return
}
try {
if (schemeManager.getProjects(it).size() == 0) {
sb.append("${it.name}<br/>\n")
if (!isPreview) {
schemeManager.removeFieldScreenScheme(it)
}
}
}
catch (Exception e) {
sb.append("Error: " + e + "<br/>\n")
}
}

return sb.toString()

 

 

 

And last one is cleanup un associated workflow schemes and workflows:

boolean isPreview = true
import com.atlassian.jira.component.ComponentAccessor
import org.apache.log4j.Logger
import org.apache.log4j.Level


def log = Logger.getLogger("com.gonchik.scripts.groovy.deleteUnUsedWorkflows")
log.setLevel(Level.DEBUG)

def workflowManager = ComponentAccessor.workflowManager
def schemeManager = ComponentAccessor.workflowSchemeManager
def sb = new StringBuilder()

// Review workflow schemes
schemeManager.schemeObjects.each {
try {
if (schemeManager.getProjectsUsing(schemeManager.getWorkflowSchemeObj(it.id)).size() == 0) {
sb.append("${it.name}<br/>\n")
if (!isPreview) {
log.info("Deleting workflow scheme: ${it.name}")
schemeManager.deleteScheme(it.id)
}
}
}
catch (Exception e) {
log.error('Something wrong, ' + e)
sb.append("Error: " + e + "<br/>\n")
}
}

// review Workflows
workflowManager.workflows.each {
if (!it.systemWorkflow) {
def schemes = schemeManager.getSchemesForWorkflow(it)
if (schemes.size() == 0) {
sb.append("${it.name}<br/>\n")
if (!isPreview) {
log.info("Deleting workflow: ${it.displayName}")
workflowManager.deleteWorkflow(it)
}
}
}
}

return sb.toString()

  

I hope these short scripts will reduce your manual work.

Have a nice experiments. :)

P.S. All related code you can find bitbucket repo or github repo

P.S.S Next article will related to the comparing the configs. 

P.S.S.S. After that I will show how to find same configs with predefined distance of next configs. (Levenshtein distance)  

 

Cheers,

Gonchik Tsymzhitov

9 comments

Hey Gonchik,

Great work on both parts of your articles - will be trying them out.

Wondering if you may consider a part 3 with any of the following:

- removing users/groups from a project role where that role does nothing (no permissions, notifications, use in workflow conditions etc)

- identifying use of groups (if a group is to be deprecated or renamed etc). There’s so many locations used within core/software/JSD, let alone the marketplace apps

 

CCM

tom lister Community Leader Feb 09, 2019

Hi @Gonchik Tsymzhitov

this could save me many hours as I’ve inherited a Jira instance at my new job with dozens and dozens of orphaned schemes.

will definitely be looking into open source groovy runners too.

Hi @tom lister

I am happy if it helps you and feel free fork and time to time provide Pull Request:))

 

Cheers,

Gonchik Tsymzhitov

tom lister Community Leader Feb 13, 2019

Hi

In 4. Cleanup Un Associated Issue Type Screen

I had to change this line 

def schemeManager = ComponentAccessor.issueTypeScreenSchemeManager

tom lister Community Leader Feb 13, 2019

Ignore the above, versions in github are good

After reading Part 1, I had to find the other.  I've bookmarked both articles for future reference.  Thank you for sharing!

Welcome to use it :) 

Hi @Gonchik Tsymzhitov 

Thanks for sharing scripts :)

I need to do the same for Confluence, any idea?

Hi @Gonchik Tsymzhitov 

 

Could you please provide a script to remove the  inactive status in jira, i tried a lot but it doesn't seems to be working as expected.

Thanks

Comment

Log in or Sign up to comment
TAGS

Community Events

Connect with like-minded Atlassian users at free events near you!

Find an event

Connect with like-minded Atlassian users at free events near you!

Unfortunately there are no Community Events near you at the moment.

Host an event

You're one step closer to meeting fellow Atlassian users at your local event. Learn more about Community Events

Events near you