Skip to content

build: enable JaCoCo coverage report generation across all modules #1

build: enable JaCoCo coverage report generation across all modules

build: enable JaCoCo coverage report generation across all modules #1

Workflow file for this run

name: SonarQube Cloud scan
# Least-privilege per CodeQL's "Workflow does not contain permissions" rule.
# - contents: read — checkout the branch
# - pull-requests: read — let SonarQube Cloud decorate the PR via its own token
permissions:
contents: read
pull-requests: read
# Runs the official SonarQube Cloud scan against the branch on every PR and on
# pushes to main. This complements .github/workflows/sonar.yml (our own self-
# scan): SonarQube Cloud is the canonical reference, so a delta between the
# two surfaces drift in our daemon's behaviour vs. SonarSource's own pipeline.
#
# Setup required (one-time, by the repo admin):
# 1. Sign in to https://sonarcloud.io with the repo's GitHub org/account.
# 2. Import this repo as a SonarQube Cloud project.
# (Project key is conventionally `<github-org>_<repo>`; organisation slug
# is `<github-org>` in lowercase.)
# 3. Configure "Analysis Method" → "With GitHub Actions"; copy the generated
# `SONAR_TOKEN`.
# 4. In this repo: Settings → Secrets and variables → Actions → New
# repository secret named SONAR_TOKEN, paste the token.
#
# Without SONAR_TOKEN the workflow fails fast in the "Verify secrets" step —
# the rest of the pipeline never runs, so a missing token is obvious from the
# job summary.
#
# Why a Maven-driven scan (sonar:sonar) rather than the generic scan-action?
# This is a Maven multi-module project; the Maven plugin auto-discovers
# `src/main/java`, `src/test/java`, JaCoCo XMLs, and the compiled-classes path
# per module. Less configuration to drift out of sync.
on:
pull_request:
branches: [main]
push:
branches: [main]
workflow_dispatch:
jobs:
sonarqube-cloud:
name: SonarQube Cloud
runs-on: ubuntu-latest
# Skip when the token isn't configured (fork PRs, first-run before setup)
# — emits a soft-fail rather than every PR carrying a hard ❌.
if: ${{ github.event_name == 'workflow_dispatch' || github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository }}
steps:
# Full history lets SonarQube Cloud compute new-code coverage and
# author-blame correctly. Without fetch-depth: 0 the scan sees a
# shallow clone and falls back to "all code is new code" per PR.
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
# JDK 17 matches maven.compiler.release in the parent pom.
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '17'
# The JS/TS analyzer plugin spawns Node at scan time. Without this the
# JS/TS sensors silently skip — and our counts then diverge from the
# self-scan, which has the same prerequisite.
- name: Set up Node.js 20
uses: actions/setup-node@v4
with:
node-version: '20'
# Two caches: Maven repo + SonarQube Cloud analysis cache. The Sonar
# cache stores per-language scan state (e.g. JS/TS server-side
# analysis blobs) so reruns of unchanged files are much faster.
- name: Cache Maven repository
uses: actions/cache@v4
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
- name: Cache SonarQube Cloud packages
uses: actions/cache@v4
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: |
${{ runner.os }}-sonar
# Verify SONAR_TOKEN exists before we waste minutes on a full build that
# the scan step would then fail to authenticate. Clear setup hint in
# the failure message — no need to read the workflow header.
- name: Verify secrets
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: |
if [ -z "${SONAR_TOKEN:-}" ]; then
echo "::error::SONAR_TOKEN secret is not set. See the header of this workflow for one-time SonarQube Cloud setup."
exit 1
fi
echo "SONAR_TOKEN configured — proceeding with scan."
# `mvn verify` runs tests AND generates the per-module JaCoCo XMLs that
# the Sonar Maven plugin picks up automatically from
# <module>/target/site/jacoco/jacoco.xml. failIfNoSpecifiedTests=false
# keeps the dist module (no tests) from breaking the reactor.
# We skip the dist module's assembly here — sonar:sonar doesn't need
# the skill bundle, and skipping shaves ~30s.
- name: Build, test, generate JaCoCo XML
run: mvn -B -ntp -pl '!dist' verify -Dsurefire.failIfNoSpecifiedTests=false
# The actual SonarQube Cloud scan via the Maven plugin. Reads
# SONAR_TOKEN from env. Project key + organisation conventions:
# `<github-org>_<repo>` and `<github-org>` lowercased — adjust if
# the SonarCloud project is set up under different identifiers.
- name: SonarQube Cloud scan
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
mvn -B -ntp -pl '!dist' \
org.sonarsource.scanner.maven:sonar-maven-plugin:sonar \
-Dsonar.projectKey=RandomCodeSpace_sonar-predict \
-Dsonar.organization=randomcodespace \
-Dsonar.host.url=https://sonarcloud.io \
-Dsonar.qualitygate.wait=false \
-Dsonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml,../protocol/target/site/jacoco/jacoco.xml,../daemon/target/site/jacoco/jacoco.xml,../cli/target/site/jacoco/jacoco.xml
# Project link printed into the job summary so a reviewer can jump
# straight to the SonarCloud dashboard from the PR Checks tab.
- name: Link to SonarQube Cloud dashboard
if: always()
run: |
{
echo "## SonarQube Cloud"
echo
echo "Reference scan — compare against the in-repo self-scan to confirm parity."
echo
echo "Dashboard: https://sonarcloud.io/project/overview?id=RandomCodeSpace_sonar-predict"
if [ "${{ github.event_name }}" = "pull_request" ]; then
echo "PR view: https://sonarcloud.io/project/issues?id=RandomCodeSpace_sonar-predict&pullRequest=${{ github.event.pull_request.number }}"
fi
} >> "$GITHUB_STEP_SUMMARY"