How to find all JIRA filters that include JQL for a custom field value

Dale Wolfe
Contributor
February 19, 2018

Use case: I want to remove an old custom field value (or convert the old value into a new value). 

However, I need to see if that change would cause any JIRA filters including Board Quick Filter errors.

 

 

4 answers

1 accepted

3 votes
Answer accepted
Jonny Carter
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
February 20, 2018

Bit late to the party, but wanted to provide an answer I'd cooked up for a similar question:

import com.atlassian.jira.bc.issue.search.SearchService
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.search.SearchRequestEntity
import com.atlassian.jira.issue.search.SearchRequestManager
import com.atlassian.jira.util.Visitor

def filtersWithField = []
def myCustomFieldRegex = ~/(.*?Whatever You Call This Field.*?)|(.*?cf\[12345\].*?)/
def searchService = ComponentAccessor.getComponent(SearchService)
def searchRequestManager = ComponentAccessor.getComponent(SearchRequestManager)
searchRequestManager.visitAll(new Visitor<SearchRequestEntity>() {
@Override
void visit(SearchRequestEntity filter) {
def jql = filter.request
if (jql.findAll(myCustomFieldRegex)) {
/*
You don't have to get the search request object
as I am doing here. However, if you want to programatically
update search requests, you'll need to get the SearchRequest object itself, as I'm doing here. The SearchRequestEntity is a bit quicker to get, so I'm using that for this loop that iterates through the
entire list of saved filters.
*/
filtersWithField << searchRequestManager.getSearchRequestById(filter.id)
}
}
})
log.warn filtersWithField

You'll need to tweak the regular expression in the second line of code to match your custom field. Note that I've accounted for both the case where someone uses the custom field name in a query and where they reference it by ID.

The main difference between this and Daniel's is that instead of looping through the users and checking their owned filters, this uses the SearchRequestManager to loop through all saved searches directly.

I'm pretty sure the quick filters used on Jira Software Boards require their own treatment, but see the examples at https://scriptrunner.adaptavist.com/latest/jira/plugins/working-with-jira-agile.html for a starting point on looping through boards.

Ram August 4, 2023

Hi All,

I trying the same script, but its not yielding any result, can you please help?

import com.atlassian.jira.bc.issue.search.SearchService
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.search.SearchRequestEntity
import com.atlassian.jira.issue.search.SearchRequestManager
import com.atlassian.jira.util.Visitor

def filtersWithField = []
def myCustomFieldRegex = ~/(.Mobile OS.)|(.cf\[10801\].)/
def searchService = ComponentAccessor.getComponent(SearchService)
def searchRequestManager = ComponentAccessor.getComponent(SearchRequestManager)
searchRequestManager.visitAll(new Visitor<SearchRequestEntity>() {
@Override
void visit(SearchRequestEntity filter) {
def jql = filter.request
if (jql.findAll(myCustomFieldRegex)) {
filtersWithField << searchRequestManager.getSearchRequestById(filter.id)
}
}
})
log.warn filtersWithField

Like Shane Garner likes this
2 votes
Daniel Garcia
Contributor
February 19, 2018

The following groovy script (run it in scriptrunner console) should help

 

import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.bc.filter.SearchRequestService
import com.atlassian.jira.issue.search.SearchRequest
import com.atlassian.jira.bc.user.search.UserSearchParams
import com.atlassian.jira.bc.user.search.UserSearchService
import java.lang.StringBuilder

// Change these 2 constants to the values you want to search for
Integer CUSTOM_FIELD_ID = 12345
String CUSTOM_FIELD_NAME = 'My Custom Field'


SearchRequestService searchRequestService = ComponentAccessor.getComponent(SearchRequestService.class)
UserSearchService userSearchService = ComponentAccessor.getComponent(UserSearchService)
StringBuilder output = StringBuilder.newInstance()
output << "<pre>\n"

UserSearchParams userSearchParams = new UserSearchParams.Builder()
    .allowEmptyQuery(true)
    .ignorePermissionCheck(true)
    .maxResults(10000)
    .build()
userSearchService.findUsers("", userSearchParams).each{ApplicationUser filter_owner ->
    searchRequestService.getOwnedFilters(filter_owner).each{SearchRequest filter->
        String jql = filter.getQuery().toString()
        if (jql.contains(CUSTOM_FIELD_NAME) || jql.contains("cf[${CUSTOM_FIELD_ID}]")) {
            output << "${filter_owner.displayName}, ${filter.name}, ${filter.getPermissions().isPrivate() ? 'Private' : 'Shared'}, ${jql}\n"
        }
    }
}

output << "</pre>"
output.toString()

It isn't perfect as it would also match filters with your field name in search string (e.g. description ~ "my custom field is awesome") but for most purposes it should do what you want

Dale Wolfe
Contributor
February 19, 2018

I receive an error when attempting to run that script:

ScriptConsole.jpg

I was able to execute the following script (via Jonny Carter):

import com.atlassian.jira.bc.issue.search.SearchService
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.search.SearchRequestEntity
import com.atlassian.jira.issue.search.SearchRequestManager
import com.atlassian.jira.util.Visitor

def filtersWithField = []
def myCustomFieldRegex = ~/(.*?Whatever You Call This Field.*?)|(.*?cf\[12345\].*?)/
def searchService = ComponentAccessor.getComponent(SearchService)
def searchRequestManager = ComponentAccessor.getComponent(SearchRequestManager)
searchRequestManager.visitAll(new Visitor<SearchRequestEntity>() {
    @Override
    void visit(SearchRequestEntity filter) {
        def jql = filter.request
        if (jql.findAll(myCustomFieldRegex)) {
            /*
            You don't have to get the search request object
            as I am doing here. However, if you want to programatically
            update search requests, you'll need to get the SearchRequest object itself, as I'm doing here. The SearchRequestEntity is a bit quicker to get, so I'm using that for this loop that iterates through the
            entire list of saved filters.
             */
            filtersWithField << searchRequestManager.getSearchRequestById(filter.id)
        }
    }
})
log.warn filtersWithField

Dale Wolfe
Contributor
February 19, 2018

However, it appears to only scan system-based filters.  Is it also possible to scan board quick filters too?

Daniel Garcia
Contributor
February 19, 2018

It looks like a permission problem to me

Daniel Garcia
Contributor
February 19, 2018

This version should be more robust and will display what it can. It will also tell you which users it is having trouble with

import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.bc.filter.SearchRequestService
import com.atlassian.jira.issue.search.SearchRequest
import com.atlassian.jira.bc.user.search.UserSearchParams
import com.atlassian.jira.bc.user.search.UserSearchService
import java.lang.StringBuilder

// Change these 2 constants to the values you want to search for
Integer CUSTOM_FIELD_ID = 12345
String CUSTOM_FIELD_NAME = 'Field name'


SearchRequestService searchRequestService = ComponentAccessor.getComponent(SearchRequestService.class)
UserSearchService userSearchService = ComponentAccessor.getComponent(UserSearchService)
StringBuilder output = StringBuilder.newInstance()
output << "<pre>\n"

UserSearchParams userSearchParams = new UserSearchParams.Builder()
    .allowEmptyQuery(true)
    .ignorePermissionCheck(true)
    .maxResults(10000)
    .build()
userSearchService.findUsers("", userSearchParams).each{ApplicationUser filter_owner ->
    try {
        searchRequestService.getOwnedFilters(filter_owner).each{SearchRequest filter->
            String jql = filter.getQuery().toString()
            if (jql.contains(CUSTOM_FIELD_NAME) || jql.contains("cf[${CUSTOM_FIELD_ID}]")) {
                output << "${filter_owner.displayName}, ${filter.name}, ${filter.getPermissions().isPrivate() ? 'Private' : 'Shared'}, ${jql}\n"
            }
        }
    } catch (Exception e) {
           output << "Unable to get filters for ${filter_owner.displayName} due to ${e}"     
    }
}

output << "</pre>"
output.toString()
Like arama mihai likes this
Wayne Cranford July 22, 2019

Others may know, but we needed this capability for Components and the simple change worked great:

if (jql.contains(CUSTOM_FIELD_NAME) || jql.contains("cf[${CUSTOM_FIELD_ID}]"))

to 

if (jql.contains('component/s') || jql.contains("component entry")) {

 We are using JIRA v7.4.4 and Script Runner v5.3.5, 

Bogdan Titu
I'm New Here
I'm New Here
Those new to the Atlassian Community have posted less than three times. Give them a warm welcome!
January 31, 2022

Hi Daniel,

 

Can this script be adapted to list all the workflows where a custom filed is mentioned (eg there is a post function having the field as mandatory)?

 

Thank you

0 votes
Alexander Allen October 27, 2020

Is there any way to do this without having scriptrunner? Or does anyone know of a feature request submitted to Atlassian for this ability?

0 votes
Antonina Khirnaya March 19, 2020

For anyone still interested in this functionality:

The Subscriptions for Jira app allows Jira admin to find all filters by a piece of JQL (almost like a regular text search but within JQL-queries).

Suggest an answer

Log in or Sign up to answer
TAGS
AUG Leaders

Atlassian Community Events