コンテンツにスキップ

Qodana Cheat Sheet

Overview

Qodana is JetBrains' code quality platform that brings the smart code inspections from JetBrains IDEs to your CI/CD pipeline. It provides comprehensive static analysis, security vulnerability detection, and code quality metrics for multiple programming languages with deep integration into development workflows.

⚠️ Note: Free tier available with limitations. Paid plans start at $0.50 per 1000 lines of code per month.

Getting Started

Installation Methods

# Docker (Recommended)
docker pull jetbrains/qodana-jvm
docker pull jetbrains/qodana-js
docker pull jetbrains/qodana-python
docker pull jetbrains/qodana-php
docker pull jetbrains/qodana-dotnet

# CLI Installation
# Linux/macOS
curl -fsSL https://jb.gg/qodana-cli/install | bash

# Windows (PowerShell)
iex "& { $(irm https://jb.gg/qodana-cli/install-ps1) }"

# Homebrew (macOS)
brew install jetbrains/utils/qodana

# Snap (Linux)
sudo snap install qodana

Quick Start

# Initialize Qodana in project
qodana init

# Run analysis with Docker
docker run --rm -it \
  -v $(pwd):/data/project/ \
  -v $(pwd)/qodana-results:/data/results/ \
  jetbrains/qodana-jvm

# Run with CLI
qodana scan --project-dir . --results-dir ./qodana-results

Project Setup

# qodana.yaml configuration file
version: "1.0"
profile:
  name: qodana.recommended
include:
  - name: All
exclude:
  - name: "Unused import"
  - name: "Spelling"
projectJDK: "11"
bootstrap: |
  set -eu
  echo "Bootstrap script execution"
  ./gradlew build -x test

Language Support

JVM Languages (Java, Kotlin, Scala)

# Qodana JVM Linter
docker run --rm -it \
  -v $(pwd):/data/project/ \
  -v $(pwd)/qodana-results:/data/results/ \
  jetbrains/qodana-jvm

# Supported build tools:
# - Maven
# - Gradle
# - SBT
# - Ant

# Java-specific inspections:
# - Code style violations
# - Null pointer analysis
# - Resource leak detection
# - Performance issues
# - Security vulnerabilities

JavaScript/TypeScript

# Qodana JS Linter
docker run --rm -it \
  -v $(pwd):/data/project/ \
  -v $(pwd)/qodana-results:/data/results/ \
  jetbrains/qodana-js

# Supported frameworks:
# - React
# - Vue.js
# - Angular
# - Node.js
# - Express

# JS/TS inspections:
# - ESLint integration
# - TypeScript compiler checks
# - React-specific issues
# - Async/await problems
# - Performance optimizations

Python

# Qodana Python Linter
docker run --rm -it \
  -v $(pwd):/data/project/ \
  -v $(pwd)/qodana-results:/data/results/ \
  jetbrains/qodana-python

# Python features:
# - PEP 8 compliance
# - Type checking with mypy
# - Security vulnerability detection
# - Code complexity analysis
# - Import optimization

PHP

# Qodana PHP Linter
docker run --rm -it \
  -v $(pwd):/data/project/ \
  -v $(pwd)/qodana-results:/data/results/ \
  jetbrains/qodana-php

# PHP inspections:
# - PSR compliance
# - Security vulnerabilities
# - Performance issues
# - Type safety
# - Framework-specific checks

.NET (C#, VB.NET, F#)

# Qodana .NET Linter
docker run --rm -it \
  -v $(pwd):/data/project/ \
  -v $(pwd)/qodana-results:/data/results/ \
  jetbrains/qodana-dotnet

# .NET features:
# - Roslyn analyzer integration
# - Security rule checks
# - Performance optimizations
# - Code style enforcement
# - Framework compatibility

Configuration

Basic Configuration

# qodana.yaml - Basic setup
version: "1.0"
profile:
  name: qodana.recommended
include:
  - name: All
exclude:
  - name: "Unused import"
  - name: "Spelling"
  - name: "Typo"

Advanced Configuration

# qodana.yaml - Advanced setup
version: "1.0"
profile:
  name: qodana.recommended
  path: .qodana/profiles/custom.xml
include:
  - name: "Code style issues"
  - name: "Probable bugs"
  - name: "Performance"
exclude:
  - name: "Spelling"
  - name: "Unused import"
  - path: "src/test/**"
  - path: "**/*.generated.js"
projectJDK: "11"
bootstrap: |
  set -eu
  echo "Installing dependencies..."
  npm install
  ./gradlew build -x test
failThreshold: 0

Profile Customization

<!-- .qodana/profiles/custom.xml -->
<profile version="1.0">
  <option name="myName" value="Custom Profile" />
  <inspection_tool class="UnusedDeclaration" enabled="true" level="WARNING" enabled_by_default="true" />
  <inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="true" />
  <inspection_tool class="JSUnusedLocalSymbols" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>

Environment Variables

# Common environment variables
export QODANA_TOKEN="your-token-here"
export QODANA_PROJECT_ID="project-id"
export QODANA_BRANCH="main"
export QODANA_REVISION="HEAD"

# Docker environment variables
docker run --rm -it \
  -e QODANA_TOKEN=$QODANA_TOKEN \
  -e QODANA_PROJECT_ID=$QODANA_PROJECT_ID \
  -v $(pwd):/data/project/ \
  -v $(pwd)/qodana-results:/data/results/ \
  jetbrains/qodana-jvm

CLI Commands

Basic Commands

# Initialize project
qodana init

# Scan project
qodana scan

# Scan with specific linter
qodana scan --linter jetbrains/qodana-jvm

# Scan with custom config
qodana scan --config ./custom-qodana.yaml

# Show scan results
qodana show

# View help
qodana --help
qodana scan --help

Advanced CLI Usage

# Scan with custom parameters
qodana scan \
  --project-dir /path/to/project \
  --results-dir /path/to/results \
  --cache-dir /path/to/cache \
  --linter jetbrains/qodana-jvm \
  --config qodana.yaml \
  --property=idea.headless.enable.statistics=false

# Scan specific files/directories
qodana scan --include-paths "src/main/**,lib/**"
qodana scan --exclude-paths "src/test/**,**/*.generated.*"

# Set fail threshold
qodana scan --fail-threshold 10

# Generate SARIF report
qodana scan --sarif-report results.sarif

# Upload results to Qodana Cloud
qodana scan --upload-result

Result Management

# View results in browser
qodana show --port 8080

# Export results
qodana export --format json --output results.json
qodana export --format sarif --output results.sarif

# Compare results between branches
qodana diff --base main --target feature-branch

# Generate baseline
qodana scan --baseline qodana.sarif.json

CI/CD Integration

GitHub Actions

# .github/workflows/qodana.yml
name: Qodana
on:
  workflow_dispatch:
  pull_request:
  push:
    branches:
      - main

jobs:
  qodana:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: write
      checks: write
    steps:
      - uses: actions/checkout@v3
        with:
          ref: ${{ github.event.pull_request.head.sha }}
          fetch-depth: 0

      - name: 'Qodana Scan'
        uses: JetBrains/qodana-action@v2023.2
        with:
          args: --fail-threshold,0
        env:
          QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }}

      - name: Upload SARIF file
        uses: github/codeql-action/upload-sarif@v2
        with:
          sarif_file: ${{ runner.temp }}/qodana/results/qodana.sarif.json

GitLab CI

# .gitlab-ci.yml
qodana:
  stage: test
  image: jetbrains/qodana-jvm:latest
  script:
    - qodana --results-dir $CI_PROJECT_DIR/qodana-results
  artifacts:
    reports:
      codequality: qodana-results/qodana.json
    paths:
      - qodana-results/
    expire_in: 1 week
  only:
    - merge_requests
    - main

Jenkins Pipeline

pipeline {
    agent any

    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }

        stage('Qodana Analysis') {
            steps {
                script {
                    docker.image('jetbrains/qodana-jvm:latest').inside {
                        sh '''
                            qodana --results-dir ./qodana-results \
                                   --fail-threshold 0 \
                                   --sarif-report qodana.sarif
                        '''
                    }
                }
            }
            post {
                always {
                    publishHTML([
                        allowMissing: false,
                        alwaysLinkToLastBuild: true,
                        keepAll: true,
                        reportDir: 'qodana-results',
                        reportFiles: 'report.html',
                        reportName: 'Qodana Report'
                    ])

                    recordIssues(
                        enabledForFailure: true,
                        tools: [sarif(pattern: 'qodana.sarif')]
                    )
                }
            }
        }
    }
}

Azure DevOps

# azure-pipelines.yml
trigger:
- main

pool:
  vmImage: 'ubuntu-latest'

steps:
- task: Docker@2
  displayName: 'Run Qodana Analysis'
  inputs:
    command: 'run'
    arguments: >
      --rm
      -v $(Build.SourcesDirectory):/data/project/
      -v $(Build.ArtifactStagingDirectory)/qodana-results:/data/results/
      jetbrains/qodana-jvm

- task: PublishBuildArtifacts@1
  displayName: 'Publish Qodana Results'
  inputs:
    pathToPublish: '$(Build.ArtifactStagingDirectory)/qodana-results'
    artifactName: 'qodana-results'

Quality Gates and Thresholds

Fail Threshold Configuration

# Set fail threshold (number of problems)
qodana scan --fail-threshold 10

# Fail on any critical issues
qodana scan --fail-threshold 0 --severity critical

# Fail on new issues only
qodana scan --baseline qodana-baseline.sarif.json --fail-threshold 0

Quality Gate Profiles

# qodana.yaml with quality gates
version: "1.0"
profile:
  name: qodana.recommended
failThreshold: 5
include:
  - name: "Critical"
  - name: "High"
exclude:
  - name: "Low"
  - name: "Informational"

Custom Quality Rules

<!-- Custom inspection profile -->
<profile version="1.0">
  <option name="myName" value="Strict Quality Gate" />

  <!-- Critical issues that should fail the build -->
  <inspection_tool class="NullPointerException" enabled="true" level="ERROR" />
  <inspection_tool class="SqlInjection" enabled="true" level="ERROR" />
  <inspection_tool class="XssVulnerability" enabled="true" level="ERROR" />

  <!-- High priority issues -->
  <inspection_tool class="UnusedDeclaration" enabled="true" level="WARNING" />
  <inspection_tool class="DuplicatedCode" enabled="true" level="WARNING" />

  <!-- Disabled for CI -->
  <inspection_tool class="SpellCheckingInspection" enabled="false" />
  <inspection_tool class="TodoComment" enabled="false" />
</profile>

Security Analysis

Security Vulnerability Detection

# Enable security inspections
qodana scan --include "Security"

# Focus on critical security issues
qodana scan \
  --include "SQL injection" \
  --include "XSS" \
  --include "Path traversal" \
  --include "Hardcoded credentials"

Common Security Issues Detected

// SQL Injection Detection
// ❌ Vulnerable code
String query = "SELECT * FROM users WHERE id = " + userId;
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery(query);

// ✅ Fixed code
String query = "SELECT * FROM users WHERE id = ?";
PreparedStatement stmt = connection.prepareStatement(query);
stmt.setString(1, userId);
ResultSet rs = stmt.executeQuery();

// Hardcoded Credentials Detection
// ❌ Vulnerable code
String password = "admin123";
String apiKey = "sk-1234567890abcdef";

// ✅ Fixed code
String password = System.getenv("DB_PASSWORD");
String apiKey = System.getenv("API_KEY");

Security Baseline

# Create security baseline
qodana scan --include "Security" --baseline security-baseline.sarif.json

# Check only new security issues
qodana scan --baseline security-baseline.sarif.json --include "Security"

Performance Analysis

Performance Inspections

# Focus on performance issues
qodana scan --include "Performance"

# Common performance issues detected:
# - Inefficient string concatenation
# - Resource leaks
# - Unnecessary object creation
# - Inefficient collections usage
# - Database query optimization

Performance Examples

// String Concatenation Performance
// ❌ Inefficient
String result = "";
for (String item : items) {
    result += item + ", ";
}

// ✅ Efficient
StringBuilder sb = new StringBuilder();
for (String item : items) {
    sb.append(item).append(", ");
}
String result = sb.toString();

// Resource Leak Detection
// ❌ Resource leak
FileInputStream fis = new FileInputStream("file.txt");
// Missing close() call

// ✅ Proper resource management
try (FileInputStream fis = new FileInputStream("file.txt")) {
    // Use the stream
} // Automatically closed

Code Quality Metrics

Complexity Analysis

# Analyze code complexity
qodana scan --include "Complexity"

# Metrics collected:
# - Cyclomatic complexity
# - Cognitive complexity
# - Lines of code
# - Method length
# - Class size

Duplication Detection

# Detect code duplication
qodana scan --include "Code duplication"

# Configure duplication thresholds in qodana.yaml:
version: "1.0"
profile:
  name: qodana.recommended
duplicates:
  minTokens: 50
  minLines: 10

Technical Debt Assessment

// Technical Debt Examples

// ❌ High technical debt
function processData(data) {
    // TODO: Refactor this method
    if (data) {
        if (data.length > 0) {
            for (let i = 0; i < data.length; i++) {
                if (data[i].status === 'active') {
                    // Complex nested logic
                    if (data[i].type === 'premium') {
                        // More nesting...
                    }
                }
            }
        }
    }
}

// ✅ Refactored code
function processActiveData(data) {
    if (!data?.length) return;

    return data
        .filter(item => item.status === 'active')
        .map(item => processItem(item));
}

function processItem(item) {
    return item.type === 'premium' 
        ? processPremiumItem(item)
        : processStandardItem(item);
}

Reporting and Visualization

HTML Reports

# Generate HTML report
qodana scan --show-report

# Custom report location
qodana scan --results-dir ./custom-results
qodana show --port 8080 --results-dir ./custom-results

SARIF Reports

# Generate SARIF report
qodana scan --sarif-report results.sarif

# Upload to GitHub Security tab
# (automatically done with GitHub Actions integration)

# Convert SARIF to other formats
qodana export --format json --input results.sarif --output results.json

Custom Report Templates

<!-- Custom HTML template -->
<!DOCTYPE html>
<html>
<head>
    <title>Custom Qodana Report</title>
    <style>
        .critical { color: red; font-weight: bold; }
        .high { color: orange; }
        .medium { color: yellow; }
        .low { color: green; }
    </style>
</head>
<body>
    <h1>Code Quality Report</h1>
    <div id="summary">
        <!-- Summary statistics -->
    </div>
    <div id="issues">
        <!-- Issue details -->
    </div>
</body>
</html>

IDE Integration

IntelliJ IDEA Integration

# Qodana plugin for IntelliJ IDEA
# 1. Install Qodana plugin from marketplace
# 2. Configure Qodana settings
# 3. Run analysis from IDE
# 4. View results in tool window

# Plugin features:
# - Run Qodana analysis locally
# - View results in IDE
# - Navigate to issues
# - Configure inspection profiles
# - Integration with VCS

VS Code Integration

# Qodana extension for VS Code
# 1. Install Qodana extension
# 2. Configure workspace settings
# 3. Run analysis command
# 4. View results in problems panel

# Extension commands:
# - Qodana: Scan Project
# - Qodana: Show Results
# - Qodana: Configure
# - Qodana: Upload Results

Command Line Integration

# IDE-like experience in terminal
qodana scan --ide-like

# Open results in default browser
qodana show --open

# Watch mode for development
qodana scan --watch --fail-threshold 0

Advanced Features

Baseline Management

# Create baseline from current state
qodana scan --baseline qodana-baseline.sarif.json

# Update baseline
qodana scan --update-baseline qodana-baseline.sarif.json

# Use baseline to check only new issues
qodana scan --baseline qodana-baseline.sarif.json --fail-threshold 0

Custom Inspections

// Custom inspection example
class CustomInspection : LocalInspectionTool() {
    override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
        return object : JavaElementVisitor() {
            override fun visitMethodCallExpression(expression: PsiMethodCallExpression) {
                super.visitMethodCallExpression(expression)

                if (isDeprecatedMethod(expression)) {
                    holder.registerProblem(
                        expression,
                        "Use of deprecated method",
                        ProblemHighlightType.WARNING
                    )
                }
            }
        }
    }

    private fun isDeprecatedMethod(expression: PsiMethodCallExpression): Boolean {
        // Custom logic to detect deprecated methods
        return false
    }
}

License Compliance

# License detection and compliance
qodana scan --include "License"

# Configure allowed licenses
version: "1.0"
profile:
  name: qodana.recommended
licenseRules:
  allowed:
    - "MIT"
    - "Apache-2.0"
    - "BSD-3-Clause"
  prohibited:
    - "GPL-3.0"
    - "AGPL-3.0"

Troubleshooting

Common Issues

# Out of memory errors
docker run --rm -it \
  -m 4g \
  -v $(pwd):/data/project/ \
  -v $(pwd)/qodana-results:/data/results/ \
  jetbrains/qodana-jvm

# Permission issues
sudo chown -R $USER:$USER qodana-results/

# Network connectivity issues
docker run --rm -it \
  --network host \
  -v $(pwd):/data/project/ \
  -v $(pwd)/qodana-results:/data/results/ \
  jetbrains/qodana-jvm

Performance Optimization

# Optimize for large projects
qodana scan \
  --cache-dir ./qodana-cache \
  --exclude-paths "node_modules/**,target/**,build/**" \
  --include "Critical,High"

# Parallel processing
docker run --rm -it \
  --cpus="4" \
  -m 8g \
  -v $(pwd):/data/project/ \
  -v $(pwd)/qodana-results:/data/results/ \
  jetbrains/qodana-jvm

Debug Mode

# Enable debug logging
qodana scan --log-level debug

# Verbose output
qodana scan --verbose

# Save logs
qodana scan --log-file qodana.log

Best Practices

Configuration Management

# Version control qodana.yaml
# - Keep configuration in repository
# - Use environment-specific configs
# - Document configuration changes
# - Review configuration in PRs

# Example structure:
.qodana/
├── qodana.yaml              # Main configuration
├── profiles/
│   ├── strict.xml          # Strict quality profile
│   └── relaxed.xml         # Relaxed profile for legacy code
├── baselines/
│   ├── main.sarif.json     # Main branch baseline
│   └── legacy.sarif.json   # Legacy code baseline
└── scripts/
    └── bootstrap.sh        # Setup script

CI/CD Best Practices

# Gradual adoption strategy:
# 1. Start with baseline to avoid failing builds
# 2. Gradually reduce fail threshold
# 3. Focus on critical and high-priority issues first
# 4. Regular baseline updates
# 5. Team training and adoption

# Performance considerations:
# - Use caching between builds
# - Exclude unnecessary files/directories
# - Run on appropriate hardware
# - Use incremental analysis when possible

Team Adoption

# Team onboarding:
# 1. Introduce Qodana gradually
# 2. Provide training on code quality
# 3. Set up IDE integration
# 4. Regular review of quality metrics
# 5. Celebrate improvements

# Quality culture:
# - Make quality metrics visible
# - Regular quality reviews
# - Code quality champions
# - Continuous improvement mindset

Resources

Documentation

Community

Training