feat: roadmap batch (2026-06-19) — solar/linear-light/dither/nanoleaf + integrations
Eight roadmap features from the 2026-06-19 review, each a full vertical (backend + tests + frontend + i18n en/ru/zh); ~67 new unit tests: - automations: SolarRule sunrise/sunset trigger (new utils/solar.py, shared with the daylight cycle; window logic mirrors TimeOfDayRule) - ci: best-effort arm64 multi-arch Docker manifest via QEMU + docker manifest (release.yml; amd64 path untouched, continue-on-error) - game-integration: wire the orphaned LoLPoller via a LoLPollManager + a shared runtime_state module (poll lifecycle on enable/CRUD/startup/shutdown) - ui: color-harmony gradient generator (complementary/analogous/triadic/...) - effects: audio-reactive palette modulation (new audio_energy_tap; brightness/ saturation modulation across all 12 procedural effects) - capture: linear-light blending + spatio-temporal dithering, opt-in per calibration (new utils/linear_light.py, utils/dither.py) - devices: Nanoleaf extControl v2 per-panel UDP streaming (per_panel mode) Also bundles the pending 2026-06-18 production-review fixes and other in-progress work already in the working tree (manual-trigger rule, etc.), since they share files and could not be cleanly separated. Gate: ruff + tsc clean; pytest 2654 passed / 2 skipped. The single failing test (automation manual_trigger handler coverage) is a separate in-progress item owned elsewhere, intentionally left as-is.
This commit is contained in:
@@ -354,6 +354,58 @@ jobs:
|
||||
docker push "$REGISTRY:latest"
|
||||
fi
|
||||
|
||||
# Best-effort arm64 (Raspberry Pi / arm64 HAOS hosts). Runs AFTER the
|
||||
# amd64 push so the amd64 image always ships even if this fails.
|
||||
# Deliberately avoids `docker buildx` (its docker-container driver needs
|
||||
# nested networking the TrueNAS runners lack — see contexts/ci-cd.md):
|
||||
# instead it cross-builds a single arm64 image via QEMU binfmt and folds
|
||||
# amd64 + arm64 into multi-arch manifest lists under the existing tags.
|
||||
# `continue-on-error` keeps a runner that can't emulate arm64 from
|
||||
# failing the release; the plain amd64 tags pushed above remain valid.
|
||||
- name: Build + publish arm64 (multi-arch manifest, best-effort)
|
||||
if: github.event_name == 'push' && steps.docker-login.outcome == 'success'
|
||||
continue-on-error: true
|
||||
run: |
|
||||
set -e
|
||||
export DOCKER_CLI_EXPERIMENTAL=enabled
|
||||
TAG="${{ gitea.ref_name }}"
|
||||
REGISTRY="${{ steps.meta.outputs.registry }}"
|
||||
VERSION="${{ steps.meta.outputs.version }}"
|
||||
|
||||
# Register arm64 emulation. If the runner forbids privileged
|
||||
# containers this fails and the whole step is skipped.
|
||||
docker run --privileged --rm tonistiigi/binfmt --install arm64
|
||||
|
||||
# Cross-build the arm64 image (QEMU-emulated — slow but uses arm64
|
||||
# manylinux wheels, so no source compilation). Stays in the local
|
||||
# daemon alongside the amd64 image from the previous build step.
|
||||
DOCKER_BUILDKIT=1 docker build \
|
||||
--platform linux/arm64 \
|
||||
--build-arg APP_VERSION="$VERSION" \
|
||||
--label "org.opencontainers.image.version=$VERSION" \
|
||||
--label "org.opencontainers.image.revision=${{ gitea.sha }}" \
|
||||
-t "$REGISTRY:$VERSION-arm64" \
|
||||
./server
|
||||
|
||||
# Fold amd64 + arm64 into a multi-arch manifest list under each
|
||||
# user-facing tag. The arch-suffixed tags remain pullable directly.
|
||||
publish_manifest() {
|
||||
local t="$1"
|
||||
docker tag "$REGISTRY:$t" "$REGISTRY:$t-amd64"
|
||||
docker push "$REGISTRY:$t-amd64"
|
||||
docker tag "$REGISTRY:$VERSION-arm64" "$REGISTRY:$t-arm64"
|
||||
docker push "$REGISTRY:$t-arm64"
|
||||
docker manifest create --amend "$REGISTRY:$t" \
|
||||
"$REGISTRY:$t-amd64" "$REGISTRY:$t-arm64"
|
||||
docker manifest push "$REGISTRY:$t"
|
||||
}
|
||||
|
||||
publish_manifest "$TAG"
|
||||
publish_manifest "$VERSION"
|
||||
if ! echo "$TAG" | grep -qE '(alpha|beta|rc)'; then
|
||||
publish_manifest "latest"
|
||||
fi
|
||||
|
||||
# ── Publish the release (flip draft=false) ─────────────────
|
||||
# Runs only after every build job succeeded so users never see a
|
||||
# release that's missing artifacts or sha256 sidecars (the in-app
|
||||
|
||||
Reference in New Issue
Block a user