wrolpi/docker/web/Dockerfile

33 lines
1.5 KiB
Text
Raw Normal View History

fix: repair CI after the dependency bumps, and align it with the Trixie build (#651) * fix(app): depend on @testing-library/dom directly jest-dom 7 moved @testing-library/dom from a bundled dependency to a peer dependency. Nothing else pulls the top-level copy in — @testing-library/react 13 carries its own nested v8 — so it was present only as a peer, and CI installs with --legacy-peer-deps, which skips peers. Every suite then failed to load setupTests.js with "Cannot find module '@testing-library/dom'". Declare it as a devDependency so it installs under either resolution mode. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(app): import mount from cypress/react Cypress 14 removed the cypress/react18 subpath; cypress/react mounts React 18 itself. The e2e support file loads commands.js, so the stale import broke bundling for every spec, not just component tests: Module not found: Package path ./react18 is not exported from package cypress Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * ci: install and cache Cypress the way the bump requires The Cypress binary lives in ~/.cache/Cypress, outside node_modules, but only node_modules was cached. A restored cache satisfied npm, so npm skipped the postinstall download and the 15.x binary was never fetched: The cypress npm package is installed, but the Cypress binary is missing. Cache both paths and install the binary explicitly. Also align the JS toolchain with what actually ships. Debian 13 devices run nodejs 20.19.2 and install with a plain `npm install`; the Docker app image does the same. CI pinned older Node and passed --legacy-peer-deps, which skips peer dependencies -- that is why jest-dom 7's peer requirement passed review and broke CI. Match the devices instead. Pin caddy to 2.11.4, the version Debian 13 devices run, rather than latest. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * ci: test on Python 3.13, the version that ships Debian 13 devices run Python 3.13.5 and the api/controller/help images are python:3.13-trixie, but CI ran 3.11 (and one job on 3.12), so the runtime under test was two minors behind the runtime in production. Verified on 3.13 before switching: backend 1712 passed, 5 skipped; controller 883 passed. The only new warning is SQLAlchemy 1.3.22 reaching Python's deprecated datetime.utcfromtimestamp(), which is noise rather than a break. Drop api-tests-3-12: no workflow referenced it, it duplicated api-tests, and its "Sanic does not yet support 3.12" note is stale now that devices run 3.13. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-08 18:01:52 -06:00
# Pinned to the Caddy that Debian 13 devices run, so Docker matches hardware.
FROM caddy:2.11.4
Map previews that never drew, and a Docker map with no world under it (#658) * ui: a preview map that waited for a container it could never see Both map preview modals -- the per-region eye button and "View All Regions" -- opened to an empty box. Each renders a div into a Modal and hands it to MapLibre from an effect gated on `open`, reading the node out of a `useRef`: if (!open || !mapContainer.current) return; Mantine's Modal mounts its body one commit after `opened` flips true, so on the render that opens the modal the ref is still null. The effect returns, nothing it depends on changes again, and it never runs a second time. No console error, no rejected promise, no canvas -- just an empty div. Semantic UI's Portal mounted the body in the same commit that opened it, so the ref was attached by the time effects ran. The effect bodies are byte-identical across that migration; the modal library is the only variable, confirmed against a device still running the older build where both previews render. A callback ref instead, so the effect re-runs when the node arrives and this stops depending on any modal's mounting schedule. The async source lookup also gets a cancelled flag: it could resolve after the cleanup ran, building a map nothing would ever remove and leaking a WebGL context per open. The tests drive the real page and assert a map was built against a node that is in the document -- the outcome, rather than the mechanism that quietly changed underneath it. Seven of the eight fail on the code before this. * build: docker had no world underneath its map regions Caddy serves /blobs/map-overview.pmtiles out of /opt/wrolpi-blobs, and that blob is the world at zoom 0-6 -- what a regional extract sits on top of. Without it a user who subscribes to a few regions gets those regions floating on an empty background everywhere their data does not reach. Only a full planet file, at 134GB, makes it unnecessary. Raspberry Pi and Debian installs get the blob from pi-gen, the live-build config, and upgrade.sh. Docker got nothing: the compose file bind-mounted a git-ignored host directory over /opt/wrolpi-blobs, and a bind mount replaces the image's directory rather than merging with it, so the path existed and was empty on every Docker WROLPi. Verified against a running deployment, where that URL returned 404 while the same URL on hardware returned 206. So the web image fetches the blob at build time, as the other three builders do, and the mount that would hide it is gone. `curl -f` so an HTTP error fails the layer -- an image that builds without the blob is this same bug, except silent at build time too. The tests read the deployment files rather than a built container: building to check costs a CDN download and several minutes, and both things that broke -- nothing fetches it, a mount hides it -- are visible in the source. * ui: cancel the load handler too, and make the cancel test falsifiable Review follow-ups on the preview modals. The `cancelled` flag was checked before constructing the map but not inside the `load` handler it installs, so cleanup landing between the two left that body drawing into a map `remove()` had already torn down. Guarded, mirroring the `destroyed` pattern in MapViewer.js. The source promise also gets a `.catch`: the helper cannot reject today, but nothing says it never will, and an unhandled rejection here would be as quiet as the bug this all started as. Two test corrections, both cases of an assertion claiming more than it read: The region-drawing test spied on `addSource` AFTER construction and then re-fired `load` by hand, so its count came entirely from that manual call and said nothing about the production path. FakeMap now records the sources it is given, and the assertion reads what the component's own `load` drew -- each region once, in order, and none for the entry with no bbox. The new cancel test passed with the guard deleted, which is worse than not having it: Mantine had not mounted the modal body when it closed, so the effect had never run and there was nothing to cancel. It now waits for the effect to reach the source lookup before closing, and ships beside a control that releases the same held promise WITHOUT closing and requires a map. The control is what makes the zero meaningful; verified that removing the guard fails the cancel test while the control still passes.
2026-08-11 20:37:14 -06:00
RUN apk add --no-cache openssl bash curl
# The planet overview blob, which Caddy serves at /blobs/map-overview.pmtiles.
#
# It is the world at zoom 0-6, and it is what a regional map extract sits on top of: without
# it a user who subscribes to, say, three US regions gets those regions floating on an empty
# background at every zoom level that does not have their data. Only a full planet file (134
# GB) makes it unnecessary.
#
# Raspberry Pi and Debian installs get this from pi-gen, the live-build config, and
# upgrade.sh. Docker had no equivalent and shipped without it -- see
# modules/map/test/test_map_overview_blob.py. 42 MB.
#
# `curl -f` so an HTTP error fails this layer rather than writing the error body to the file
# and exiting 0; an image that builds without the blob is the bug all over again, except now
# it is silent at build time too.
RUN mkdir -p /opt/wrolpi-blobs && \
curl -fsSL https://wrolpi.nyc3.cdn.digitaloceanspaces.com/maps/map-overview.pmtiles \
-o /opt/wrolpi-blobs/map-overview.pmtiles && \
[ -s /opt/wrolpi-blobs/map-overview.pmtiles ]
# Copy scripts and static files.
COPY docker/web/Caddyfile /etc/caddy/Caddyfile
COPY docker/web/entrypoint.sh /entrypoint.sh
COPY scripts/generate_certificates.sh /opt/wrolpi/scripts/generate_certificates.sh
RUN chmod +x /entrypoint.sh /opt/wrolpi/scripts/generate_certificates.sh
ENTRYPOINT ["/entrypoint.sh"]