Analyze SonarCloud quality issues for a specific PR. Generates comprehensive report with metrics, top violators, and action plan.
Core principle: Analysis-only = no code changes, pure insight.
$SONARQUBE_TOKEN environment variable# Set SonarQube token (add to ~/.bashrc or ~/.zshrc)
export SONARQUBE_TOKEN="your_token_here"
# Verify token is set
echo $SONARQUBE_TOKEN
To get token:
Configure your SonarCloud project details:
# Add to project's CLAUDE.md or as environment variables
SONAR_ORGANIZATION="your-org-name"
SONAR_PROJECT_KEY="your-org_your-project"
SONAR_BASE_URL="https://sonarcloud.io/api"
If not set: Ask user to provide organization and project key.
Important: Direct curl with -u "$SONARQUBE_TOKEN:" fails in zsh due to authentication parsing. Use bash script wrapper:
# Create temporary bash script to handle authentication
cat > /tmp/fetch_sonar.sh << 'SCRIPT'
#!/bin/bash
curl -s -u "${SONARQUBE_TOKEN}:" \
"https://sonarcloud.io/api/issues/search?componentKeys=${SONAR_PROJECT_KEY}&pullRequest=$1&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true&ps=500"
SCRIPT
chmod +x /tmp/fetch_sonar.sh
/tmp/fetch_sonar.sh $PR_NUMBER > /tmp/sonar_pr_$PR_NUMBER.json
API Parameters:
componentKeys: Your project keypullRequest: PR numberissueStatuses: OPEN,CONFIRMED (exclude resolved)sinceLeakPeriod: Only new issues in this PRps: Page size (max 500)Create Node.js analysis script at /tmp/sonar_analyze.js:
const fs = require('fs');
const prNumber = process.argv[2];
const data = JSON.parse(fs.readFileSync(`/tmp/sonar_pr_${prNumber}.json`, 'utf8'));
const issues = data.issues || [];
// Group by severity
const bySeverity = issues.reduce((acc, i) => {
acc[i.severity] = (acc[i.severity] || 0) + 1;
return acc;
}, {});
// Group by type
const byType = issues.reduce((acc, i) => {
acc[i.type] = (acc[i.type] || 0) + 1;
return acc;
}, {});
// Group by file
const byFile = issues.reduce((acc, i) => {
const file = i.component.split(':')[1] || i.component;
acc[file] = (acc[file] || 0) + 1;
return acc;
}, {});
// Group by rule
const byRule = issues.reduce((acc, i) => {
if (!acc[i.rule]) {
acc[i.rule] = {
count: 0,
severity: i.severity,
message: i.message
};
}
acc[i.rule].count++;
return acc;
}, {});
// Output structured data
console.log(JSON.stringify({
total: data.total,
bySeverity,
byType,
topFiles: Object.entries(byFile)
.sort((a, b) => b[1] - a[1])
.slice(0, 10),
topRules: Object.entries(byRule)
.map(([rule, d]) => ({ rule, ...d }))
.sort((a, b) => b.count - a.count)
.slice(0, 5)
}, null, 2));
Run analysis:
node /tmp/sonar_analyze.js $PR_NUMBER > /tmp/sonar_analysis_$PR_NUMBER.json
Generate formatted report from analysis:
๐ SonarCloud Analysis - PR #XXX
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
๐ EXECUTIVE SUMMARY
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Total Issues: {TOTAL}
By Severity:
๐ด Blocker/Critical: {COUNT} ({PERCENTAGE}%)
๐ก Major: {COUNT} ({PERCENTAGE}%)
๐ต Minor/Info: {COUNT} ({PERCENTAGE}%)
By Type:
๐ Bugs: {COUNT}
๐ก๏ธ Vulnerabilities: {COUNT}
๐งน Code Smells: {COUNT}
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
๐ TOP 10 FILES WITH ISSUES
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
1. src/components/UserProfile.tsx - 8 issues
2. src/services/auth.service.ts - 5 issues
3. src/utils/validation.ts - 4 issues
...
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๏ธ TOP 5 VIOLATED RULES
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
1. typescript:S1854 (MAJOR) - 12 occurrences
"Dead stores should be removed"
2. typescript:S3776 (CRITICAL) - 8 occurrences
"Cognitive Complexity of functions should not be too high"
3. typescript:S1186 (MINOR) - 6 occurrences
"Functions should not be empty"
...
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
ACTION PLAN
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Priority 1 - CRITICAL/BLOCKER ({COUNT} issues):
โข Fix immediately before merge
โข Focus on: {TOP_FILES}
Priority 2 - MAJOR ({COUNT} issues):
โข Address in this PR if possible
โข Consider technical debt ticket if extensive
Priority 3 - MINOR/INFO ({COUNT} issues):
โข Can be addressed in follow-up PR
โข Add to backlog for refactoring sprint
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
๐ LINKS
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
View in SonarCloud:
https://sonarcloud.io/project/pull_requests_list?id={PROJECT_KEY}&pullRequest={PR_NUMBER}
| SonarCloud | Symbol | Priority | Action |
|---|---|---|---|
| BLOCKER | ๐ด | P0 | Fix immediately |
| CRITICAL | ๐ด | P0 | Fix immediately |
| MAJOR | ๐ก | P1 | Fix in this PR |
| MINOR | ๐ต | P2 | Consider for follow-up |
| INFO | ๐ต | P3 | Optional improvement |
| Type | Symbol | Description |
|---|---|---|
| BUG | ๐ | Code that is demonstrably wrong |
| VULNERABILITY | ๐ก๏ธ | Security issues |
| CODE_SMELL | ๐งน | Maintainability issue |
| SECURITY_HOTSPOT | ๐ | Security-sensitive code to review |
Always clean up temporary files after execution:
rm -f /tmp/fetch_sonar.sh
rm -f /tmp/sonar_pr_$PR_NUMBER.json
rm -f /tmp/sonar_analyze.js
rm -f /tmp/sonar_analysis_$PR_NUMBER.json
| Error | Cause | Action |
|---|---|---|
| Token not set | $SONARQUBE_TOKEN missing |
Ask user to export token |
| 401 Unauthorized | Invalid or expired token | Request new token from SonarCloud |
| 404 Not Found | PR doesn't exist in SonarCloud | Verify PR number and project key |
| Empty response | No issues found | Report clean PR, congratulate team |
| >500 issues | Pagination limit reached | Warn about incomplete data, suggest filtering |
| Network error | API unreachable | Check internet connection, retry |
Create .sonarcloud.properties or add to CLAUDE.md:
# SonarCloud Configuration
SONAR_ORGANIZATION=your-org
SONAR_PROJECT_KEY=your-org_your-project
SONAR_EXCLUSIONS=**/*.test.ts,**/*.spec.ts,**/migrations/**
SONAR_COVERAGE_EXCLUSIONS=**/*.test.ts,src/test/**
SonarCloud API limits:
Tip: Cache results for repeated queries to same PR.
- name: SonarQube Analysis
run: |
export SONARQUBE_TOKEN=${{ secrets.SONAR_TOKEN }}
export SONAR_PROJECT_KEY="${{ secrets.SONAR_PROJECT }}"
claude -p "/sonarqube ${{ github.event.pull_request.number }}"
Add to .claude/hooks/pre-merge.sh:
#!/bin/bash
PR_NUMBER=$(gh pr view --json number -q .number)
claude -p "/sonarqube $PR_NUMBER"
Never:
/tmp (cleanup required)Always:
# Only show critical/blocker issues
/sonarqube 123 --severity BLOCKER,CRITICAL
# Only show bugs and vulnerabilities
/sonarqube 123 --types BUG,VULNERABILITY
# Specific file pattern
/sonarqube 123 --files "src/services/**"
# Compare issues across PRs
/sonarqube 123,124,125 --compare
Cause: Invalid or missing token
Fix:
# Regenerate token in SonarCloud
# Export new token
export SONARQUBE_TOKEN="new_token_here"
Cause: Analysis not yet complete or PR not analyzed
Fix: Wait for SonarCloud analysis to complete (~2-5 minutes after PR creation)
Cause: Wrong project key
Fix: Verify project key in SonarCloud URL:
https://sonarcloud.io/project/overview?id=YOUR_PROJECT_KEY
# Basic usage
/sonarqube 170
# With PR prefix
/sonarqube PR #234
# Using PR URL
/sonarqube https://github.com/org/repo/pull/170
# Custom severity filter (if implemented)
/sonarqube 170 --critical-only
PR Number: $ARGUMENTS