Skip to content

feat(history, stats): surface wind aggregates from history backend #936

feat(history, stats): surface wind aggregates from history backend

feat(history, stats): surface wind aggregates from history backend #936

Workflow file for this run

name: CI
on:
push:
branches: [master]
pull_request:
branches: [master]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Setup .NET
uses: actions/setup-dotnet@v5
with:
global-json-file: global.json
- name: Install workloads
run: dotnet workload install wasm-tools
- name: Restore
run: dotnet restore OnaPlotter.slnx
- name: Build
run: dotnet build OnaPlotter.slnx --no-restore --configuration Release
# JS lint runs on the build job (not e2e) so a TDZ-class bug
# like the editModeDeps ReferenceError fails CI as soon as the
# PR opens, not 10+ minutes later when Playwright trips over a
# broken /map page. Setup-node happens here too because the
# build job didn't previously need Node; the e2e job sets up
# its own Node further down.
- name: Setup Node (for JS lint)
uses: actions/setup-node@v4
with:
node-version: '22'
- name: Install JS lint deps
run: npm ci
- name: Lint (JS)
run: npm run lint
# `dotnet test` on .NET 10 SDK dispatches through VSTest by default,
# which Microsoft.Testing.Platform refuses. TUnit is MTP-native and
# runs as an executable, so invoking the test project directly is
# the cleanest route. `--no-build` reuses the Release artefacts from
# the step above. A non-zero exit propagates a red CI.
- name: Test (C# unit + bUnit component)
run: dotnet run --project OnaPlotter.Tests --configuration Release --no-build
# All JS unit tests: geoMath, chartOverzoom, markerLayer. Pure Node,
# no server dependency. Drops the single-quoted glob that bash
# couldn't expand (previous CI was red with "Could not find
# '.../OnaPlotter/wwwroot/js/*.test.js'"); bash's default globbing
# hands Node a concrete file list so new *.test.js files still
# pick up automatically.
- name: Test (JS unit)
shell: bash
run: node --test OnaPlotter/wwwroot/js/*.test.js
# End-to-end job: runs OnaPlotter + the dev SignalK stack from
# docker/docker-compose.dev.yml and drives the Map page via Playwright.
# Separate job so a pure-unit failure still reports quickly, and so
# docker setup doesn't slow down the C# build's feedback loop.
e2e:
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v6
- name: Setup .NET
uses: actions/setup-dotnet@v5
with:
global-json-file: global.json
- name: Install workloads
run: dotnet workload install wasm-tools
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '22'
# Start the dev SignalK server + fake-data pump. --wait makes
# compose block until the sk healthcheck passes (curl /signalk).
# fake-data is a TCP server; signalk-server connects to it via
# a pipedProvider configured in docker/signalk-config/settings.json.
- name: Start dev SignalK stack
run: docker compose -f docker/docker-compose.dev.yml up -d --build --wait
# Give the pipedProvider a few ticks to fan deltas onto the bus
# before Playwright starts querying for vessels. 6 = own + 5 AIS.
- name: Wait for SignalK deltas
run: |
for i in $(seq 1 30); do
COUNT=$(curl -sS http://localhost:3000/signalk/v1/api/vessels 2>/dev/null \
| python3 -c 'import json,sys; d=json.loads(sys.stdin.read()); print(len(d))' 2>/dev/null || echo 0)
if [ "$COUNT" -ge "6" ]; then
echo "SignalK has $COUNT vessels; ready."
exit 0
fi
sleep 2
done
echo "Timeout waiting for SignalK vessels"
docker compose -f docker/docker-compose.dev.yml logs
exit 1
- name: Build OnaPlotter (Release)
run: dotnet build OnaPlotter/OnaPlotter.csproj --configuration Release
# Override the SignalK target to the compose'd server on localhost.
- name: Point OnaPlotter at dev SK
run: |
cat > OnaPlotter/bin/Release/net10.0/wwwroot/appsettings.json <<EOF
{ "SignalK": { "ServerUrl": "http://localhost:3000" } }
EOF
- name: Start OnaPlotter
run: |
nohup dotnet run --project OnaPlotter --configuration Release --no-build \
> onaplotter.log 2>&1 &
echo $! > onaplotter.pid
for i in $(seq 1 30); do
if curl -sf http://localhost:5282/ > /dev/null 2>&1; then
echo "OnaPlotter ready."
exit 0
fi
sleep 2
done
echo "Timeout waiting for OnaPlotter"
cat onaplotter.log
exit 1
- name: Install Playwright deps
working-directory: OnaPlotter.UiTests
run: |
npm ci
npx playwright install --with-deps chromium
# Smoke is required. Fuzz uses a 200-click budget which fills
# the test's 3-min cap (avg ~0.4 s per click on a healthy CI
# runner - ~80 s real-time, plenty of headroom). Higher click
# counts catch "banner path crashes after N random clicks"
# regressions the local 10-min fuzz exercises. Seed is fixed
# so a failure reproduces on a dev machine with the same input.
- name: Playwright smoke + actions + short fuzz
working-directory: OnaPlotter.UiTests
env:
BASE_URL: http://localhost:5282/
FUZZ_CLICKS: "200"
FUZZ_SEED: "20260419"
# Explicit spec list keeps the diagnose-*.spec.js files (manual
# debug helpers that only log) out of the CI run. Ordering:
# smoke first for the quickest failure signal, fuzz last since
# it's the slowest of the three.
run: npx playwright test smoke.spec.js actions.spec.js fuzz.spec.js --reporter=list
- name: Upload Playwright report on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: playwright-report
path: OnaPlotter.UiTests/playwright-report/
retention-days: 7
- name: Dump logs on failure
if: failure()
run: |
echo "=== OnaPlotter log ==="
tail -200 onaplotter.log || true
echo "=== docker compose logs ==="
docker compose -f docker/docker-compose.dev.yml logs --tail=200 || true
- name: Stop OnaPlotter
if: always()
run: |
if [ -f onaplotter.pid ]; then
kill $(cat onaplotter.pid) 2>/dev/null || true
fi
- name: Stop dev SignalK stack
if: always()
run: docker compose -f docker/docker-compose.dev.yml down
# Packages the Release build as the SignalK-webapp NPM shape and
# uploads it as an artifact so a maintainer can download, sanity-
# check, and then publish manually. Mirrors deploy/deploy.ps1's
# staging so the shape the kiosk gets is the shape CI builds.
# Actual publish lives in publish.yml and is only wired on a tag.
package:
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v6
- name: Setup .NET
uses: actions/setup-dotnet@v5
with:
global-json-file: global.json
- name: Install workloads
run: dotnet workload install wasm-tools
- name: Publish OnaPlotter (Release + AOT)
run: dotnet publish OnaPlotter/OnaPlotter.csproj -c Release -o publish
# SignalK webapps expect <base href="/{webapp-name}/"> so the
# Blazor router resolves correctly when the app is served from
# /signalk/apps/<webapp-name>/ on the SK server. See deploy.ps1
# for the matching local patch.
- name: Patch index.html base href
run: |
sed -i 's|<base href="/" />|<base href="/signalk-onaplotter/" />|' publish/wwwroot/index.html
grep '<base href' publish/wwwroot/index.html
# Runtime ServerUrl = "auto" tells SignalkClient to use the page
# origin, which IS the SignalK host when the app is served as a
# webapp. Dev / local builds override this locally.
- name: Set appsettings ServerUrl to auto
run: |
cat > publish/wwwroot/appsettings.json <<'EOF'
{ "SignalK": { "ServerUrl": "auto" } }
EOF
# Stage the SignalK-webapp layout:
# signalk-onaplotter/
# package.json (from deploy/package.json.template)
# public/ (Blazor wwwroot)
# Version = 0.0.0-ci.<run> so artifacts from different CI runs
# don't collide. Real publish rewrites with the tag version.
- name: Stage SignalK webapp bundle
run: |
set -euo pipefail
stage=staging/signalk-onaplotter
mkdir -p "$stage"
version="0.0.0-ci.${{ github.run_number }}"
sed "s|__VERSION__|$version|" deploy/package.json.template > "$stage/package.json"
cp -r publish/wwwroot "$stage/public"
echo "--- package.json ---"
cat "$stage/package.json"
echo "--- staging tree ---"
find "$stage" -maxdepth 2 -type d | sort
# Pre-flight: make sure the staged folder would actually pack
# cleanly. --dry-run doesn't touch the registry but surfaces
# any files npm would refuse (tarball-too-big, missing license,
# manifest typos, etc).
- name: npm pack dry-run
working-directory: staging/signalk-onaplotter
run: npm pack --dry-run
# Real tarball for the artifact. Named signalk-onaplotter-*.tgz
# so a maintainer can `npm publish <tarball>` if they want.
- name: npm pack
working-directory: staging/signalk-onaplotter
run: npm pack
- name: Upload webapp bundle
uses: actions/upload-artifact@v4
with:
name: signalk-onaplotter-${{ github.run_number }}
path: staging/signalk-onaplotter/signalk-onaplotter-*.tgz
if-no-files-found: error
retention-days: 30