Commit Graph

9 Commits

Author SHA1 Message Date
2f3e8f7df5 ci(sonarqube): report test execution so the Unit Tests measure populates
All checks were successful
PR Checks / bot-install (pull_request) Successful in 14s
PR Checks / client-build (pull_request) Successful in 23s
PR Checks / server-tests (pull_request) Successful in 9m25s
The lcov reports only feed SonarQube's Coverage metric — the "Unit Tests" tile
stayed "-" because we never provided a test-execution report (a separate input
via sonar.testExecutionReportPaths, in SonarQube's own Generic Test Execution
XML format, which the lcov/junit reporters don't produce).

Add a dependency-free custom node:test reporter (scripts/sonar-test-reporter.mjs)
that emits that XML — repo-root-relative <file path> entries matching sonar.tests,
integer-ms durations — and wire it into both the server and client coverage runs
in sonarqube.yml, plus sonar.testExecutionReportPaths in sonar-project.properties.

Verified locally: server 380 + client 43 test cases, well-formed XML, all three
reporters (spec/lcov/sonar) coexist in one `node --test` invocation.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-21 01:16:08 -05:00
886a504152 test(client): unit-test the pure-logic modules + wire coverage into CI/Sonar
All checks were successful
PR Checks / bot-install (pull_request) Successful in 15s
PR Checks / client-build (pull_request) Successful in 44s
PR Checks / server-tests (pull_request) Successful in 9m36s
Stand up a client test suite on Node's built-in runner (no vitest/jsdom — the
targeted modules are plain ESM with no browser/DOM deps) and cover the
meaningful client logic, not presentational components:

- api/client.js: the fetch wrapper — always sends the session cookie, maps a
  non-2xx response to a thrown ApiError (body.message → statusText fallback),
  resolves an empty body to null, sets Content-Type for JSON but NOT for raw
  FormData uploads, and builds/encodes query strings + path params.
- lib/shardEvents.js: describe() across event kinds (payload vs live frame,
  actor name→acct→"Someone" fallback, sale pluralization, champ.update
  branches) and the categoryOf table-consistency check.
- data/regionBuckets.js: the presence roll-up, incl. the first-match-wins
  ordering and the "buckets always reconcile to the total" invariant.
- lib/heroLayout.js: parseLayout's version/shape guard and heroBackground's
  default-vs-custom branch.
- lib/format.js: the date/label formatters + relative-time buckets.

Wiring so these actually count:
- client/package.json gains a `test` script (node --test);
- pr-checks.yml runs the client tests as a PR gate;
- sonarqube.yml generates a client LCOV report and sonar-project.properties
  feeds it alongside the server report (SF paths resolve to client/src/...).

43 client tests; coverage on the tested modules: format/regionBuckets/
heroLayout 100%, api client 86%, shardEvents 80%.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-21 00:38:53 -05:00
e515fc0c9d ci(sonarqube): generate and report server test coverage
All checks were successful
PR Checks / bot-install (pull_request) Successful in 18s
PR Checks / server-tests (pull_request) Successful in 44s
PR Checks / client-build (pull_request) Successful in 9m24s
SonarQube reported 0% coverage because the analysis workflow never ran
the test suite — the scanner does static analysis only and was handed no
coverage report, and sonar-project.properties defined no report path.

Generate an LCOV report in sonarqube.yml before the scan using Node's
built-in test coverage (run from the repo root so SF: paths are
server/src/... and resolve against the project base dir), and point
the scanner at it via sonar.javascript.lcov.reportPaths. Node's lcov
coverage reporter needs Node >= 22, so the coverage job pins node 22.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-20 23:46:44 -05:00
c54bb54834 ci(sonarqube): add non-blocking SonarQube analysis on push to main
All checks were successful
PR Checks / bot-install (pull_request) Successful in 1m16s
PR Checks / server-tests (pull_request) Successful in 9m41s
PR Checks / client-build (pull_request) Successful in 10m39s
Wire the self-hosted SonarQube server into Gitea via a Gitea Actions
workflow. Runs on push to `main` (post-merge) and workflow_dispatch, so
it feeds the dashboard without gating any PR. Adds sonar-project.properties
(project key runic-gateway-website; server/client/bot sources, server tests,
node_modules/dist/generated excluded).

Requires two one-time Gitea settings: secret SONAR_TOKEN and variable
SONAR_HOST_URL. The scan does not wait on the Quality Gate, keeping it
fully non-blocking.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-20 21:43:00 -05:00
Claude
d441e92029 chore: add open-source governance files (GPLv3 + contributing docs)
All checks were successful
PR Checks / client-build (pull_request) Successful in 9m24s
PR Checks / server-tests (pull_request) Successful in 10m32s
PR Checks / bot-install (pull_request) Successful in 9m20s
Add standard open-source project files:
- LICENSE.md — GNU GPL v3.0 or later (verbatim)
- CONTRIBUTING.md — setup, workflow, and required AI-usage disclosure
- CONTRIBUTORS.md — maintainers, contributors, AI-assistance policy
- CODE_OF_CONDUCT.md — Contributor Covenant 2.1
- SECURITY.md — private vulnerability reporting
- .gitea/ISSUE_TEMPLATE/* + PULL_REQUEST_TEMPLATE.md
- README: License section (Copyright (C) 2026 Runic Gateway)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XmHdsbnLzDMAVQkAoTQSBe
2026-07-18 19:10:55 -05:00
0facdb2b2a ci(deploy): correct deploy runner label to uom-deploy-runner
All checks were successful
PR Checks / server-tests (pull_request) Successful in 9m29s
PR Checks / client-build (pull_request) Successful in 9m57s
PR Checks / bot-install (pull_request) Successful in 9m23s
The deploy job referenced a runner labelled `uom_deploy`, which doesn't
match the actual self-hosted runner (`uom-deploy-runner`), so the job
would queue forever waiting for a runner that never picks it up. Update
the `runs-on` label (and the two doc comments) to the real label.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 05:32:02 -05:00
97d95052db ci(deploy): auto-deploy prod stack after image build on merge to main
All checks were successful
PR Checks / server-tests (pull_request) Successful in 10m20s
PR Checks / bot-install (pull_request) Successful in 9m39s
PR Checks / client-build (pull_request) Successful in 13m0s
Add a `deploy` job to build-images.yml that runs on the self-hosted
`uom_deploy` runner and, via `needs: build`, fires only after a clean
image build+push. It pulls the fresh :latest images and recreates the
stack (pull → down → up -d) from /home/perry/website. Guarded on
refs/heads/main so a workflow_dispatch off another branch can't deploy.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 05:03:01 -05:00
34c511c8d0 ci: gate PRs into main on server tests + client build
All checks were successful
PR Checks / server-tests (pull_request) Successful in 11m35s
PR Checks / client-build (pull_request) Successful in 9m42s
PR Checks / bot-install (pull_request) Successful in 9m34s
Add .gitea/workflows/pr-checks.yml running on pull_request into main.
Three parallel jobs on the existing ubuntu-latest runner:

  • server-tests  — npm ci + node --test (164 tests, no DB needed:
    the suite stubs models and points the pool at a dead port)
  • client-build  — npm ci + vite build
  • bot-install   — npm ci only (catches a broken/stale lockfile)

No ESLint exists in the repo yet, so no lint step. Complements
build-images.yml, which publishes images post-merge.

Enable in Branch Protection with status check pattern: PR Checks / *

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0114TpmrNW4wNXsHq5CR72jQ
2026-07-12 10:07:16 -05:00
4f24959d49 ci: build & publish app + bot images to Gitea registry on merge
Add a Gitea Actions workflow (.gitea/workflows/build-images.yml) that fires on
push to main (and workflow_dispatch). On the always-on ubuntu-latest runner it:

  - verifies the host Docker daemon is reachable (socket must be mounted)
  - logs into gitea.whitlocktech.com with a PAT (REGISTRY_USER / REGISTRY_TOKEN)
  - builds & pushes both images from the existing Dockerfiles, each tagged
    :latest and :sha-<7>:
      gitea.whitlocktech.com/<owner>/website-app  (./Dockerfile — server+client)
      gitea.whitlocktech.com/<owner>/website-bot   (./bot/Dockerfile)

Raw docker CLI (no marketplace actions) for portability on self-hosted Gitea;
the shared host daemon gives free layer caching between runs. Registry owner is
lowercased for Docker refs. Deploy (compose image: + pull) is a follow-up.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0114TpmrNW4wNXsHq5CR72jQ
2026-07-11 17:59:55 -05:00