Cómo usamos Jira Query Language en la práctica

¡Hola a todos!



Mi nombre es Sergey Rakov, soy el jefe de la división B2G en Rostelecom IT. Quiero hablarles sobre Jira Query Language (JQL): cómo usarlo en la práctica, técnicas básicas, qué problemas encontramos y cómo los resolvimos.



imagen Imagen original tomada de deviniti.com/atlassian



Hay muchos rastreadores de tareas, cada uno es adecuado para resolver algunos problemas y no es muy útil para resolver otros. Usamos muchos de ellos, pero ahora nos decidimos por Jira, es nuestra herramienta principal. Personalmente, me gusta mucho su lenguaje JQL, que simplifica enormemente el trabajo y te permite tener una herramienta poderosa y flexible para encontrar tickets listos para usar.



Fuera de la caja, Jira tiene búsquedas básicas y avanzadas. Estas dos opciones de búsqueda pueden resolver la mayoría de los problemas que enfrenta el usuario. La búsqueda básica es familiar para cualquier persona que haya utilizado los servicios de las tiendas en línea al menos una vez; funciona de acuerdo con el mismo esquema simple. Hay muchos filtros: por proyectos, tipos de tareas, por ejecutor y estado. También puede agregar campos adicionales según los criterios admitidos por Jira.



Pero surge un problema cuando necesita ir más allá de las consultas básicas. Por ejemplo, si queremos encontrar tareas que alguna vez hayan estado en un ejecutante en particular, o encontrar todas las tareas, excluyendo un proyecto. Ya no es posible hacer una selección complicada para un proyecto con un estado y ejecutante de tarea y un ejecutante más y otro estado de tarea utilizando la búsqueda básica.



La búsqueda avanzada viene al rescate. La sintaxis de JQL es muy similar a SQL. Pero en JQL, no es necesario seleccionar campos específicos que seleccionaremos, indicar tablas y bases de datos desde las que mostraremos. Especificamos solo un bloque con condiciones y trabajamos con clasificación; Jira hace el resto automáticamente.



Todo lo que necesita saber para trabajar con JQL son los nombres de los campos mediante los cuales seleccionaremos tickets, operadores ( = ,! =, <,>, In, not in, was, is , etc.), palabras clave ( Y , OR, NOT, EMPTY, ORDER BY , etc.) y funciones que están disponibles de inmediato en el modo avanzado ( Now (), CurrentUser (), IssueHistory (), EndOfDay () y otros).



Campos



Jira, cuando escribe en la barra de búsqueda, da pistas de todos los valores posibles que está buscando: tanto por campos como por los valores de estos campos. Para mí, recientemente descubrí un campo de sistema interesante lastViewed . Jira realiza un seguimiento de las visualizaciones de sus entradas.

imagen

Aquí hay dos opciones para componer filtros para ver tareas recientes. La primera es mi opción lastViewed , donde Jira devolverá los problemas que he visto en los últimos siete días, ordenados en orden descendente. Este filtro está configurado en mi tablero como un gadget y lo uso a menudo. Debido a que el boleto estaba cerrado, no recordaba la pestaña y el número, lo abrí rápidamente, miré cuál era el último boleto.



Hay un filtro estándar Visto recientemente. Utiliza la función IssueHistory () , la clasificación también se realiza mediante el campo lastViewed . El resultado es el mismo, pero el método, incluso en Jira, se puede utilizar de forma diferente. Vale la pena señalar que los campos LastViewed y IssueHistory () solo devuelven su historial de navegación; no puede ver el historial de terceros de esta manera.



imagen

En su mayor parte, en Jira, todos los operadores son estándar. Mis favoritos son los operadores de WAS , FUE EN , no estaba en , no era , CAMBIADO porque funcionan con el tiempo. Esto no es posible en las bases de datos convencionales.



imagen



Jira le permite trabajar con datos históricos listos para usar. Usando el operador WAS , puede encontrar tickets donde el ejecutor estaba y es User1. Si el boleto estaba a mi cargo y luego se lo pasó a otra persona, la solicitud mostrará que este boleto lo tuve una vez. Está claro que para una selección más detallada, debe agregar algunas condiciones más, pero llegaremos a esto más adelante.



Sin embargo, hay una advertencia: Jira no almacena el historial de los campos de texto: los nombres de los tickets y sus descripciones. No puede escribir allí: “ Tráeme boletos en los que el campo Resumen contenía la palabra“ Rostelecom ” ”.



El segundo ejemplo es con el operador CAMBIADO . Nos gustaría recibir tickets en los que se cambió el albacea después del 1 de enero de 2020. Puede utilizar otras palabras adicionales, por ejemplo, ANTES o signos>, <, para quien es más conveniente y una fecha específica. En el mismo ejemplo, también puede hacer una negación y ver qué tickets se cuelgan de qué usuarios: el asignatario no cambió DESPUÉS de '2020-01-01' .



Palabras clave



imagen

Las palabras clave principales son OR , AND , NOT . Funcionan de la misma forma que los operadores lógicos. Usando OR , obtenemos un conjunto completo de tickets de dos proyectos A y B. Si necesitamos reducir la selección, usamos AND . Ejemplo: necesitamos tickets del borrador A, en el que el usuario estaba ejecutando Bed y: project = A = Bed y el asignado AND . Lo mismo ocurre con la negación.



Funciones



Según la documentación, hay 47 funciones en Jira, pero nunca las usé todas. Aquí hay algunas, en mi opinión, las principales:



imagen



ahora () es una función popular que te permite buscar entradas que, por ejemplo, han caducado.



currentUser () devuelve el usuario actual. Jira contiene filtros preconfigurados que utilizan esta función. Con currentUser (), puede realizar búsquedas genéricas. Así es como hice un tablero universal para todo el equipo de desarrollo: coloqué gadgets en el tablero y en cada uno indiqué currentUser () en lugar de un usuario específico . Este panel será único para cada usuario que haya iniciado sesión, aunque la configuración será la misma.



unreleasedVersions () es una función que devuelve tickets que están en versiones inéditas. Pero no devuelve boletos que no tienen una versión configurada.



startOfDay () devuelve el inicio del día actual. Hay funciones para semana, mes y año. Lo mismo se aplica a la función de cierre endOfDay () . Le permiten deshacerse de fechas específicas, se les puede dar argumentos: si escribe startOfDay (-1) , se devolverá el comienzo del día anterior. Si deja todo como está, se mostrará el inicio del día actual; la salida será la hora. Estas funciones ayudan a evitar el hardcode, las usamos mucho.



De issueHistory ()Ya di un ejemplo, esta función devuelve una lista de solo sus vistas.



LinkedIssues () es una función que le permite encontrar tickets que están vinculados a un ticket específico.



Estas son las funciones más simples. Pero profundicemos un poco más y veamos conexiones más complejas.



assignee was currentUser()

AND fixVersion was in
unreleasedVersions()

AND created > startOfYear()

      
      





Un ejemplo un poco sintético, pero no obstante. Esta es una solicitud única dividida en tres bloques. Después de completar la primera parte de la solicitud, recibiremos entradas en las que alguna vez he sido un artista o lo soy en este momento. Es muy importante que WAS no solo existió, sino que aún existe.



En la segunda parte, se agrega el filtrado: filtraremos el alcance recibido de mis boletos que alguna vez hayan estado en versiones inéditas en este momento. Es decir, si había un ticket en esta versión inédita y aún no se ha lanzado en este momento, pero luego transferí el ticket a otra versión, y ya fue lanzado, entonces el ticket se incluirá en esta selección.



La tercera condición es la fecha de creación. Filtramos solo aquellos tickets que se han creado desde el comienzo del año actual.



ScriptRunner



Este es un complemento que mejora enormemente las capacidades de Jira. Por lo general, se usa para automatizar procesos, pero también agrega muchas funciones adicionales a JQL. ScriptRunner fue nuestro primer complemento que entregamos tan pronto como nos mudamos a Jira, a fines de 2018. Pedí muy activamente instalar este complemento, porque sin él no podría recopilar datos sobre enlaces con épicas. Por ejemplo, a menudo necesitaba devolver todas las entradas épicas para una solicitud específica o todas las épicas para las entradas de las subconsultas. ScriptRunner le permite hacer todo esto con éxito.



Para usar las funciones de ScriptRunner, debe agregar una palabra adicional issueFunction en o no en JQL . Luego viene la función, por ejemplo epicsOf () : devuelve épicos para tickets que coinciden con las condiciones de la subconsulta. La subconsulta viene entre paréntesis en la segunda línea y la veremos más de cerca.



issueFunction in epicsOf
("worklogDate >= startOfWeek(-1) AND worklogDate <= endOfWeek(-1)")
AND project in (".B2G")
      
      





En el primer ejemplo, buscamos epopeyas con pérdidas de tiempo durante la última semana. Truco de vida para líderes de equipo y gerentes: si olvidó completar las hojas de tiempo y no recuerda lo que hizo la semana pasada, al completar esta solicitud, verá en qué epopeyas trabajó el equipo. Y lo más probable es que también hayas trabajado en ellos, porque el equipo claramente vino con preguntas. En general, esta consulta ayuda a recordar lo que estaba haciendo y todo está bien para pintar.



La consulta en sí comienza a ejecutarse desde paréntesis, es decir, desde la subconsulta worklogDate , la fecha de débito. Además, hay una especificación > = startOfWeek (-1) - el comienzo de la semana. Pero preste atención al número -1: significa que no necesitamos este lunes, sino el último. Y también worklogDate <= endOfWeek (-1), es decir, es menor que el final de la semana pasada. Esta solicitud emitirá tickets, sin importar qué (errores, tareas, historias de usuarios) para los cuales los empleados cancelaron el tiempo de lunes a domingo la semana pasada.



El truco es que las funciones startOfWeek () y endOfWeek () le permiten deshacerse de la fecha. Independientemente del tiempo durante el cual haga esta solicitud en la semana actual, me devolverá el mismo alcance épico. Tan pronto como termine esta semana, devolverá las epopeyas. Sorprendentemente, no todos aprovechan esta oportunidad: recientemente estudié solicitudes abiertas que se comparten públicamente y vi muchas fechas codificadas allí. Y existe la sospecha de que estas fechas cambian constantemente. Y qué puedo decir, al principio lo hice yo mismo.



Al ejecutar la subconsulta, obtenemos el conjunto habitual de tickets. Luego viene la función epicsOf , que nos da una lista de las epopeyas asociadas con estos tickets. Y luego está el filtrado por proyecto, porque solo necesito epopeyas para mi proyecto, y todos los demás no son interesantes.



La próxima solicitud es para epopeyas con cancelaciones este año, pero sin contratos. Esta solicitud apareció debido al hecho de que usamos Jira no solo como un rastreador de tareas, sino también para la contabilidad financiera. Hay un proyecto separado para los contratos, que ejecutamos en forma de tickets, y lo usamos como un sistema de gestión de documentos electrónicos: los estados cambian constantemente, vinculamos los contratos con las epopeyas, sabemos cuántas personas han cancelado cada epopeya, sabemos cuánto cuesta y luego por establecemos el costo del trabajo para cada contrato. Además, a través de contratos, los costos laborales se transfieren a Redmine 2.0. Es decir, cancelamos a Jira, y luego los scripts automáticos transfieren nuestros costos a Redmine 2.0 bajo estos contratos.



Cuando esta automatización empezó a funcionar, empecé a recibir peticiones de compañeros del tipo: hay épicas cuyos costes laborales no se pueden trasladar a Redmine, porque allí no hay contratos. Consideremos la solicitud con más detalle.



issueFunction in epicsOf("worklogDate >= startOfYear()")
AND issueFunction not in hasLinkType(Contract)
AND project in (".B2G")
      
      







La solicitud adjunta significa que estamos interesados ​​en las entradas que se han cobrado este año. La función epicsOf sigue del ejemplo anterior y nos da una lista de épicas. A continuación, queremos filtrar por la presencia de contratos.



Un contrato entre paréntesis es un tipo de vínculo interno que conecta contratos con epopeyas. hasLinkType () es una función en ScriptRunner que devuelve tickets con este tipo de enlace. Pero necesito tickets que no contengan este tipo de relación y, por lo tanto, uso la negación not in.



Cuando se cumplió la primera condición, obtuve una serie de epopeyas que fueron relevantes este año. Además, se filtraron épicas sin contratos, y en la final, para un proyecto específico "Video.B2G". De esta manera conseguí trabajar con todas las epopeyas.



Y al final me gustaría sugerir pasar una pequeña prueba de tres preguntas sobre el tema de este post. Tardará 2 minutos. Después de aprobar, verá su evaluación.

Enlace de encuesta
Me complacería aclarar algo o responder preguntas en los comentarios, si tiene alguna.

Gracias.



All Articles