A secure, CLI-based toolset for pulling issue data from Jira. The repo contains two independent entry points:
| Script | Purpose |
|---|---|
main.py |
Extract issues for any JQL query, compute time metrics, and run local AI theme analysis via Ollama. Writes a CSV and a Markdown report. |
jira_metrics_report.py |
Print a quick terminal metrics summary scoped to a fixed set of assignees — active issue counts, weekly averages, and wait-time breakdown. No files are written. |
- Issue title, assignee, account name, Rancher team, reporter
- Created / updated / resolved date-time
- Current status, type, priority, resolution
- Description and comments
- Issue key (for traceability)
- Status change history (used for time-in-status metrics)
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtcp .env.example .envJira Server / Data Center:
JIRA_BASE_URL=https://jira.suse.comJIRA_API_TOKEN=<Personal Access Token>— create at Profile → Personal Access Tokens in Jira.
Runs a JQL query, fetches the full issue set (including status changelog for time-in-status metrics), writes a CSV, and produces a Markdown report with AI-generated themes via a local Ollama instance.
python3 main.py 'project IN ("SURE", "NVSHAS") AND created >= -7d AND issuetype in ("Bug", "Escalation")'Timestamped files written to output/:
jira_issues_<timestamp>.csv— raw issue datajira_issue_themes_<timestamp>.md— Markdown report containing:- Status breakdown — closed vs. open counts
- Time metrics (always shown):
- Time to initial response — creation to first comment by the assignee
- Time actively worked — open time excluding Waiting for Reporter periods
- Time waiting for reporter — total time spent in Waiting for Reporter status
- Resolution statistics (shown when JQL targets resolved issues):
- Average and median time to resolution
- Issues by customer and team
- AI-generated themes, cross-cutting observations, and team-specific action items
If Ollama is unreachable or returns invalid JSON, extraction still completes and the tool prints a "Theme analysis skipped" message.
python3 main.py \
--timeout 1200 \
--ollama-retries 3 \
--page-title 'Weekly Escalation Report' \
--base-filename escalations_weekly \
'project IN ("SURE", "NVSHAS") AND created >= -7d AND issuetype in ("Bug", "Escalation")'| Flag | Default | Description |
|---|---|---|
--timeout |
900 |
Seconds per Ollama request |
--ollama-retries |
2 |
Retries for transient Ollama failures (timeouts, temporary connectivity, 5xx/429) |
--page-title |
"Jira Issue Theme Analysis" |
Heading in the Markdown report |
--base-filename |
"jira_issue_themes" |
Base name for output files |
| Variable | Default | Description |
|---|---|---|
JIRA_EXTRACTOR_OUTPUT_DIR |
output |
Directory for output files |
OLLAMA_ENABLED |
true |
Set to false to skip AI analysis |
OLLAMA_MODEL |
llama3.1:8b |
Ollama model to use |
OLLAMA_HOST |
http://localhost:11434 |
Ollama endpoint (OLLAMA_BASE_URL is also accepted as a fallback) |
Prints a terminal summary for a fixed set of assignees: active issue counts, issues waiting for reporter, and weekly new/resolved averages. No files are written. Requires JIRA_ASSIGNEES to be set.
JIRA_ASSIGNEES="jane.doe,john.smith" python3 jira_metrics_report.pyOr set JIRA_ASSIGNEES in your .env file and run:
python3 jira_metrics_report.py| Flag | Default | Description |
|---|---|---|
--weeks |
12 |
Rolling window for new/resolved weekly averages |
--projects |
SURE,NVSHAS |
Comma-separated Jira project keys |
Example:
python3 jira_metrics_report.py --weeks 8 --projects SURE,NVSHAS,OBS| Variable | Description |
|---|---|
JIRA_ASSIGNEES |
Comma-separated list of Jira usernames to scope the report to |
Standalone phrase-based extractor with no AI theme analysis. It builds JQL from
--phrase and --window, fetches matching issues, and writes CSV output.
# Last year (default: 1y)
python3 jira_phrase_extractor.py --phrase "MetalLB"
# Last 9 months
python3 jira_phrase_extractor.py --phrase "MetalLB" --window 9m
# Last 2 years
python3 jira_phrase_extractor.py --phrase "MetalLB" --window 2y
# Scope to specific projects
python3 jira_phrase_extractor.py --phrase "MetalLB" --window 1y --projects SURE,NVSHAS
# Only bug issues
python3 jira_phrase_extractor.py --phrase "MetalLB" --window 2y --type Bug
# Multiple issue types
python3 jira_phrase_extractor.py --phrase "MetalLB" --window 2y --type Bug --type EscalationGenerated JQL looks like:
text ~ "\"MetalLB\"" AND created >= "2025-06-04"
The extractor intentionally uses an absolute cutoff date for compatibility with
Jira instances that reject relative year/month period syntax like -2y.
Switch the date field for window filtering:
python3 jira_phrase_extractor.py --phrase "MetalLB" --window 9m --date-field updated| Flag | Default | Description |
|---|---|---|
--phrase |
(required) | Phrase to search for in issue text. |
--window |
1y |
Time window (1y, 9m, 2y, 12w, 30d, etc.). |
--date-field |
created |
Date field used for the window (created or updated). |
--projects |
(unset) | Optional comma-separated project keys (SURE,NVSHAS). |
--type |
(unset) | Optional issue type filter; repeat for multiple values (--type Bug --type Escalation). |
--base-filename |
jira_phrase_issues |
Base filename for generated CSV output. |
- Jira Server / DC uses
POST /rest/api/2/searchwithstartAt/totalpagination. main.pyfetches the status changelog per issue (GET /rest/api/2/issue/{key}/changelog) to compute time-in-status metrics. This adds one extra API call per issue.- The "Account Name" field is hardcoded to
customfield_23901. - The "Rancher Team" field is hardcoded to
customfield_23900. - AI analysis runs only against your local Ollama endpoint. No issue data is sent to any hosted LLM service.
curl -sS \
-H "Authorization: Bearer ${JIRA_API_TOKEN}" \
-H "Accept: application/json" \
"${JIRA_BASE_URL}/rest/api/2/field" | jq -r '.[] | select(.name == "Rancher Team") | .id'