How make a transition depending on the issue types in a version

Ignacio Flores September 8, 2020
Hello community! Im Ignacio, Jira Admin
To give the context a bit, it's the following:

In a project A *, we will store issues of the "Deployment" type, these issues will have a custom field where a version number related to a project B * will be entered at the time of finalizing the issue.

In project B we will find issues of the types:

Task x
Task y
Task z
Task i

Our client requires that, for example, when entering the version number related to project B in our project A, it validates that the issue types contained in the version of project B are "Task x, Task y and Task z ", then the system must allow ending the issue of project A. For example, if it were the case that the validation will find only issues of the type" Task z, Task i ", should not let the transition take place.

I couldn't find anything like it in the community forums, your help would be greatly appreciated.

We have Scriptrunner!

Actually I Have This

Hello Gustavo! Look at this is what I have at the moment. I'm getting the version id saved in the "" Project / Releases "field. As a test, the id is being saved as a comment within the problem, to validate that the postfunction is working correctly. What I am having trouble with is how to get? With that "version id" obtained, go to find the topics it contains and validate if there are the issuetype that I require in order to advance in the transition. Do you know if it is possible to pass a variable in a JQL or SQL query in jira? Thank you very much for your help!

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.user.util.UserUtil
import org.apache.log4j.Level
import org.apache.log4j.Logger
import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.ComponentManager
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.comments.CommentManager

def log = Logger.getLogger("com.acme.workflows")
log.setLevel(Level.DEBUG)


def customField = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("Proyecto/Releases")
Issue issueKey = issue
// Get the current logged in user
def CurrentUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()displayName

// Get access to the Jira comment and component manager
CommentManager commentManager = ComponentAccessor.getCommentManager()
ComponentManager componentManager = ComponentManager.getInstance()
def issueManager = ComponentAccessor.issueManager
// Get the last comment entered in on the issue to a String


def value = (String) issue.getCustomFieldValue(customField)
def comment = value
if(value !=null)
{
commentManager.create(issueKey, CurrentUser,comment, true)
}

log.info("the version selected is" + value)

 

 

 

1 answer

1 accepted

0 votes
Answer accepted
Gustavo Félix
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.
September 8, 2020

Hi @Ignacio Flores 
If I understood you , doing a jql like "project = B and fixVersion = version1" , would give you all the issues that have that version. 

So, inside your code(from A) , you could execute a jql that will return you those issues. You could iterate the results, and check if all your issue types are present.

e.g. as a pseudocode 
def version = someCustomFieldValue
results = executeJql("project = B and fixVersion = version")
boolean isTaskXPresent= false
boolean isTaskYPresent= false
boolean finalizeIssue = false;
for(Issue issue : results){
    if(issue.type=="Task X "){
         isTaskXPresent= true
    }
   else
   if(issue.type=="Task Y "){
         isTaskYPresent= true
    }
    if(isTaskXPresent&&isTaskYPresent)
    finalizeIssue = true
    break;
    }

if(finalizeIssue){
issue.setVersion(version)
}else{
error
}
}

I'm not sure if this is the best way to do it ,but it's an idea to work with.
Hope that helps you.

Ignacio Flores September 9, 2020

@Gustavo Félix 
Disculpa gustavo, eres chileno ? de ser asi podriamos intercambiar algunas palabras ? +569 64940994

Gustavo Félix
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.
September 9, 2020

@Ignacio Flores No soy chileno, pero cualquier duda me la puedes dejar por aquí .

Ignacio Flores September 21, 2020

@Gustavo Félix 

Hola Gustavo!

De momento esto es lo que tengo:

Mediante el codigo obtengo el id de la versión guardado en el campo "Proyecto/Release".

Para probar que la postfunction esta trabajando correctamente, estoy guardando el "ID de la versión" en un comentario al momento de ejecutar el script.

¿Como puedo realizar una busqueda de los issues con ell "id de version" encontrado y así verificar que issue types se encuentran dentro? ¿Sera posible usar variables de codigo en un JQL o SQL query ?

Muchas gracias por tu ayuda!

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.user.util.UserUtil
import org.apache.log4j.Level
import org.apache.log4j.Logger
import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.ComponentManager
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.comments.CommentManager

def log = Logger.getLogger("com.acme.workflows")
log.setLevel(Level.DEBUG)


def customField = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("Proyecto/Releases")
Issue issueKey = issue
// Get the current logged in user
def CurrentUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()displayName

// Get access to the Jira comment and component manager
CommentManager commentManager = ComponentAccessor.getCommentManager()
ComponentManager componentManager = ComponentManager.getInstance()
def issueManager = ComponentAccessor.issueManager
// Get the last comment entered in on the issue to a String


def value = (String) issue.getCustomFieldValue(customField)
def comment = value
if(value !=null)
{
commentManager.create(issueKey, CurrentUser,comment, true)
}

log.info("the Version selected is" + value)

Ignacio Flores September 21, 2020

@Gustavo Félix 

Hola Gustavo!

De momento esto es lo que tengo:

Mediante el codigo obtengo el id de la versión guardado en el campo "Proyecto/Release".

Para probar que la postfunction esta trabajando correctamente, estoy guardando el "ID de la versión" en un comentario al momento de ejecutar el script.

¿Como puedo realizar una busqueda de los issues con ell "id de version" encontrado y así verificar que issue types se encuentran dentro? ¿Sera posible usar variables de codigo en un JQL o SQL query ?

Muchas gracias por tu ayuda!

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.user.util.UserUtil
import org.apache.log4j.Level
import org.apache.log4j.Logger
import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.ComponentManager
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.comments.CommentManager

def log = Logger.getLogger("com.acme.workflows")
log.setLevel(Level.DEBUG)


def customField = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("Proyecto/Releases")
Issue issueKey = issue
// Get the current logged in user
def CurrentUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()displayName

// Get access to the Jira comment and component manager
CommentManager commentManager = ComponentAccessor.getCommentManager()
ComponentManager componentManager = ComponentManager.getInstance()
def issueManager = ComponentAccessor.issueManager
// Get the last comment entered in on the issue to a String


def value = (String) issue.getCustomFieldValue(customField)
def comment = value
if(value !=null)
{
commentManager.create(issueKey, CurrentUser,comment, true)
}

log.info("the version selected is" + value)

Ignacio Flores September 21, 2020

@Gustavo Félix 

De momento esto es lo que tengo:

Mediante el codigo obtengo el id de la versión guardado en el campo "Proyecto/Release".

Para probar que la postfunction esta trabajando correctamente, estoy guardando el "ID de la versión" en un comentario al momento de ejecutar el script.

¿Como puedo realizar una busqueda de los issues con ell "id de version" encontrado y así verificar que issue types se encuentran dentro? ¿Sera posible usar variables de codigo en un JQL o SQL query ?

Muchas gracias por tu ayuda!

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.user.util.UserUtil
import org.apache.log4j.Level
import org.apache.log4j.Logger
import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.ComponentManager
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.comments.CommentManager

def log = Logger.getLogger("com.acme.workflows")
log.setLevel(Level.DEBUG)


def customField = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("Proyecto/Releases")
Issue issueKey = issue
// Get the current logged in user
def CurrentUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()displayName

// Get access to the Jira comment and component manager
CommentManager commentManager = ComponentAccessor.getCommentManager()
ComponentManager componentManager = ComponentManager.getInstance()
def issueManager = ComponentAccessor.issueManager
// Get the last comment entered in on the issue to a String


def value = (String) issue.getCustomFieldValue(customField)
def comment = value
if(value !=null)
{
commentManager.create(issueKey, CurrentUser,comment, true)
}

log.info("the version selected is" + value)

Ignacio Flores September 21, 2020

chek

Gustavo Félix
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.
September 21, 2020

import com.atlassian.jira.issue.search.SearchProvider
import com.atlassian.jira.jql.parser.JqlQueryParser
import com.atlassian.jira.web.bean.PagerFilter
import com.atlassian.jira.bc.issue.search.SearchService

Con este código deberías poder ejecutar el queryJql que necesites. Esto te devolverá una lista de issues ("results") que vas a iterar con el "each"

Espero te funcione.

def queryJql = "project= TuProyecto and fixVersion=TuVersion" 
SearchService searchService = ComponentAccessor.getComponent(SearchService.class)
SearchService.ParseResult parseResult = searchService.parseQuery(user,queryJql)
def searchResult = searchService.search(user,parseResult.getQuery(),PagerFilter.getUnlimitedFilter())
List<Issue> results = searchResult.getResults()
results.each{ tempIssue ->
def issueType = issue.getIssueType().getName()
//Aquí agregas lo que necesites validar con los issueTypes
}

Ignacio Flores September 22, 2020

@Gustavo Félix 

Gustavo muchas gracias por tu ayuda funciono perfectamente!

Ahora tengo algunas preguntas ?

Desde la siguiente línea de código que va a rescatar los tipos de issues dentro de una version seleccionada:

def issueType = issue.getIssueType().getName()
if (issue.getIssueType().getName().equals("Modelo de Datos") || issue.getIssueType().getName().equals("Hacking etico"))
{
return true
}
else
{
return false
}

Para esta casuística, estamos utilizando una version que contiene dentro 5 issues (1 de hacking etico/ 1 de Modelo de Datos/ 1 Historia usuario/ 2 Calidad Técnica).

El script me esta retornando los valores: [false, true, true, false, false] Lo cual esta correcto según el código mencionado.

Mi pregunta es, ¿Cómo puedo condicionar que cuando el código me devuelva esos dos valores "true" (Tienen que ser los 2 true, no basta uno solo) se guarde en un campo que se llamara Aprobación con el valor: Aprobado? y en caso de que solo encuentre un "True" o ninguno, me guarde el valor: Sin tareas QA.

Te dejo el código completo, muchas gracias por tu ayuda ha sido demasiado util!

import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.jql.parser.JqlQueryParser;
import com.atlassian.jira.issue.search.SearchProvider;
import com.atlassian.jira.web.bean.PagerFilter;
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.fields.config.FieldConfig
import com.atlassian.jira.issue.context.IssueContextImpl
import com.atlassian.jira.issue.customfields.manager.OptionsManager
import com.atlassian.jira.issue.customfields.option.Options
import com.atlassian.jira.issue.customfields.option.Option
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import org.apache.log4j.Level
import com.atlassian.jira.issue.Issue
import org.apache.log4j.Logger

def log = Logger.getLogger("com.acme.workflows")
log.setLevel(Level.DEBUG)


def findIssues(String jqlQuery) {
def issueManager = ComponentAccessor.issueManager
def user = ComponentAccessor.jiraAuthenticationContext.getLoggedInUser()
def jqlQueryParser = ComponentAccessor.getComponent(JqlQueryParser.class)
def searchProvider = ComponentAccessor.getComponent(SearchProvider.class)
def query = jqlQueryParser.parseQuery(jqlQuery)
def results = searchProvider.search(query, user, PagerFilter.unlimitedFilter)
results.issues.collect {
issue -> issueManager.getIssueObject(issue.id)
def issueType = issue.getIssueType().getName()
if (issue.getIssueType().getName().equals("Modelo de Datos") || issue.getIssueType().getName().equals("Hacking etico"))
{
return true
}
else
{
return false
}
}
}
//def user = ComponentAccessor.jiraAuthenticationContext.userCustomField
CustomField cf1 = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("Proyecto/Releases")
def jqlQuery = "fixVersion =11827"
def issues = findIssues(jqlQuery)
log.info(issues)

Gustavo Félix
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.
September 23, 2020

A ver, si te entendí ...
boolean findIssues(String jqlQuery) {
...
...
...
int trueCount = 0;
if (issue.getIssueType().getName().equals("Modelo de Datos") || issue.getIssueType().getName().equals("Hacking etico"))
{
trueCount++;
}
else{...}
...
if (trueCount >=2){
return true;
}else{
return false
}

y ya en tu código, 
if (findIssues(jqlQuery)){
//Aquí haces lo que quieras con tu customfield
}else{
//Haces otra cosa
}

Ignacio Flores September 24, 2020

@Gustavo Félix 

Entendiste a la perfección! jajaja

Pero el único problema, es que siempre me esta retornando true, independientemente si este if se cumple o no

if (issue.getIssueType().getName().equals("Modelo de Datos") || issue.getIssueType().getName().equals("Hacking etico"))

Probando para ver que valores esta guardando, cambie nuevamente el boolean findIssues(String jqlQuery) por def y note que el if si esta funcionando bien, pero al declarar findIssues(String jqlQuery) como boolean siempre me los esta setendo en True


Gustavo Félix
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.
September 24, 2020

Podrías poner el código completo ? 

Ignacio Flores September 29, 2020

@Gustavo Félix 

Te dejo el código completo!

Por lo que estuve investigando al declarar un resultado collection como boolean, siempre va a devolver true cuando encuentre algo, independientemente si se cumple la condición dentro o no. ¿A que me refiero con esto?, cuando ejecuto el código y este valida la versión indicada en el JQL, si encuentra issues siempre devuelve TRUE independientemente si el IF se cumple o no, si no encuentra issues solo en ese caso devuelve FALSE

Version id 11827 (Contiene tickets de Hacking Etico y Modelo de datos) = TRUE
Version id 11828 (Contiene uno de Hacking Etico pero ningun de Modelo de datos) =TRUE --> Aquí debería dar FALSE.

Version id 11829 (No contiene tickets) = FALSE 

 

import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.jql.parser.JqlQueryParser;
import com.atlassian.jira.issue.search.SearchProvider;
import com.atlassian.jira.web.bean.PagerFilter;
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.fields.config.FieldConfig
import com.atlassian.jira.issue.context.IssueContextImpl
import com.atlassian.jira.issue.customfields.manager.OptionsManager
import com.atlassian.jira.issue.customfields.option.Options
import com.atlassian.jira.issue.customfields.option.Option
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import org.apache.log4j.Level
import com.atlassian.jira.issue.Issue
import org.apache.log4j.Logger

def log = Logger.getLogger("com.acme.workflows")
log.setLevel(Level.DEBUG)

boolean findIssues(String jqlQuery) {
def issueManager = ComponentAccessor.issueManager
def user = ComponentAccessor.jiraAuthenticationContext.getLoggedInUser()
def jqlQueryParser = ComponentAccessor.getComponent(JqlQueryParser.class)
def searchProvider = ComponentAccessor.getComponent(SearchProvider.class)
def query = jqlQueryParser.parseQuery(jqlQuery)
def results = searchProvider.search(query, user, PagerFilter.unlimitedFilter)
results.issues.collect {
issue -> issueManager.getIssueObject(issue.id)
def issueType = issue.getIssueType().getName()
int trueCount = 0;
if (issue.getIssueType().getName().equals("Modelo de Datos") || issue.getIssueType().getName().equals("Hacking etico"))
{
trueCount++;
return true
}
else
{
return false

}
if (trueCount ==true)
{
return true;
}
else
{
return false;
}
}
}

//def user = ComponentAccessor.jiraAuthenticationContext.userCustomField
//CustomField cf1 = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("Proyecto/Releases")
//def jqlQuery = "fixVersion =11827"
def jqlQuery = "fixVersion =11828"
boolean issues = findIssues(jqlQuery)
log.warn(issues)

Gustavo Félix
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.
September 29, 2020

Es que en esta parte
if (issue.getIssueType().getName().equals("Modelo de Datos") || issue.getIssueType().getName().equals("Hacking etico"))
{
trueCount++;
return true
}
else
{
return false

}

solo va a entrar una vez al primer if y va a regresar true, o sea, en esa parte no deberías poner return, porque se saldrá del método.
Solo quita los primeros returns y creo que debería funcionar.

if (issue.getIssueType().getName().equals("Modelo de Datos") || issue.getIssueType().getName().equals("Hacking etico"))
{
trueCount++;
}
else
{
Aquí tampoco iría return false, porque necesitas terminar de iterar primero todos los issues. Así que si no necesitas agregar algo aquí, podrías quitar el else.
}

Espero te funcione.

Ignacio Flores September 30, 2020

@Gustavo Félix 

Hola Gustavo!

Probe quitando los return pero de igual manera, siempre me devuelve true si es que encuentra issues, independientemente del if, solo devuelve false si no encuentra nada.

Se te ocurre que puede ser ? ya me va a explotar la cabeza jajaja

 

import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.jql.parser.JqlQueryParser;
import com.atlassian.jira.issue.search.SearchProvider;
import com.atlassian.jira.web.bean.PagerFilter;
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.fields.config.FieldConfig
import com.atlassian.jira.issue.context.IssueContextImpl
import com.atlassian.jira.issue.customfields.manager.OptionsManager
import com.atlassian.jira.issue.customfields.option.Options
import com.atlassian.jira.issue.customfields.option.Option
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import org.apache.log4j.Level
import com.atlassian.jira.issue.Issue
import org.apache.log4j.Logger

def log = Logger.getLogger("com.acme.workflows")
log.setLevel(Level.DEBUG)

boolean findIssues(String jqlQuery) {
def issueManager = ComponentAccessor.issueManager
def user = ComponentAccessor.jiraAuthenticationContext.getLoggedInUser()
def jqlQueryParser = ComponentAccessor.getComponent(JqlQueryParser.class)
def searchProvider = ComponentAccessor.getComponent(SearchProvider.class)
def query = jqlQueryParser.parseQuery(jqlQuery)
def results = searchProvider.search(query, user, PagerFilter.unlimitedFilter)
results.issues.collect {
issue -> issueManager.getIssueObject(issue.id)
def issueType = issue.getIssueType().getName()
int trueCount = 0;
if (issue.getIssueType().getName().equals("Modelo de Datos") || issue.getIssueType().getName().equals("Hacking etico"))
{
trueCount++;
log.warn(trueCount)
}
}
}

//def user = ComponentAccessor.jiraAuthenticationContext.userCustomField
//CustomField cf1 = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("Proyecto/Releases")
//def jqlQuery = "fixVersion =11827"
def jqlQuery = "fixVersion =11827"
def issues = findIssues(jqlQuery)
log.warn(issues)

Gustavo Félix
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.
September 30, 2020

Es que removiste código de más , así debería quedar:

results.issues.collect {
issue -> issueManager.getIssueObject(issue.id)
def issueType = issue.getIssueType().getName()
int trueCount = 0;
if (issue.getIssueType().getName().equals("Modelo de Datos") || issue.getIssueType().getName().equals("Hacking etico"))
{
trueCount++;
log.warn(trueCount)
}
}
if (trueCount >=2){   //Con esta parte validas si trueCount es >=2 , si encontró más de                                        //dos issues de esos dos tipos. Si sí , regresa true, si no, false
return true;
}else{
return false
}
}


Ignacio Flores September 30, 2020

@Gustavo Félix 

Lo probé, pero sigue retornando true, te dejo imagen del resultado.

import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.jql.parser.JqlQueryParser;
import com.atlassian.jira.issue.search.SearchProvider;
import com.atlassian.jira.web.bean.PagerFilter;
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.fields.config.FieldConfig
import com.atlassian.jira.issue.context.IssueContextImpl
import com.atlassian.jira.issue.customfields.manager.OptionsManager
import com.atlassian.jira.issue.customfields.option.Options
import com.atlassian.jira.issue.customfields.option.Option
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import org.apache.log4j.Level
import com.atlassian.jira.issue.Issue
import org.apache.log4j.Logger

def log = Logger.getLogger("com.acme.workflows")
log.setLevel(Level.DEBUG)

boolean findIssues(String jqlQuery) {
def issueManager = ComponentAccessor.issueManager
def user = ComponentAccessor.jiraAuthenticationContext.getLoggedInUser()
def jqlQueryParser = ComponentAccessor.getComponent(JqlQueryParser.class)
def searchProvider = ComponentAccessor.getComponent(SearchProvider.class)
def query = jqlQueryParser.parseQuery(jqlQuery)
def results = searchProvider.search(query, user, PagerFilter.unlimitedFilter)
results.issues.collect {
issue -> issueManager.getIssueObject(issue.id)
def issueType = issue.getIssueType().getName()
int trueCount = 0;
if (issue.getIssueType().getName().equals("Modelo de Datos") || issue.getIssueType().getName().equals("Hacking etico"))
{
trueCount++;
log.warn(trueCount)
}
if (trueCount >=2)

log.warn(trueCount)
return true;
}
else
{
log.warn(trueCount)
return false
}
}
}def jqlQuery = "fixVersion =11828"
def issues = findIssues(jqlQuery)
log.warn(issues)

resultados.png

Gustavo Félix
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.
September 30, 2020

Bueno, es que el trueCount debe estar fuera de tu cuando estés iterando tu listado de issues. Igual , se estaba inicializando en 0 trueCount por cada vez que iterabas , entonces siempre iniciaba en 0 y no se acumulaba la cuenta.
Intenta de esta forma, igual agregué unos warns para ver qué va imprimiendo.

import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.jql.parser.JqlQueryParser;
import com.atlassian.jira.issue.search.SearchProvider;
import com.atlassian.jira.web.bean.PagerFilter;
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.fields.config.FieldConfig
import com.atlassian.jira.issue.context.IssueContextImpl
import com.atlassian.jira.issue.customfields.manager.OptionsManager
import com.atlassian.jira.issue.customfields.option.Options
import com.atlassian.jira.issue.customfields.option.Option
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import org.apache.log4j.Level
import com.atlassian.jira.issue.Issue
import org.apache.log4j.Logger

def log = Logger.getLogger("com.acme.workflows")
log.setLevel(Level.DEBUG)

boolean findIssues(String jqlQuery) {
def issueManager = ComponentAccessor.issueManager
def user = ComponentAccessor.jiraAuthenticationContext.getLoggedInUser()
def jqlQueryParser = ComponentAccessor.getComponent(JqlQueryParser.class)
def searchProvider = ComponentAccessor.getComponent(SearchProvider.class)
def query = jqlQueryParser.parseQuery(jqlQuery)
def results = searchProvider.search(query, user, PagerFilter.unlimitedFilter)
int trueCount = 0;
results.issues.collect {
issue -> issueManager.getIssueObject(issue.id)
def issueType = issue.getIssueType().getName()
log.warn(issueType)
if (issue.getIssueType().getName().equals("Modelo de Datos") || issue.getIssueType().getName().equals("Hacking etico"))
{
trueCount++;
}
}
log.warn(trueCount)
if (trueCount >=2)
{
return true;
}
else
{
return false
}
}
def jqlQuery = "fixVersion =11828"
def issues = findIssues(jqlQuery)
log.warn(issues)

Ignacio Flores September 30, 2020

@Gustavo Félix 

Efectivamente ahora funciono a la perfección! muchas muchas gracias por tu ayuda Gustavo.

Ahora debo seguir avanzando con algunas validaciones dentro del mismo codigo. ¿Si surgen dudas te puedo seguir molestando? 

Muchas gracias!

Gustavo Félix
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.
September 30, 2020

Claro, qué bueno que funcionó

Ignacio Flores October 1, 2020

@Gustavo Félix 

Hola gustavo!

Estoy tratando de actualizar un campo personalizado en la misma postfunction, pero no esta haciendo nada. Como dato, lo ejecuta correctamente cuando estoy en la Script console, pero al ejecutar en una transición con post function no esta actualizando el campo, este es el codigo que añadí:

pd: Como se ve en el log se esta ejecutando el código, pero no esta actualizando el campo, me falta algo ? un commit o algo así ?

if(issues==true)
{
log.warn(issues)
def issueManager = ComponentAccessor.getIssueManager()
def issue = issueManager.getIssueObject(issue.id)
def String myval = "Aprobado"
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def textCf2 = customFieldManager.getCustomFieldObjects(issue).find {it.name == "Aprobación Release"}
if (textCf2) {
def changeHolder = new DefaultIssueChangeHolder()
textCf2.updateValue(null, issue, new ModifiedValue(issue.getCustomFieldValue(textCf2), myval),changeHolder)
log.warn(textCf2)
}
}
else
{
log.warn(issues)
def issueManager = ComponentAccessor.getIssueManager()
def issue = issueManager.getIssueObject(issue.id)
def String myval = "Faltan tareas para desplegar"
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def textCf2 = customFieldManager.getCustomFieldObjects(issue).find {it.name == "Aprobación Release"}
if (textCf2) {
def changeHolder = new DefaultIssueChangeHolder()
textCf2.updateValue(null, issue, new ModifiedValue(issue.getCustomFieldValue(textCf2), myval),changeHolder)
log.warn(textCf2)
}
log.png

Gustavo Félix
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.
October 1, 2020

Bueno, algunas sospechas 
1) Creo que issue debería ser MutableIssue
MutableIssue issue = issueManager.getIssueObject(issue.id) as MutableIssue

2)En qué orden estás colocando la postfunction ?
Cuando agregas una postfunction, aparece
1.- Creates the issue originally
2.- Re index an issue to keep indexes...
3.- Fire a Issue Created 


Ignacio Flores October 7, 2020

@Gustavo Félix 

Efectivamente como mencionabas, cambie a Mutable issue y funciono. 

Ahora tengo una pregunta:
Esta postfuncion esta en una transición obviamente. ¿como se podría hacer, que al validar el "true" de mi codigo, se ejecute la transición pero si es false, no se ejecute la transicion y me arroje algún mensaje de alerta?

Muchas gracias!

Gustavo Félix
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.
October 7, 2020

Bueno, ahí creo que no es la mejor idea hacer eso.
Me parece que debes de meter un validator, que se ejecuta antes de la postfunction. Así te aseguras que cuando llegue a la postfunction sí continuará. Eso , o creo que hay algunas "condition" , pero nunca he trabajado con ellas

Ignacio Flores December 14, 2020

@Gustavo Félix 

Hola gustavo como estas?

queria perdirte ayuda con lo siguiente:

 

Necesito algún consejo u ayuda con este problema que tengo.

Creamos un script que básicamente lo que hace es caputrarel id de un reléase asignado en un campo personalizado llamado “Celula/Release” mediante un JQL Query en el script:

 

def jqlQuery = "fixVersion in (${issue.getCustomFieldValue(cf1)})"  ---⇒ el valor se guarda como “id” y no con el nombre del reléase.

 

Luego el script recorre los issues dentro del reléase, y valida algunas condiciones para poder avanzar en la transición.

El código funcionaba bien hasta que nos solicitaron cambiar el tipo de campo del campo “Celula/Release”, al tipo “Multi selección”.

Al probar que valores me está retornando el campo al seleccionar más de un reléase, retorna los id separados por “,” lo cual está bien, ya que el JQL debería quedar algo así:

 

def jqlQuery = "fixVersion in (13005,13006)" , ejecutando desde el script console el jql se ejecuta correctamente ya que ingresamos los valores directamente. Pero al llevar el código a la validación de mi workflow, al ejecutar me aparece el siguiente error:

 

2020-12-14 11:04:25,887 ERROR [workflow.ScriptWorkflowFunction]: *************************************************************************************

2020-12-14 11:04:25,887 ERROR [workflow.ScriptWorkflowFunction]: Script function failed on issue: IMP-74, actionId: 11, file: <inline script>

com.atlassian.jira.jql.parser.JqlParseException: com.atlassian.jira.jql.parser.antlr.RuntimeRecognitionException: NoViableAltException(32@[])

                at com.atlassian.jira.jql.parser.DefaultJqlQueryParser.parseClause(DefaultJqlQueryParser.java:110)

                at com.atlassian.jira.jql.parser.DefaultJqlQueryParser.parseQuery(DefaultJqlQueryParser.java:33)

                at com.atlassian.jira.jql.parser.JqlQueryParser$parseQuery.call(Unknown Source)

                at Script236.findIssues(Script236.groovy:33)

                at Script236.run(Script236.groovy:121)

Caused by: com.atlassian.jira.jql.parser.antlr.RuntimeRecognitionException: NoViableAltException(32@[])

 

Por favor su ayuda, les comparto el código completo.

 

import com.atlassian.jira.component.ComponentAccessor;

import com.atlassian.jira.jql.parser.JqlQueryParser;

import com.atlassian.jira.issue.search.SearchProvider;

import com.atlassian.jira.web.bean.PagerFilter;

import com.atlassian.jira.issue.fields.CustomField

import com.atlassian.jira.issue.fields.config.FieldConfig

import com.atlassian.jira.issue.context.IssueContextImpl

import com.atlassian.jira.issue.customfields.manager.OptionsManager

import com.atlassian.jira.issue.customfields.option.Options

import com.atlassian.jira.issue.customfields.option.Option

import com.atlassian.jira.component.ComponentAccessor

import com.atlassian.jira.issue.ModifiedValue

import com.atlassian.jira.issue.util.DefaultIssueChangeHolder

import org.apache.log4j.Level

import com.atlassian.jira.issue.Issue

import com.atlassian.jira.issue.MutableIssue

import org.apache.log4j.Logger

import com.atlassian.jira.issue.customfields.option.LazyLoadedOption;

import com.atlassian.jira.issue.IssueManager

import com.opensymphony.workflow.InvalidInputException

import com.onresolve.scriptrunner.runner.util.UserMessageUtil

 

        def log = Logger.getLogger("com.acme.workflows")

        log.setLevel(Level.DEBUG)

        def issue = issue as MutableIssue

        Long issueId = issue.getId()

 

        boolean findIssues(String jqlQuery) {

        def issueManager = ComponentAccessor.issueManager

        def user = ComponentAccessor.jiraAuthenticationContext.getLoggedInUser()

        def jqlQueryParser = ComponentAccessor.getComponent(JqlQueryParser.class)

        def searchProvider = ComponentAccessor.getComponent(SearchProvider.class)

        def query = jqlQueryParser.parseQuery(jqlQuery)

        def results = searchProvider.search(query, user, PagerFilter.unlimitedFilter)

 

        def customFieldManager = ComponentAccessor.getCustomFieldManager()

        def cf2 = customFieldManager.getCustomFieldObjects(issue).find {it.name == "Revisión Seguridad (QA Técnico)"}

        def cf2val = issue.getCustomFieldValue(cf2)

 

        def cf3 = customFieldManager.getCustomFieldObjects(issue).find {it.name == "Revisión Rendimiento"}

        def cf3val = issue.getCustomFieldValue(cf3)

 

        int trueCount = 0;

        int trueCount2 =0;

           

        

 

                if (cf2val==null || (((LazyLoadedOption)cf2val).getValue()=="Rechazado"))

                {

 

                               trueCount2++

                    invalidInputException = new InvalidInputException(trueCount)   

                    invalidInputException = new InvalidInputException("Revision de Seguridad 'Rechazado' o pendiente de completar, favor comunicarse con el equipo de seguridad para resolver esta revisión")

                }

 

                else if ((cf3val==null || (((LazyLoadedOption)cf3val).getValue()=="No")))

                {

 

                    trueCount2++

                    invalidInputException = new InvalidInputException("Revision de rendimiento 'Rechazado' o 'No' o pendiente de completar, favor comunicarse con el equipo de rendimiento para resolver esta revisión")

               

                }

 

 

                else if((((LazyLoadedOption)cf2val).getValue()=="Aprobado") || (((LazyLoadedOption)cf2val).getValue()=="No Aplica") || (((LazyLoadedOption)cf2val).getValue()=="Autorizado") && (((LazyLoadedOption)cf3val).getValue()=="Si") )

                {

 

                    trueCount++;

                   

                }

           

        results.issues.collect {

            issue -> issueManager.getIssueObject(issue.id)   

            def issueType = issue.getIssueType().getName()

            def cf4 = customFieldManager.getCustomFieldObjects(issue).find {it.name == "Tipo Test Plan"}

            def cf4val = issue.getCustomFieldValue(cf4) 

 

                    if ((issue.getIssueType().getName().equals("Test Plan")) && (((LazyLoadedOption)cf4val).getValue()=="Release"))   

                    {

 

                        trueCount++;

                       

                    }

 

                    else if ((issue.getIssueType().getName().equals("Test Plan")==false) || (((LazyLoadedOption)cf4val).getValue()=="Historia Usuario"))

                    {

                       

                        trueCount2++

                        invalidInputException = new InvalidInputException("No existe un test plan asociado en el Release o el mismo no esta asignado como Release")

                        invalidInputException = new InvalidInputException(trueCount)

  

                    }

 

                }

                log.warn(trueCount)

                               if (trueCount >=2)

                               {

                   

                                               return true;

                   

                               }

                               else if(trueCount2 >=1)

                                               {

                   

                                                               return false;

                    

                               }

 

        }

       

 

 

        CustomField cf1 = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("Celula/Release")

        def cf1val = issue.getCustomFieldValue(cf1)

                               log.warn(cf1val)

 

                if (cf1val!=null)

                                               {

               

                               def jqlQuery = "fixVersion in (${issue.getCustomFieldValue(cf1)})"

                               boolean issues = findIssues(jqlQuery)

 

                                               }

                               else

                {

               

                               invalidInputException = new InvalidInputException("Debe completar el campo 'Proyecto/Releases' para poder avanzar") 

                

                }

Gustavo Félix
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.
December 15, 2020

Qué tal, pues truena en estas dos líneas

 at Script236.findIssues(Script236.groovy:33)

                at Script236.run(Script236.groovy:121)

la 121 me queda claro que es  boolean issues = findIssues(jqlQuery)
pero la 33 , cuál sería? Es que por los saltos de línea, me da una línea del import, pero no creo que sea esa. En tu código, cuál línea es la 33(en jira)? Ya con eso se puede saber dónde truena y ver qué podría ser.

Ignacio Flores December 16, 2020

@Gustavo Félix 

Hola Gustavo! muchas gracias por responder!

la linea 33 es la siguiente: def query = jqlQueryParser.parseQuery(jqlQuery)

lo que se me occure que puede ser es que no este tomando bien el formato de entrada en la variable que se asigna en el JQL: def jqlQuery = "fixVersion in (${issue.getCustomFieldValue(cf1)})"

Ya que ahora el cf1 devuelve mas de un valor, por ejemplo: 10003, 10001, 10004

Gustavo Félix
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.
December 16, 2020

Pues podrías intentar en 

String cf1val = issue.getCustomFieldValue(cf1) as String

log.warn(cf1val)

if (cf1val!=null)

{

def jqlQuery = "fixVersion in (" + cf1val + ")"
asegurarte que sea String, quizá eso esté afectando 

Ignacio Flores December 16, 2020

@Gustavo Félix 

Gustavo, lo resolví de la siguiente forma:

def cf1val = issue.getCustomFieldValue(cf1) as List

cf1val.each{
if (cf1val!=null)
{
log.debug"id: $it"
def jqlQuery = "issuetype = 'Test Plan' and fixVersion = $it"

Ahora, tengo otra duda, como podria mostrar todos los mensajes de error de una vez y no uno por uno ?

Me explico, en la validacion se revisan 3 puntos: Revision QA/Revision Seguridad/Revision Release

Para cada uno de estos errores se ejecuta una excepción cuando se da el caso arrojando el mensaje de error.

te dejo el código completo:

import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.jql.parser.JqlQueryParser;
import com.atlassian.jira.issue.search.SearchProvider;
import com.atlassian.jira.web.bean.PagerFilter;
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.fields.config.FieldConfig
import com.atlassian.jira.issue.context.IssueContextImpl
import com.atlassian.jira.issue.customfields.manager.OptionsManager
import com.atlassian.jira.issue.customfields.option.Options
import com.atlassian.jira.issue.customfields.option.Option
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import org.apache.log4j.Level
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.MutableIssue
import org.apache.log4j.Logger
import com.atlassian.jira.issue.customfields.option.LazyLoadedOption;
import com.atlassian.jira.issue.IssueManager
import com.opensymphony.workflow.InvalidInputException
import com.onresolve.scriptrunner.runner.util.UserMessageUtil

def log = Logger.getLogger("com.acme.workflows")
log.setLevel(Level.DEBUG)
def issue = issue as MutableIssue
Long issueId = issue.getId()

boolean findIssues(String jqlQuery) {
def issueManager = ComponentAccessor.issueManager
def user = ComponentAccessor.jiraAuthenticationContext.getLoggedInUser()
def jqlQueryParser = ComponentAccessor.getComponent(JqlQueryParser.class)
def searchProvider = ComponentAccessor.getComponent(SearchProvider.class)
def query = jqlQueryParser.parseQuery(jqlQuery)
def results = searchProvider.search(query, user, PagerFilter.unlimitedFilter)

def customFieldManager = ComponentAccessor.getCustomFieldManager()
def cf2 = customFieldManager.getCustomFieldObjects(issue).find {it.name == "Revisión Seguridad (QA Técnico)"}
def cf2val = issue.getCustomFieldValue(cf2)

def cf3 = customFieldManager.getCustomFieldObjects(issue).find {it.name == "Revisión Rendimiento"}
def cf3val = issue.getCustomFieldValue(cf3)

int trueCount = 0;
int trueCount2 =0;

if (cf2val==null || (((LazyLoadedOption)cf2val).getValue()=="Rechazado"))
{

trueCount2++
invalidInputException = new InvalidInputException(trueCount)
invalidInputException = new InvalidInputException("Revision de Seguridad 'Rechazado' o pendiente de completar, favor comunicarse con el equipo de seguridad para resolver esta revisión")
}

else if ((cf3val==null || (((LazyLoadedOption)cf3val).getValue()=="No")))
{

trueCount2++
invalidInputException = new InvalidInputException("Revision de rendimiento 'Rechazado' o 'No' o pendiente de completar, favor comunicarse con el equipo de rendimiento para resolver esta revisión")

}


else if((((LazyLoadedOption)cf2val).getValue()=="Aprobado") || (((LazyLoadedOption)cf2val).getValue()=="No Aplica") || (((LazyLoadedOption)cf2val).getValue()=="Autorizado") && (((LazyLoadedOption)cf3val).getValue()=="Si") )
{

trueCount++;

}


results.issues.collect {
issue -> issueManager.getIssueObject(issue.id)
def issueType = issue.getIssueType().getName()
def cf4 = customFieldManager.getCustomFieldObjects(issue).find {it.name == "Tipo Test Plan"}
def cf4val = issue.getCustomFieldValue(cf4)
log.warn("el valor del campo Tipo Test Plan es:"+cf4val)
log.warn(issueType)

if (((LazyLoadedOption)cf4val).getValue()=="Release")
{

trueCount++;
log.warn("trueCount-primero:"+trueCount)


}

else if (((LazyLoadedOption)cf4val).getValue()=="Historia Usuario")
{

trueCount2++
invalidInputException = new InvalidInputException("No existe un test plan asociado en el Release o el mismo no esta asignado como Release")
log.warn("trueCount2-primero:"+trueCount2)
}

}
log.warn(trueCount)
if (trueCount >=2)
{

return true;

}
else if(trueCount2 >=1)
{

return false;

}

}


CustomField cf1 = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("Celula/Release")
def cf1val = issue.getCustomFieldValue(cf1) as List
log.warn("el valor de Celula/Release es:"+cf1val)
cf1val.each{
if (cf1val!=null)
{
log.debug"id: $it"
def jqlQuery = "issuetype = 'Test Plan' and fixVersion = $it"
boolean issues = findIssues(jqlQuery)
log.debug(jqlQuery)
log.warn(cf1val)

}
else
{

invalidInputException = new InvalidInputException("Debe completar el campo 'Proyecto/Releases' para poder avanzar")

}
}

Gustavo Félix
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.
December 16, 2020

Si te entendí bien, el problema es que tienes múltiples invalidInputException, correcto ? 
Si sí, pues podrías en vez de definir un invalidInputException cada que haya un error, ir concatenando un string de errores, o una lista de string por cada error.

Y ya al final ves si ese string no está vacío o esa lista no está vacía ( cero errores) , y ahí creas el invalid InputException.

Ignacio Flores December 17, 2020

@Gustavo Félix 

Hola Gustavo!

Me perdí un poco con lo que me comentas ... Me podrías dar un ejemplo básico ?

Gustavo Félix
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.
December 18, 2020

String errores = ""   //Esto lo defines al inicio de todo 

y en vez de hacer invalidInputException("texto") en tus ifs, vas haciendo 
errores = errores.concat("Revision de Seguridad ...") 

y en el siguiente if , haces lo mismo
errores = errores.concat("Revision de rendimiento...") 

Y ya al final, 
if(errores == "") {
//No hubo errores
}else{

invalidInputException = new InvalidInputException(errores)
}
Y así solo imprimirías un solo invalidInputException

Ahora, no sé si este era tu problema o lo entendí mal .

Suggest an answer

Log in or Sign up to answer