Files
soleprint/artery/veins/jira/core/query.py
2025-12-31 08:34:18 -03:00

87 lines
2.2 KiB
Python

"""
JQL query builder.
"""
from typing import Optional, List
class JQL:
"""Fluent JQL builder."""
def __init__(self):
self._parts: List[str] = []
self._order: Optional[str] = None
def _q(self, val: str) -> str:
return f'"{val}"' if " " in val else val
# Conditions
def assigned_to_me(self) -> "JQL":
self._parts.append("assignee = currentUser()")
return self
def project(self, key: str) -> "JQL":
self._parts.append(f"project = {self._q(key)}")
return self
def sprint_open(self) -> "JQL":
self._parts.append("sprint in openSprints()")
return self
def in_backlog(self) -> "JQL":
self._parts.append("sprint is EMPTY")
return self
def not_done(self) -> "JQL":
self._parts.append("statusCategory != Done")
return self
def status(self, name: str) -> "JQL":
self._parts.append(f"status = {self._q(name)}")
return self
def label(self, name: str) -> "JQL":
self._parts.append(f"labels = {self._q(name)}")
return self
def text(self, search: str) -> "JQL":
self._parts.append(f'text ~ "{search}"')
return self
def issue_type(self, name: str) -> "JQL":
self._parts.append(f"issuetype = {self._q(name)}")
return self
def raw(self, jql: str) -> "JQL":
self._parts.append(jql)
return self
# Ordering
def order_by(self, field: str, desc: bool = True) -> "JQL":
self._order = f"ORDER BY {field} {'DESC' if desc else 'ASC'}"
return self
def build(self) -> str:
jql = " AND ".join(self._parts)
if self._order:
jql = f"{jql} {self._order}"
return jql.strip()
# Preset queries for main use cases
class Queries:
@staticmethod
def my_tickets(project: Optional[str] = None) -> JQL:
q = JQL().assigned_to_me().not_done().order_by("updated")
if project:
q.project(project)
return q
@staticmethod
def backlog(project: str) -> JQL:
return JQL().project(project).in_backlog().not_done().order_by("priority")
@staticmethod
def current_sprint(project: str) -> JQL:
return JQL().project(project).sprint_open().order_by("priority")