chore(ci): scan this repo with SonarQube (phase 4, slice 0) #7

Merged
whitlocktech merged 1 commits from chore/sonarqube into main 2026-08-12 07:37:41 +00:00
Member

First slice of module-system Phase 4 (docs#141 settles the phase's shape). Independent of the rest of it — this touches nothing the other four slices touch, and module-uo is the only repo Phase 4 changes outside website.

Until now this was the one part of the platform that had never been scanned. The 75 files here arrived in the Phase 3 extraction and left their Sonar history behind in core's project, so a whole module's worth of shipped code has no dashboard at all.

Adds sonar-project.properties (project key Module-uo) and a sonarqube.yml mirroring website's: push to main, never a PR gate, nothing waiting on the quality gate.

Two things differ from core's config

Both because this repo is shaped differently, not by preference:

  • There is no src/ to point sonar.sources at — the server half keeps boot.js/core.js/index.js at server/ root beside its subdirectories. So the whole tree is included and the non-source parts are excluded instead. That direction is deliberate: a new top-level server directory is scanned by default rather than silently unscanned, which is the safer way for the list to be wrong.
  • server/scripts and client/scripts are in, not out. checkImports.js and checkExternals.js are the enforcement of MODULE_API.md §5.1 and §3.6, they each carry their own test suite, and both have already shipped defects a reviewer missed. Build code that decides whether a release is allowed out is not throwaway code.

The build ordering is load-bearing here too

The workflow builds the client chunk before running either suite, for the reason pr-checks.yml already spells out: build.test.js and registration.test.js read dist/entry.js and skip without it. Run the other way round, this job reports coverage for a suite that quietly asked less than it looks like it did.

Both suites run from the repo root rather than with --prefix, so the LCOV SF: paths come out repo-root-relative and resolve against sonar.sources. That is why the server suite's --require is spelled out in the workflow instead of reusing npm test --prefix server, whose path is relative to server/.

scripts/sonar-test-reporter.mjs is a copy of core's — SonarQube's "Unit Tests" measure is fed by a separate report from coverage, and without it the dashboard shows a coverage % against an empty Unit Tests tile. A pure leaf build helper, which is the side of the vendoring line that may be copied.

Verified locally

Ran both coverage commands exactly as the workflow does:

Test cases Covered files Reports
server 385 57 LCOV + Generic Test Execution XML, paths repo-root-relative
client 40 8 same

The client's covered-file count is low and honestly so: most of client/src is JSX the DOM-less runner cannot import, which is a known and documented limit of this test harness rather than something this PR should paper over.

Setup

The Module-uo project already exists on the SonarQube instance (confirmed against /api/projects/search — it sits alongside runic-gateway-website, Runic-Gateway-link and Runic-Gateway-Android-app), so the key in sonar-project.properties matches a real dashboard and nothing needs creating.

Still needed once, in the Gitea UI (Repo → Settings → Actions), unless they resolve from org-level settings:

  • Secret SONAR_TOKEN — a SonarQube Analysis token
  • Variable SONAR_HOST_URL

Until both resolve the job runs and fails at the scan step, harmlessly — it gates nothing.


AI disclosure

  • This contribution was AI-assisted (Claude Code).

🤖 Generated with Claude Code

First slice of module-system Phase 4 ([docs#141](https://gitea.whitlocktech.com/RunicGateway/docs/pulls/141) settles the phase's shape). Independent of the rest of it — this touches nothing the other four slices touch, and `module-uo` is the only repo Phase 4 changes outside `website`. Until now this was the one part of the platform that had never been scanned. The 75 files here arrived in the Phase 3 extraction and left their Sonar history behind in **core's** project, so a whole module's worth of shipped code has no dashboard at all. Adds `sonar-project.properties` (project key **`Module-uo`**) and a `sonarqube.yml` mirroring `website`'s: push to `main`, never a PR gate, nothing waiting on the quality gate. ## Two things differ from core's config Both because this repo is shaped differently, not by preference: - **There is no `src/` to point `sonar.sources` at** — the server half keeps `boot.js`/`core.js`/`index.js` at `server/` root beside its subdirectories. So the whole tree is included and the non-source parts are excluded instead. That direction is deliberate: a new top-level server directory is scanned **by default** rather than silently unscanned, which is the safer way for the list to be wrong. - **`server/scripts` and `client/scripts` are in, not out.** `checkImports.js` and `checkExternals.js` *are* the enforcement of MODULE_API.md §5.1 and §3.6, they each carry their own test suite, and both have already shipped defects a reviewer missed. Build code that decides whether a release is allowed out is not throwaway code. ## The build ordering is load-bearing here too The workflow builds the client chunk before running either suite, for the reason `pr-checks.yml` already spells out: `build.test.js` and `registration.test.js` read `dist/entry.js` and **skip** without it. Run the other way round, this job reports coverage for a suite that quietly asked less than it looks like it did. Both suites run from the repo root rather than with `--prefix`, so the LCOV `SF:` paths come out repo-root-relative and resolve against `sonar.sources`. That is why the server suite's `--require` is spelled out in the workflow instead of reusing `npm test --prefix server`, whose path is relative to `server/`. `scripts/sonar-test-reporter.mjs` is a copy of core's — SonarQube's "Unit Tests" measure is fed by a *separate* report from coverage, and without it the dashboard shows a coverage % against an empty Unit Tests tile. A pure leaf build helper, which is the side of the vendoring line that may be copied. ## Verified locally Ran both coverage commands exactly as the workflow does: | | Test cases | Covered files | Reports | | --- | --- | --- | --- | | server | 385 | 57 | LCOV + Generic Test Execution XML, paths repo-root-relative | | client | 40 | 8 | same | The client's covered-file count is low and honestly so: most of `client/src` is JSX the DOM-less runner cannot import, which is a known and documented limit of this test harness rather than something this PR should paper over. ## Setup The **`Module-uo` project already exists** on the SonarQube instance (confirmed against `/api/projects/search` — it sits alongside `runic-gateway-website`, `Runic-Gateway-link` and `Runic-Gateway-Android-app`), so the key in `sonar-project.properties` matches a real dashboard and nothing needs creating. Still needed once, in the Gitea UI (Repo → Settings → Actions), unless they resolve from org-level settings: - Secret **`SONAR_TOKEN`** — a SonarQube *Analysis* token - Variable **`SONAR_HOST_URL`** Until both resolve the job runs and fails at the scan step, harmlessly — it gates nothing. --- ### AI disclosure - [x] This contribution was AI-assisted (Claude Code). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
wtclaude added 1 commit 2026-08-12 07:36:41 +00:00
chore(ci): scan this repo with SonarQube (phase 4, slice 0)
All checks were successful
PR Checks / client-build (pull_request) Successful in 14s
PR Checks / frozen-manifest (pull_request) Successful in 34s
PR Checks / server-tests (pull_request) Successful in 8m50s
62c8ee68b4
Until now this was the one part of the platform that had never been scanned.
The 75 files here arrived in the Phase 3 extraction and left their Sonar
history behind in core's project, so a whole module's worth of shipped code
has no dashboard at all.

Adds sonar-project.properties (project key Module-uo) and a sonarqube.yml
mirroring website's: push to main, never a PR gate, nothing waiting on the
quality gate.

Two things differ from core's config, both because this repo is shaped
differently:

  - There is no src/ to point sonar.sources at — the server half keeps
    boot.js/core.js/index.js at server/ root beside its subdirectories — so
    the whole tree is included and the non-source parts are excluded. That
    direction is deliberate: a new top-level server directory is scanned by
    default rather than silently unscanned.
  - server/scripts and client/scripts are IN. checkImports.js and
    checkExternals.js are the enforcement of MODULE_API.md 5.1 and 3.6, they
    carry their own test suites, and both have already shipped defects a
    reviewer missed. Build code that decides whether a release is allowed out
    is not throwaway code.

The workflow builds the client chunk before running either suite, for the
reason pr-checks.yml already calls load-bearing: build.test.js and
registration.test.js read dist/entry.js and SKIP without it, so the other
order reports coverage for a suite that quietly asked less than it looks like
it did.

Both suites run from the repo root rather than with --prefix, so the LCOV SF:
paths come out repo-root-relative and resolve against sonar.sources. That is
why the server suite's --require is spelled out here instead of reusing
`npm test --prefix server`, whose path is relative to server/.

Verified locally: 385 server test cases across 57 covered files and 40 client
cases, both LCOV and Generic Test Execution XML well-formed with
repo-root-relative paths.

Needs one-time setup in the Gitea UI before it can run — secret SONAR_TOKEN
and variable SONAR_HOST_URL, same as the other repos.

Co-Authored-By: Claude <noreply@anthropic.com>
whitlocktech merged commit 97e2fddfcd into main 2026-08-12 07:37:41 +00:00
whitlocktech deleted branch chore/sonarqube 2026-08-12 07:37:42 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: RunicGateway/Module-uo#7
No description provided.