11 KiB
JQL Patterns Skill
Master JQL (Jira Query Language) query construction for advanced issue filtering and reporting.
Overview
JQL is Jira's powerful query language for finding issues. This skill provides patterns and templates for constructing effective queries using jira-cli.
Basic JQL Structure
field operator value [AND|OR field operator value]
Essential Field Reference
Issue Fields
| Field | Type | Example |
|---|---|---|
project |
Text | project = PROJ |
key |
Text | key = PROJ-123 |
summary |
Text | summary ~ "login" |
description |
Text | description ~ "error" |
status |
Text | status = "In Progress" |
priority |
Text | priority IN (High, Critical) |
type |
Text | type = Bug |
labels |
List | labels = urgent |
component |
Text | component = Backend |
fixVersion |
Version | fixVersion = "1.0" |
resolution |
Text | resolution = Fixed |
People Fields
| Field | Type | Example |
|---|---|---|
assignee |
User | assignee = currentUser() |
reporter |
User | reporter = "user@example.com" |
creator |
User | creator = currentUser() |
watcher |
User | watcher = currentUser() |
Date Fields
| Field | Type | Example |
|---|---|---|
created |
Date | created >= -7d |
updated |
Date | updated >= startOfWeek() |
resolved |
Date | resolved >= "2024-01-01" |
duedate |
Date | duedate <= now() |
Agile Fields
| Field | Type | Example |
|---|---|---|
sprint |
Sprint | sprint = 123 |
"Epic Link" |
Epic | "Epic Link" = PROJ-100 |
"Story Points" |
Number | "Story Points" > 5 |
Operators Reference
Equality
=- Equals!=- Not equalsIN- In listNOT IN- Not in list
Comparison
>- Greater than>=- Greater than or equal<- Less than<=- Less than or equal
Text Search
~- Contains (case-insensitive)!~- Does not containIS- For checking null/emptyIS NOT- For checking not null/empty
Special
IS EMPTY- Field has no valueIS NOT EMPTY- Field has valueWAS- Historical valueCHANGED- Field was changed
JQL Functions
User Functions
assignee = currentUser()
reporter = currentUser()
watcher = currentUser()
assignee IN membersOf("developers")
Date Functions
created >= startOfDay()
created <= endOfDay()
created >= startOfWeek()
created >= startOfMonth()
created >= startOfYear()
updated >= startOfDay(-7) # 7 days ago
duedate <= endOfWeek(1) # End of next week
Sprint Functions
sprint IN openSprints()
sprint IN closedSprints()
sprint IN futureSprints()
Common Query Patterns
My Work Queries
Current work:
assignee = currentUser() AND status NOT IN (Done, Closed)
Recently completed:
assignee = currentUser() AND status = Done AND resolved >= -7d
Reported by me:
reporter = currentUser() AND status NOT IN (Done, Closed)
Watching:
watcher = currentUser() AND status NOT IN (Done, Closed)
Priority Queries
Critical and high priority open:
priority IN (Critical, High) AND status NOT IN (Done, Closed, Resolved)
Urgent bugs:
type = Bug AND priority = Critical AND status NOT IN (Done, Closed)
Prioritized backlog:
status = "To Do" AND priority IN (High, Medium) ORDER BY priority DESC
Time-Based Queries
Created today:
created >= startOfDay()
Updated this week:
updated >= startOfWeek()
Created in last 30 days:
created >= -30d
Overdue issues:
duedate < now() AND status NOT IN (Done, Closed)
Due this week:
duedate >= startOfWeek() AND duedate <= endOfWeek()
Stale issues (not updated in 90 days):
updated <= -90d AND status NOT IN (Done, Closed)
Team Queries
Unassigned issues:
assignee IS EMPTY AND status = "To Do"
Team workload:
assignee IN (user1@example.com, user2@example.com) AND status IN ("In Progress", "To Do")
Blocked issues:
status = Blocked OR labels = blocked
Issues needing review:
status = "In Review" AND assignee IS NOT EMPTY
Sprint Queries
Current sprint:
sprint IN openSprints()
Current sprint for project:
project = PROJ AND sprint IN openSprints()
Specific sprint:
sprint = 123
Issues without sprint:
type IN (Story, Bug, Task) AND sprint IS EMPTY
Incomplete sprint items:
sprint = 123 AND status NOT IN (Done, Closed)
Epic Queries
All issues in epic:
"Epic Link" = PROJ-100
Completed epic issues:
"Epic Link" = PROJ-100 AND status = Done
Issues without epic:
type = Story AND "Epic Link" IS EMPTY
Bug Tracking Queries
Open bugs:
type = Bug AND status NOT IN (Done, Closed, "Won't Fix")
Critical production bugs:
type = Bug AND priority = Critical AND labels = production AND status NOT IN (Done, Closed)
Bugs by component:
type = Bug AND component = Backend AND status NOT IN (Done, Closed)
Recently fixed bugs:
type = Bug AND status = Done AND resolved >= -7d
Regression bugs:
type = Bug AND labels = regression AND status NOT IN (Done, Closed)
Story Queries
Ready for development:
type = Story AND status = "To Do" AND "Story Points" IS NOT EMPTY
Unestimated stories:
type = Story AND "Story Points" IS EMPTY AND status = "To Do"
Large stories (need breakdown):
type = Story AND "Story Points" >= 13
Component Queries
Frontend issues:
component = Frontend AND status NOT IN (Done, Closed)
Backend bugs:
component = Backend AND type = Bug AND status NOT IN (Done, Closed)
Issues without component:
component IS EMPTY AND type IN (Story, Bug, Task)
Label Queries
Technical debt:
labels = tech-debt AND status NOT IN (Done, Closed)
Multiple labels:
labels IN (urgent, critical) AND status NOT IN (Done, Closed)
Issues without labels:
labels IS EMPTY AND type IN (Story, Bug)
Advanced Patterns
Complex Logic with Parentheses
project = PROJ AND
(priority = Critical OR labels = urgent) AND
status NOT IN (Done, Closed)
ORDER BY created DESC
Historical Queries
Issues that were in progress:
status WAS "In Progress" DURING (-7d, now())
Issues that changed priority:
priority CHANGED DURING (-30d, now())
Issues moved to done this week:
status CHANGED TO Done DURING (startOfWeek(), now())
Negative Queries
Not assigned to specific team:
assignee NOT IN membersOf("qa-team")
Exclude certain statuses:
status NOT IN (Done, Closed, "Won't Fix", Duplicate)
Not labeled:
labels IS EMPTY
Multi-Project Queries
Across projects:
project IN (PROJ1, PROJ2, PROJ3) AND assignee = currentUser()
All projects bugs:
type = Bug AND priority = Critical AND status NOT IN (Done, Closed)
Sorting Patterns
Single Sort
ORDER BY priority DESC
ORDER BY created ASC
ORDER BY updated DESC
ORDER BY duedate ASC
Multiple Sort
ORDER BY priority DESC, created ASC
ORDER BY status ASC, priority DESC, updated DESC
ORDER BY duedate ASC, priority DESC
Using with jira-cli
Basic Query
jira issue list --jql "assignee = currentUser() AND status = 'In Progress'"
Multi-line for Readability
jira issue list --jql "\
project = PROJ AND \
status IN ('In Progress', 'In Review') AND \
assignee = currentUser() AND \
created >= -7d \
ORDER BY priority DESC"
With Output Formats
# Human readable
jira issue list --jql "..." --plain
# JSON for parsing
jira issue list --jql "..." --raw
# CSV for export
jira issue list --jql "..." --csv
Report Patterns
Sprint Velocity
sprint = 123 AND status = Done
Sum story points from results.
Bug Trend
type = Bug AND created >= -30d
type = Bug AND resolved >= -30d
Compare created vs resolved.
Team Performance
assignee IN membersOf("dev-team") AND
status = Done AND
resolved >= startOfWeek()
Epic Progress
"Epic Link" = PROJ-100
"Epic Link" = PROJ-100 AND status = Done
Calculate percentage complete.
Technical Debt Tracking
labels = tech-debt AND
status NOT IN (Done, Closed) AND
created <= -90d
ORDER BY priority DESC, created ASC
Query Optimization Tips
1. Narrow by Project First
❌ Slow:
status = "In Progress"
✅ Fast:
project = PROJ AND status = "In Progress"
2. Use Specific Operators
❌ Slow:
summary ~ ".*login.*"
✅ Fast:
summary ~ "login"
3. Limit Results
jira issue list --jql "..." --limit 100
4. Use IS EMPTY Instead of Negation
❌ Slower:
assignee != null
✅ Faster:
assignee IS NOT EMPTY
Common Mistakes
Mistake 1: Missing Quotes
❌ Wrong:
status = In Progress
✅ Correct:
status = "In Progress"
Mistake 2: Wrong Function
❌ Wrong:
assignee = me
✅ Correct:
assignee = currentUser()
Mistake 3: Wrong Field Name
❌ Wrong:
epic = PROJ-100
✅ Correct:
"Epic Link" = PROJ-100
Mistake 4: Wrong Date Format
❌ Wrong:
created > 7d
✅ Correct:
created >= -7d
Debugging Queries
Step 1: Simplify
Start with basic query:
project = PROJ
Step 2: Add Conditions Incrementally
project = PROJ AND status = "In Progress"
project = PROJ AND status = "In Progress" AND assignee = currentUser()
Step 3: Test Each Addition
Run query after each change to identify issues.
Step 4: Check Field Names
Verify custom field names in Jira UI.
Step 5: Use --debug
jira issue list --jql "..." --debug
Saving Common Queries
Shell Aliases
alias jira-my-work='jira issue list --jql "assignee = currentUser() AND status NOT IN (Done, Closed)" --plain'
alias jira-urgent='jira issue list --jql "priority IN (Critical, High) AND status NOT IN (Done, Closed)" --plain'
alias jira-sprint='jira issue list --jql "sprint IN openSprints()" --plain'
Script Functions
# Add to ~/.bashrc or ~/.zshrc
jira-find() {
local query="$1"
jira issue list --jql "summary ~ \"$query\" OR description ~ \"$query\"" --plain
}
jira-my-bugs() {
jira issue list --jql "assignee = currentUser() AND type = Bug AND status NOT IN (Done, Closed)" --plain
}
jira-overdue() {
jira issue list --jql "duedate < now() AND status NOT IN (Done, Closed)" --plain
}
When to Use This Skill
- User needs complex issue filtering
- Generating reports or metrics
- Finding issues across projects
- Historical queries
- Performance optimization needed
- Combining multiple criteria
Next Steps
After mastering JQL:
- Create saved queries for common needs
- Integrate queries into automation scripts
- Build dashboards based on queries
- Share query templates with team
- Document organization-specific patterns