# Run SonarQube static analysis against the code that just landed on `main` and
# report the results to the self-hosted SonarQube server for review. This is
# intentionally NON-BLOCKING: it triggers on push to main (i.e. AFTER merge),
# not on pull_request, so it never gates a PR. It complements pr-checks.yml
# (which gates PRs) and build-images.yml (which ships images) — this one only
# feeds the dashboard.
#
# Prerequisites (one-time, in the Gitea UI — Repo → Settings → Actions):
#   • Secret   SONAR_TOKEN     — a SonarQube "Analysis" token generated at
#                                My Account → Security in SonarQube for the
#                                runic-gateway-website project (or a global one).
#   • Variable SONAR_HOST_URL  — the SonarQube base URL on your LAN, e.g.
#                                http://192.168.0.56:9000
#     (kept as a variable, not committed, so the internal address stays out of git.)
#
# The runner (self-hosted `ubuntu-latest`, same as the other workflows) must be
# able to reach SONAR_HOST_URL on your network. Nothing here waits on the
# SonarQube Quality Gate, so a failing gate does not fail this job — check the
# dashboard when you want to.

name: SonarQube

on:
  push:
    branches: [main]
  # Allow re-running the analysis on demand from the Actions tab.
  workflow_dispatch: {}

concurrency:
  group: sonarqube-${{ github.ref }}
  cancel-in-progress: true

jobs:
  analysis:
    runs-on: ubuntu-latest
    steps:
      - name: Check out (full history for accurate new-code + blame)
        uses: actions/checkout@v4
        with:
          # SonarQube uses git history to attribute issues to authors and to
          # compute "new code". A shallow clone degrades both.
          fetch-depth: 0

      # SonarQube runs static analysis only — it never executes the test suite,
      # so we must produce a coverage report ourselves and hand it to the
      # scanner (see sonar.javascript.lcov.reportPaths in sonar-project.properties).
      # Node's built-in `lcov` coverage reporter needs Node >= 22.
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm
          cache-dependency-path: server/package-lock.json

      - name: Install server deps
        run: npm ci --prefix server

      - name: Generate server test coverage (LCOV)
        # Run from the repo root (not `--prefix server`) so the LCOV `SF:` paths
        # are emitted as `server/src/...`, matching sonar.sources and letting the
        # scanner resolve them against the project base dir. The server tests stub
        # their models and point the DB pool at a dead port, so no MariaDB is needed.
        run: |
          mkdir -p server/coverage
          node --test --experimental-test-coverage \
            --test-reporter=spec --test-reporter-destination=stdout \
            --test-reporter=lcov --test-reporter-destination=server/coverage/lcov.info \
            --test-reporter=./scripts/sonar-test-reporter.mjs --test-reporter-destination=server/coverage/test-execution.xml \
            server/test/*.test.js

      - name: Generate client test coverage (LCOV)
        # The client's pure-logic modules (lib/, api/, data/) are plain ESM with no
        # browser/DOM deps, so they run on the same built-in runner. Run from the
        # repo root so the `SF:` paths come out as `client/src/...`. No `npm ci`:
        # the tested modules import only relative files + Node built-ins.
        run: |
          mkdir -p client/coverage
          node --test --experimental-test-coverage \
            --test-reporter=spec --test-reporter-destination=stdout \
            --test-reporter=lcov --test-reporter-destination=client/coverage/lcov.info \
            --test-reporter=./scripts/sonar-test-reporter.mjs --test-reporter-destination=client/coverage/test-execution.xml \
            client/test/*.test.js

      - name: Run SonarQube scan
        uses: sonarsource/sonarqube-scan-action@v4
        env:
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
          SONAR_HOST_URL: ${{ vars.SONAR_HOST_URL }}
