Skip to content

SonarQube Analysis #3391

SonarQube Analysis

SonarQube Analysis #3391

Workflow file for this run

name: SonarQube Analysis
on:
workflow_run:
workflows: [ "Gradle Build with Kotlin 2.0 and Java 21" ]
types: [ completed ]
workflow_dispatch: # Allow manual trigger
permissions:
contents: read
checks: write
pull-requests: read # Required for PR analysis
actions: read # Required to download artifacts from the triggering gradle-java21.yml run
packages: read # Required for GitHub Packages (kDisco dependency)
concurrency:
group: ${{ github.workflow }}-${{ github.event.workflow_run.head_branch || github.ref }}
cancel-in-progress: true
env:
JAVA_VERSION: '21'
MAVEN_OPTS: '-Xmx512m'
GRADLE_OPTS: '-Xmx512m -XX:MaxMetaspaceSize=512m'
jobs:
sonarqube:
name: SonarQube Code Analysis
runs-on: ubuntu-latest
timeout-minutes: 20
if: github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success'
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
# Check out the exact commit gradle-java21.yml built — github.sha is meaningless
# for a workflow_run event (it would resolve to the default branch tip instead).
ref: ${{ github.event.workflow_run.head_sha || github.sha }}
# Fetch full history for better analysis (blame information, issue assignment)
fetch-depth: 0
- name: Set up JDK ${{ env.JAVA_VERSION }}
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: ${{ env.JAVA_VERSION }}
- name: Cache SonarQube packages
uses: actions/cache@v4
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: |
${{ runner.os }}-sonar
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
with:
gradle-version: wrapper
cache-read-only: ${{ github.ref != 'refs/heads/main' && github.ref != 'refs/heads/develop' }}
- name: Make Gradle wrapper executable
run: chmod +x gradlew
- name: Download build/test outputs from gradle-java21.yml
uses: actions/download-artifact@v4
with:
name: sonar-inputs-${{ github.event.workflow_run.head_sha }}
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
path: .
- name: Generate coverage report summary
if: always()
run: |
if [ -f desktop-ui/build/reports/jacoco/test/jacocoTestReport.xml ]; then
echo "## Code Coverage Report" >> $GITHUB_STEP_SUMMARY
echo "JaCoCo coverage data reused from gradle-java21.yml (no re-run of tests)" >> $GITHUB_STEP_SUMMARY
fi
# SonarCloud Analysis (for public repositories)
# Requires SONAR_TOKEN and SONAR_ORGANIZATION secrets configured in GitHub
# If secrets are not configured, this step will skip gracefully
#
# Reuses gradle-java21.yml's compiled classes/test-results/jacoco XML (downloaded above)
# instead of rebuilding and retesting — the :desktop-ui:test, :desktop-ui:integrationTest,
# :desktop-ui:jacocoTestReport, :core:jvmTest, :core:integrationTest and
# :core:jacocoTestReport tasks that "sonar" hard-depends on (build.gradle.kts) are
# explicitly excluded so Gradle doesn't re-walk that graph.
- name: SonarCloud Scan
env:
GITHUB_ACTOR: ${{ github.actor }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_ORGANIZATION: ${{ secrets.SONAR_ORGANIZATION }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
if [ -z "$SONAR_TOKEN" ]; then
echo "⚠️ SONAR_TOKEN not configured - skipping SonarCloud analysis"
echo "To enable: Add SONAR_TOKEN secret in repository settings"
exit 0
fi
if [ -z "$SONAR_ORGANIZATION" ]; then
echo "⚠️ SONAR_ORGANIZATION not configured - skipping SonarCloud analysis"
echo "To enable: Add SONAR_ORGANIZATION secret in repository settings"
exit 0
fi
echo "🔍 Running SonarCloud analysis..."
# PR context comes from the workflow_run event's pull_requests[] array, which GitHub
# populates for same-repo branches with an open PR regardless of whether the
# triggering gradle-java21.yml run itself fired on push or pull_request.
PR_ARGS=""
PR_COUNT=$(jq 'length' <<< '${{ toJson(github.event.workflow_run.pull_requests) }}')
if [ "$PR_COUNT" -gt 0 ]; then
PR_NUMBER=$(jq -r '.[0].number' <<< '${{ toJson(github.event.workflow_run.pull_requests) }}')
PR_BASE=$(jq -r '.[0].base.ref' <<< '${{ toJson(github.event.workflow_run.pull_requests) }}')
PR_ARGS="-Dsonar.pullrequest.key=$PR_NUMBER -Dsonar.pullrequest.branch=${{ github.event.workflow_run.head_branch }} -Dsonar.pullrequest.base=$PR_BASE"
echo "PR analysis mode: PR #$PR_NUMBER (${{ github.event.workflow_run.head_branch }} → $PR_BASE)"
fi
./gradlew sonar \
-x :desktop-ui:test -x :desktop-ui:integrationTest -x :desktop-ui:jacocoTestReport \
-x :core:jvmTest -x :core:integrationTest -x :core:jacocoTestReport \
-Dsonar.host.url=https://sonarcloud.io \
-Dsonar.organization=$SONAR_ORGANIZATION \
-Dsonar.token=$SONAR_TOKEN \
$PR_ARGS \
--no-daemon --warning-mode=all --stacktrace
echo "✓ SonarCloud analysis completed successfully"
# Alternative: Local/Enterprise SonarQube server
# Uncomment and configure if using self-hosted SonarQube
# - name: SonarQube Scan (Self-hosted)
# if: env.SONAR_TOKEN != '' && env.SONAR_HOST_URL != ''
# env:
# SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
# SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
# run: |
# ./gradlew sonar \
# -Dsonar.host.url=${{ secrets.SONAR_HOST_URL }} \
# -Dsonar.token=${{ secrets.SONAR_TOKEN }} \
# --no-daemon --warning-mode=all --stacktrace
- name: SonarQube Quality Gate Check
if: success()
run: |
echo "✓ SonarCloud analysis completed"
echo "Quality Gate status will be available at SonarQube dashboard"
echo "View results at: https://sonarcloud.io/project/overview?id=bedaHovorka_interlockSim"
echo ""
echo "Note: Quality gate waiting is disabled by default for legacy code"
echo "Enable in build.gradle.kts: sonar.qualitygate.wait=true"
# Optional: Comment PR with SonarQube results link
# Requires additional permissions and SonarCloud PR decoration enabled