Using Jira CLI for Extracting Information from Jira for Reporting and Auditing

READER BEWARE: THE FOLLOWING WRITTEN ENTIRELY BY AI WITHOUT HUMAN EDITING.

Introduction

Managing Jira effectively often requires extracting data for reporting, auditing, compliance, and analysis. While the Jira web interface is great for day-to-day work, it can be limiting when you need to automate reports, perform bulk queries, or extract data for external tools. This is where Jira CLI comes in—a powerful, open-source command-line interface that makes interacting with Jira fast, scriptable, and efficient.

This guide explores how to use Jira CLI for extracting information from Jira, with a focus on practical reporting and auditing use cases.

Why Use Jira CLI for Reporting and Auditing?

Advantages Over Web Interface and API

  1. Speed: Command-line operations are much faster than clicking through the web UI
  2. Automation: Easily script repetitive reporting tasks and schedule them with cron
  3. Bulk Operations: Query and process hundreds or thousands of issues at once
  4. Scriptable: Integrate with shell scripts, Python, or other automation tools
  5. Offline Processing: Export data once, then analyze it locally without repeated API calls
  6. Version Control: Track report definitions and queries in git alongside your code
  7. CI/CD Integration: Generate reports automatically as part of your pipeline

Common Use Cases

  • Sprint Reports: Extract all issues from a sprint for retrospective analysis
  • Audit Trails: Document who did what and when for compliance requirements
  • Time Tracking: Export time logs for billing or resource planning
  • SLA Compliance: Monitor issue resolution times and response times
  • Epic Progress: Track progress across multiple epics and teams
  • Dependency Analysis: Identify blockers and dependencies across projects
  • Custom Reports: Generate reports that don’t exist in Jira’s standard reporting

Installation and Setup

Installing Jira CLI

macOS (Homebrew):

brew install ankitpokhrel/jira-cli/jira-cli

Linux:

# Download latest release
curl -sL https://github.com/ankitpokhrel/jira-cli/releases/latest/download/jira_linux_amd64.tar.gz | tar xz
sudo mv jira /usr/local/bin/

Windows (Scoop):

scoop bucket add jira-cli https://github.com/ankitpokhrel/jira-cli
scoop install jira-cli

From Source (Go):

go install github.com/ankitpokhrel/jira-cli/cmd/jira@latest

Initial Configuration

After installation, run the setup wizard:

jira init

You’ll be prompted for:

The configuration is stored in ~/.config/.jira/.config.yml and can be edited manually. Replace the placeholder values with your actual Jira instance details:

server: https://yourcompany.atlassian.net  # Replace with your Jira URL
login: your-email@company.com              # Replace with your Jira email
project:
  key: PROJ                                 # Replace with your project key
  type: Software
installation: Cloud

Testing Your Connection

Verify your setup works:

# View your profile
jira me

# List recent issues
jira issue list --plain

# View a specific issue
jira issue view PROJ-123

Basic Data Extraction

Listing Issues

The issue list command is your primary tool for extracting issue data:

# List all issues in current project
jira issue list

# List with custom JQL query
jira issue list --jql "project = PROJ AND status = 'In Progress'"

# List with specific columns
jira issue list --columns "key,summary,status,assignee,created"

# Export to CSV
jira issue list --plain --no-headers --columns "key,summary,status" > issues.csv

# Get more results (default is 50)
jira issue list --limit 100

# Paginate through results
jira issue list --paginate 25

Working with JQL

Jira Query Language (JQL) is powerful for filtering issues:

# Issues created in the last 30 days
jira issue list --jql "created >= -30d"

# High priority bugs
jira issue list --jql "type = Bug AND priority = High"

# Unresolved issues assigned to a specific user
jira issue list --jql "assignee = 'john.doe' AND status != Done"

# Issues updated this week
jira issue list --jql "updated >= startOfWeek()"

# Complex query with multiple conditions
jira issue list --jql "project = PROJ AND (status = 'In Progress' OR status = 'In Review') AND assignee is not EMPTY ORDER BY priority DESC"

Exporting Issue Details

Get comprehensive issue information:

# View single issue in detail
jira issue view PROJ-123

# Export issue as JSON
jira issue view PROJ-123 --json

# Export multiple issues
for issue in $(jira issue list --plain --no-headers --columns key | head -10); do
  jira issue view "$issue" --json >> issues.json
done

Reporting Use Cases

Sprint Report

Generate a comprehensive sprint report:

#!/bin/bash
# sprint-report.sh - Generate sprint completion report

SPRINT_NAME="Sprint 42"
PROJECT="PROJ"
OUTPUT_FILE="sprint_42_report.txt"

echo "Sprint Report: $SPRINT_NAME" > "$OUTPUT_FILE"
echo "Generated: $(date)" >> "$OUTPUT_FILE"
echo "================================" >> "$OUTPUT_FILE"
echo "" >> "$OUTPUT_FILE"

# All issues in sprint
echo "All Issues in Sprint:" >> "$OUTPUT_FILE"
jira issue list --jql "project = $PROJECT AND sprint = '$SPRINT_NAME'" \
  --plain --columns "key,type,summary,status,assignee" >> "$OUTPUT_FILE"
echo "" >> "$OUTPUT_FILE"

# Completed issues
echo "Completed Issues:" >> "$OUTPUT_FILE"
COMPLETED=$(jira issue list --jql "project = $PROJECT AND sprint = '$SPRINT_NAME' AND status = Done" --plain --no-headers | wc -l)
echo "Total: $COMPLETED" >> "$OUTPUT_FILE"
echo "" >> "$OUTPUT_FILE"

# In Progress issues
echo "In Progress Issues:" >> "$OUTPUT_FILE"
jira issue list --jql "project = $PROJECT AND sprint = '$SPRINT_NAME' AND status = 'In Progress'" \
  --plain --columns "key,summary,assignee" >> "$OUTPUT_FILE"
echo "" >> "$OUTPUT_FILE"

# Blocked issues
echo "Blocked Issues:" >> "$OUTPUT_FILE"
jira issue list --jql "project = $PROJECT AND sprint = '$SPRINT_NAME' AND labels = blocked" \
  --plain --columns "key,summary,assignee" >> "$OUTPUT_FILE"

echo "Report saved to $OUTPUT_FILE"

Epic Progress Report

Track progress across epics:

#!/bin/bash
# epic-progress.sh - Generate epic progress report

PROJECT="PROJ"
OUTPUT="epic_progress.csv"

echo "Epic Key,Epic Summary,Total Issues,Completed,In Progress,To Do" > "$OUTPUT"

# Get all epics
EPICS=$(jira issue list --jql "project = $PROJECT AND type = Epic" --plain --no-headers --columns key)

for epic in $EPICS; do
  EPIC_SUMMARY=$(jira issue view "$epic" --plain | grep "Summary:" | cut -d: -f2-)
  
  # Count issues by status
  TOTAL=$(jira issue list --jql "parent = $epic" --plain --no-headers | wc -l)
  DONE=$(jira issue list --jql "parent = $epic AND status = Done" --plain --no-headers | wc -l)
  IN_PROGRESS=$(jira issue list --jql "parent = $epic AND status = 'In Progress'" --plain --no-headers | wc -l)
  TODO=$(jira issue list --jql "parent = $epic AND status = 'To Do'" --plain --no-headers | wc -l)
  
  echo "$epic,$EPIC_SUMMARY,$TOTAL,$DONE,$IN_PROGRESS,$TODO" >> "$OUTPUT"
done

echo "Epic progress report saved to $OUTPUT"

Time Tracking Report

Extract time logging data for billing or resource planning:

#!/bin/bash
# time-tracking-report.sh - Extract time logs

PROJECT="${1:-PROJ}"
# Default to current month if no dates provided
START_DATE="${2:-$(date -d "$(date +%Y-%m-01)" +%Y-%m-%d)}"
END_DATE="${3:-$(date +%Y-%m-%d)}"

jira issue list --jql "project = $PROJECT AND worklogDate >= '$START_DATE' AND worklogDate <= '$END_DATE'" \
  --columns "key,summary,assignee,timeSpent,timeEstimate" \
  --plain > time_report.csv

echo "Time tracking report generated for $START_DATE to $END_DATE"

Audit Trail Report

Generate audit trail for compliance:

#!/bin/bash
# audit-trail.sh - Generate audit trail report

PROJECT="PROJ"
DAYS=30
OUTPUT="audit_trail_${DAYS}days.txt"

echo "Audit Trail Report" > "$OUTPUT"
echo "Period: Last $DAYS days" >> "$OUTPUT"
echo "Generated: $(date)" >> "$OUTPUT"
echo "================================" >> "$OUTPUT"
echo "" >> "$OUTPUT"

# Issues created
echo "Issues Created:" >> "$OUTPUT"
jira issue list --jql "project = $PROJECT AND created >= -${DAYS}d" \
  --columns "key,summary,creator,created" --plain >> "$OUTPUT"
echo "" >> "$OUTPUT"

# Issues updated
echo "Issues Updated:" >> "$OUTPUT"
jira issue list --jql "project = $PROJECT AND updated >= -${DAYS}d" \
  --columns "key,summary,assignee,updated" --plain >> "$OUTPUT"
echo "" >> "$OUTPUT"

# Issues transitioned to Done
echo "Issues Completed:" >> "$OUTPUT"
jira issue list --jql "project = $PROJECT AND status CHANGED TO Done AFTER -${DAYS}d" \
  --columns "key,summary,assignee,resolutionDate" --plain >> "$OUTPUT"

echo "Audit trail saved to $OUTPUT"

Advanced Extraction Techniques

Using JSON Output for Complex Processing

Jira CLI can output JSON for further processing with tools like jq:

# Extract all high priority bugs as JSON
jira issue list --jql "type = Bug AND priority = High" --json | jq '.'

# Get specific fields
jira issue list --jql "project = PROJ" --json | jq '.issues[] | {key: .key, status: .fields.status.name}'

# Count issues by status
jira issue list --jql "project = PROJ" --json | \
  jq '.issues | group_by(.fields.status.name) | map({status: .[0].fields.status.name, count: length})'

# Extract custom fields
jira issue view PROJ-123 --json | jq '.fields.customfield_10042'

Batch Processing

Process multiple issues efficiently:

#!/bin/bash
# batch-export.sh - Export detailed information for multiple issues

JQL="project = PROJ AND sprint = 'Sprint 42'"
OUTPUT_DIR="./sprint_42_export"

mkdir -p "$OUTPUT_DIR"

# Get issue keys
ISSUES=$(jira issue list --jql "$JQL" --plain --no-headers --columns key)

echo "Exporting $(echo "$ISSUES" | wc -l) issues..."

for issue in $ISSUES; do
  echo "Exporting $issue..."
  
  # Export issue details
  jira issue view "$issue" > "$OUTPUT_DIR/${issue}.txt"
  
  # Export as JSON for programmatic access
  jira issue view "$issue" --json > "$OUTPUT_DIR/${issue}.json"
  
  # Small delay to avoid rate limiting
  sleep 0.5
done

echo "Export complete. Files saved to $OUTPUT_DIR"

Combining with Other Tools

Integrate Jira CLI with other command-line tools:

# Export to Excel-compatible CSV with custom formatting
jira issue list --jql "project = PROJ" --plain --no-headers \
  --columns "key,type,summary,status,priority,assignee,created" | \
  awk -F'\t' '{printf "\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"\n", $1,$2,$3,$4,$5,$6,$7}' \
  > report.csv

# Generate Markdown table
echo "| Key | Summary | Status | Assignee |" > report.md
echo "|-----|---------|--------|----------|" >> report.md
jira issue list --jql "project = PROJ AND status = 'In Progress'" --plain --no-headers \
  --columns "key,summary,status,assignee" | \
  awk -F'\t' '{printf "| %s | %s | %s | %s |\n", $1,$2,$3,$4}' >> report.md

# Email report
jira issue list --jql "project = PROJ AND priority = High AND status != Done" \
  --plain > priority_issues.txt && \
  mail -s "High Priority Issues Report" team@company.com < priority_issues.txt

Automation and Scheduling

Daily Status Report

Create a cron job for daily reports:

# daily-status.sh - Automated daily status report

#!/bin/bash
set -euo pipefail

PROJECT="PROJ"
DATE=$(date +%Y-%m-%d)
REPORT_FILE="daily_status_${DATE}.txt"
RECIPIENT="team@company.com"

{
  echo "Daily Status Report - $DATE"
  echo "================================"
  echo ""
  
  echo "New Issues (Last 24 hours):"
  jira issue list --jql "project = $PROJECT AND created >= -1d" \
    --columns "key,summary,assignee" --plain
  echo ""
  
  echo "Completed Issues (Last 24 hours):"
  jira issue list --jql "project = $PROJECT AND status CHANGED TO Done AFTER -1d" \
    --columns "key,summary,assignee" --plain
  echo ""
  
  echo "Blocked Issues:"
  jira issue list --jql "project = $PROJECT AND labels = blocked AND status != Done" \
    --columns "key,summary,assignee" --plain
  echo ""
  
  echo "High Priority Open Issues:"
  jira issue list --jql "project = $PROJECT AND priority = High AND status != Done" \
    --columns "key,summary,status,assignee" --plain
    
} > "$REPORT_FILE"

# Email the report
if [ -s "$REPORT_FILE" ]; then
  mail -s "Daily Status Report - $DATE" "$RECIPIENT" < "$REPORT_FILE"
  echo "Report sent to $RECIPIENT"
else
  echo "Report is empty, not sending"
fi

Add to crontab:

# Run daily at 9 AM
0 9 * * * /path/to/daily-status.sh

Weekly Summary

Generate comprehensive weekly reports:

#!/bin/bash
# weekly-summary.sh - Weekly team summary

PROJECT="PROJ"
WEEK=$(date +%Y-W%U)
OUTPUT="weekly_summary_${WEEK}.html"

cat > "$OUTPUT" << EOF
<!DOCTYPE html>
<html>
<head>
  <title>Weekly Summary - Week $WEEK</title>
  <style>
    body { font-family: Arial, sans-serif; margin: 40px; }
    h1 { color: #0052CC; }
    h2 { color: #172B4D; border-bottom: 2px solid #0052CC; padding-bottom: 5px; }
    table { border-collapse: collapse; width: 100%; margin: 20px 0; }
    th, td { padding: 12px; text-align: left; border: 1px solid #ddd; }
    th { background-color: #0052CC; color: white; }
    tr:nth-child(even) { background-color: #f2f2f2; }
  </style>
</head>
<body>
  <h1>Weekly Summary - Week $WEEK</h1>
  <p>Generated: $(date)</p>
  
  <h2>Issues Created This Week</h2>
  <table>
    <tr><th>Key</th><th>Type</th><th>Summary</th><th>Assignee</th><th>Status</th></tr>
EOF

jira issue list --jql "project = $PROJECT AND created >= -7d" \
  --plain --no-headers --columns "key,type,summary,assignee,status" | \
  awk -F'\t' '{printf "<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>\n", $1,$2,$3,$4,$5}' >> "$OUTPUT"

cat >> "$OUTPUT" << EOF
  </table>
  
  <h2>Issues Completed This Week</h2>
  <table>
    <tr><th>Key</th><th>Summary</th><th>Assignee</th><th>Resolution Date</th></tr>
EOF

jira issue list --jql "project = $PROJECT AND status CHANGED TO Done AFTER -7d" \
  --plain --no-headers --columns "key,summary,assignee,resolutionDate" | \
  awk -F'\t' '{printf "<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>\n", $1,$2,$3,$4}' >> "$OUTPUT"

cat >> "$OUTPUT" << EOF
  </table>
</body>
</html>
EOF

echo "Weekly summary generated: $OUTPUT"

# Convert to PDF if wkhtmltopdf is available
if command -v wkhtmltopdf &> /dev/null; then
  wkhtmltopdf "$OUTPUT" "${OUTPUT%.html}.pdf"
  echo "PDF version created"
fi

Custom Fields and Advanced Queries

Working with Custom Fields

Find and use custom fields:

# View all fields for an issue (including custom fields)
jira issue view PROJ-123 --json | jq '.fields' | grep customfield

# Extract specific custom field
jira issue view PROJ-123 --json | jq '.fields.customfield_10042'

# Query by custom field
jira issue list --jql "project = PROJ AND customfield_10042 = 'value'"

Saved Filters

Use Jira saved filters:

# List using a saved filter
jira issue list --jql "filter = 'My Team Issues'"

# Export from multiple filters
for filter in "Sprint Backlog" "In Review" "Blocked"; do
  jira issue list --jql "filter = '$filter'" --plain > "${filter// /_}.txt"
done

Best Practices for Reporting and Auditing

1. Rate Limiting and Performance

# Add delays in loops to avoid rate limiting
for issue in $ISSUES; do
  jira issue view "$issue"
  sleep 1  # Wait 1 second between requests
done

# Process in smaller batches
BATCH_SIZE=50
jira issue list --limit $BATCH_SIZE --paginate

2. Error Handling

#!/bin/bash
set -euo pipefail  # Exit on error, undefined variable, or pipe failure

# Function with error handling
export_issue() {
  local issue=$1
  local output_dir=$2
  
  if ! jira issue view "$issue" > "$output_dir/${issue}.txt" 2>&1; then
    echo "Error exporting $issue" >&2
    return 1
  fi
  
  return 0
}

# Use with trap for cleanup
cleanup() {
  echo "Cleaning up temporary files..."
  rm -f /tmp/jira-export-*
}
trap cleanup EXIT

# Retry logic
retry_count=0
max_retries=3

while [ $retry_count -lt $max_retries ]; do
  if jira issue list --jql "project = PROJ"; then
    break
  else
    retry_count=$((retry_count + 1))
    echo "Attempt $retry_count failed, retrying..." >&2
    sleep 5
  fi
done

3. Secure Credential Management

# Use environment variables for sensitive data
export JIRA_API_TOKEN="your-token-here"

# Or use a secrets manager
JIRA_TOKEN=$(vault kv get -field=token secret/jira/api)

# Never commit credentials to version control
echo ".jira-credentials" >> .gitignore

4. Output Formatting

# Make output readable
jira issue list --plain --columns "key,summary,status,assignee" | column -t -s $'\t'

# Add timestamps to logs
log() {
  echo "[$(date +'%Y-%m-%d %H:%M:%S')] $*"
}

log "Starting report generation..."

5. Documentation

#!/bin/bash
# report-generator.sh
#
# Purpose: Generate comprehensive project status reports
# Author: Your Name
# Date: 2025-11-05
# Usage: ./report-generator.sh <project-key> <output-dir>
#
# Requirements:
#   - jira-cli installed and configured
#   - jq for JSON processing
#   - write access to output directory
#
# Example:
#   ./report-generator.sh PROJ ./reports

Integration with CI/CD

GitHub Actions Example

# .github/workflows/jira-report.yml
name: Daily Jira Report

on:
  schedule:
    - cron: '0 9 * * 1-5'  # Weekdays at 9 AM
  workflow_dispatch:  # Manual trigger

jobs:
  generate-report:
    runs-on: ubuntu-latest
    
    steps:
      - uses: actions/checkout@v3
      
      - name: Install Jira CLI
        run: |
          curl -sL https://github.com/ankitpokhrel/jira-cli/releases/latest/download/jira_linux_amd64.tar.gz | tar xz
          sudo mv jira /usr/local/bin/
                    
      - name: Configure Jira CLI
        env:
          JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }}
        run: |
          mkdir -p ~/.config/.jira
          cat > ~/.config/.jira/.config.yml << EOF
          server: https://yourcompany.atlassian.net
          login: ${{ secrets.JIRA_EMAIL }}
          EOF
          # Set API token in environment for jira-cli
          echo "JIRA_API_TOKEN=$JIRA_API_TOKEN" >> $GITHUB_ENV
                    
      - name: Generate Report
        run: |
          ./scripts/daily-report.sh > report.txt
                    
      - name: Upload Report
        uses: actions/upload-artifact@v3
        with:
          name: jira-report
          path: report.txt
          
      - name: Send Notification
        uses: slackapi/slack-github-action@v1
        with:
          payload: |
            {
              "text": "Daily Jira report generated",
              "attachments": [{
                "text": "Report available in workflow artifacts"
              }]
            }            
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

Jenkins Pipeline Example

// Jenkinsfile
pipeline {
    agent any
    
    triggers {
        cron('0 9 * * 1-5')  // Weekdays at 9 AM
    }
    
    stages {
        stage('Install Jira CLI') {
            steps {
                sh '''
                    if ! command -v jira &> /dev/null; then
                        curl -sL https://github.com/ankitpokhrel/jira-cli/releases/latest/download/jira_linux_amd64.tar.gz | tar xz
                        sudo mv jira /usr/local/bin/
                    fi
                '''
            }
        }
        
        stage('Generate Report') {
            steps {
                withCredentials([string(credentialsId: 'jira-api-token', variable: 'JIRA_TOKEN')]) {
                    sh '''
                        export JIRA_API_TOKEN=$JIRA_TOKEN
                        ./scripts/weekly-report.sh
                    '''
                }
            }
        }
        
        stage('Archive Report') {
            steps {
                archiveArtifacts artifacts: '*.txt,*.csv,*.html', fingerprint: true
            }
        }
        
        stage('Notify') {
            steps {
                emailext(
                    subject: "Weekly Jira Report - ${env.BUILD_ID}",
                    body: "Weekly Jira report has been generated. See attached artifacts.",
                    to: 'team@company.com',
                    attachmentsPattern: '*.html'
                )
            }
        }
    }
}

Troubleshooting

Common Issues

Authentication Failed

# Verify credentials
jira me

# Re-initialize configuration
jira init --force

# Check config file
cat ~/.config/.jira/.config.yml

Empty Results

# Verify JQL syntax
jira issue list --jql "project = PROJ" --debug

# Test in Jira web UI first
# Copy the JQL from Issues → Search

# Check project key
jira project list

Rate Limiting

# Add delays between requests
sleep 1

# Reduce batch size
jira issue list --limit 25

# Use pagination
jira issue list --paginate 10

Custom Fields Not Showing

# View all fields
jira issue view PROJ-123 --json | jq '.fields | keys'

# Find custom field ID
jira issue view PROJ-123 --json | jq '.fields | to_entries | .[] | select(.key | startswith("customfield"))'

Conclusion

Jira CLI is a powerful tool for extracting information from Jira for reporting and auditing purposes. By combining it with shell scripting, you can:

  • Automate repetitive reporting tasks
  • Generate custom reports not available in Jira
  • Extract data for compliance and audit requirements
  • Integrate Jira data into your CI/CD pipelines
  • Schedule regular status updates and summaries
  • Process large volumes of issues efficiently

The examples in this guide provide a solid foundation for building your own reporting and auditing workflows. Start with simple queries and gradually build more complex automation as your needs grow.

Key Takeaways

  1. Start Simple: Begin with basic jira issue list commands and gradually add complexity
  2. Use JQL: Master Jira Query Language for precise data extraction
  3. Automate Early: Schedule reports with cron or CI/CD pipelines
  4. Handle Errors: Add retry logic and error handling to production scripts
  5. Document Everything: Keep your scripts well-documented and version controlled
  6. Respect Limits: Implement rate limiting and pagination for large queries
  7. Secure Credentials: Never commit API tokens to version control

Next Steps

  • Explore the Jira CLI documentation
  • Build your first automated report
  • Share your scripts with your team
  • Integrate with your existing tools and workflows
  • Contribute back to the Jira CLI project if you develop useful features

Resources