Commit Graph

30 Commits

Author SHA1 Message Date
alexei.dolgolyov bc42604045 ci(release): publish release only after every build job uploads assets
create-release now creates the release as a draft so users never see
a release page that's missing artifacts (or, worse, missing the
sha256 sidecars that the in-app updater requires). A new
publish-release job runs after create-release, build-windows,
build-linux, and build-docker all succeed, and PATCHes the release
to draft=false in one step. If any build fails, the draft stays
hidden and can be deleted manually.
2026-05-28 17:26:28 +03:00
alexei.dolgolyov a026f0b349 ci(android): fail-fast on missing release keystore before SDK setup
Move the keystore guard from after the Decode step (step 9) to right
after Resolve build label (step 3). A release tag pushed without
ANDROID_KEYSTORE_BASE64 configured now fails in seconds instead of
after JDK + Python + Android SDK + NDK install (~3-5 min of wasted
runner time). Switched the condition from steps.keystore.outputs.present
to env.ANDROID_KEYSTORE_BASE64 since the env var is set at job level
and the keystore decode step has not yet run at the new position.
2026-05-01 19:18:46 +03:00
alexei.dolgolyov 033c1f6a92 ci: add workflow_dispatch and skip lint/test on release commits
Release-bump commits don't change code that affects lint/tests, and
release.yml already runs in parallel. Manual dispatch lets us re-run
on demand if needed.
2026-04-25 15:36:51 +03:00
alexei.dolgolyov 03d2e6b1f2 ci(release): publish .sha256 sidecars alongside release assets
Lint & Test / test (push) Successful in 2m4s
The in-app update service (`ledgrab.core.update.update_service`) refuses
to install any downloaded artifact that has no published sha256 — either
as a sibling `<asset>.sha256` asset on the Gitea release, or embedded in
the release body. The release workflow uploaded the ZIP, setup.exe, and
Linux tarball but never published checksums, so every auto-update 500'd
with "Update checksum unavailable; install aborted".

Generate sha256sum sidecars for the Windows ZIP, Windows setup.exe, and
Linux tar.gz and upload them next to the primary asset on each tagged
release. Existing v0.4.x releases stay broken — ship v0.4.2 (or manually
upload sidecars to v0.4.1) to unblock in-app updates.
2026-04-22 19:40:46 +03:00
alexei.dolgolyov 35b75a2ed8 ci(android): fix keystore env scoping, fail loudly on release without key
Lint & Test / test (push) Successful in 3m17s
Primary bug — step-level env is not visible in that same step's `if:`
expression. `Decode signing keystore` had
  if: env.ANDROID_KEYSTORE_BASE64 != ''
  env:
    ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
so the env context seen by the `if:` evaluator was empty regardless of
whether the secret was configured. The step was skipped, keystore.present
never became 'true', and every release tag silently fell back to
assembleDebug. Result: APKs named `LedGrab-0.4.0-android-debug.apk` that
can't upgrade a previously-release-signed install (signature mismatch).

Fix — move ANDROID_KEYSTORE_BASE64 to the job-level env block. It's now
resolvable in the if-expression of any step in the job, and the shell
inherits it exactly the same way as before.

Secondary — add a "Guard release tag against missing keystore" step that
fires between the decode attempt and the gradle build. If is_release=true
but keystore.present!='true', the job fails with a clear error directing
the operator to configure the four signing secrets. Previously a
misconfigured Gitea silently shipped debug APKs labeled as releases.
2026-04-21 19:55:55 +03:00
alexei.dolgolyov 4ed099d564 docs(release): drop WLED-specific language from auto-generated release notes
The "discover your WLED devices" line predates BLE / USB-serial / ESP-NOW /
MQTT / OpenRGB support and misrepresents what the app does. Replaced with
a generic "add your LED devices" — the device-add UI lists what's actually
supported, and INSTALLATION.md carries the long-form detail.
2026-04-21 19:55:55 +03:00
alexei.dolgolyov 524e422517 ci: decouple android release attach, add workflow_dispatch to release.yml
Lint & Test / test (push) Successful in 2m16s
build-android.yml
- Attach step upserts the Gitea release: GET /releases/tags/<TAG>, and
  POST to create it on 404 instead of warning-and-skipping. Removes the
  ordering dependency on release.yml's create-release job — the Android
  workflow can now own its own release attachment end-to-end.
- Fail loudly on broken DEPLOY_TOKEN: curl -f on every asset call so
  403/422 surface as job failures instead of "Uploaded" lies, and an
  explicit check that the token is non-empty before starting.
- Preserve the pre-existing replace-on-re-run behavior for idempotent
  asset uploads.

release.yml
- Add workflow_dispatch trigger with optional `version` input so the
  Windows/Linux/Docker builds can be exercised on demand between real
  releases (was tag-push only).
- Gate create-release on github.event_name == 'push' so a manual
  dispatch doesn't create a stray Gitea release.
- Each build job gets `if: !cancelled() && (needs.create-release.result
  in (success, skipped))` so dispatch runs still produce artifacts even
  though create-release was skipped.
- Gate each "Attach * to release" step on github.event_name == 'push'.
- Docker: login + push are push-only; build runs on both triggers so
  dispatch validates the Dockerfile without needing registry creds.
2026-04-21 19:10:14 +03:00
alexei.dolgolyov 7ef17c1595 ci(android): fix missing python symlink parent, restrict to release tags
Lint & Test / test (push) Successful in 3m53s
- Create android/app/src/main/python before `ln -sfn` — the parent dir
  isn't committed (android/.gitignore:17 ignores /ledgrab inside it) so
  fresh CI checkouts had nothing to link into, failing with
  "No such file or directory".
- Also wrap the step with `set -euo pipefail` and a `test -d` check so a
  broken link aborts the job instead of producing a silently-empty APK.
- Drop the `branches: [master]` push trigger and the `paths:` filter —
  every master commit touching android/** or server/src/ledgrab/** was
  queueing a ~100 MB APK build that nobody used. Only tag pushes (v*)
  and workflow_dispatch remain.
2026-04-21 18:53:43 +03:00
alexei.dolgolyov 2477e00fae ci: add Android APK row to release downloads table
Lint & Test / test (push) Successful in 1m37s
2026-04-14 12:47:27 +03:00
alexei.dolgolyov 151cea3ecb ci: Android multi-ABI APK pipeline + pydantic-core wheel rebuild
Build Android APK / build-android (push) Failing after 2m31s
Lint & Test / test (push) Successful in 6m15s
Adds .gitea/workflows/build-android.yml — Linux runner installs JDK 17,
Python 3.11, Android SDK/NDK, symlinks server/src/ledgrab into the
Chaquopy python source dir, and runs assembleDebug on master pushes /
assembleRelease on v* tags. APK is uploaded as an artifact and attached
to the Gitea release on tag push. Conditional signing config in
build.gradle.kts reads keystore from env vars (CI secrets) and falls
back to debug signing locally. Gradle wrapper (gradlew/gradlew.bat/
gradle-wrapper.jar) committed so CI can drive the build.

Rebuilds pydantic-core wheels for arm64-v8a and x86_64 — both were
missing libpython3.11.so in NEEDED, which would have crashed at import
on real devices. build-pydantic-core.sh rewritten as a multi-ABI builder:
selects targets via args, sets RUSTFLAGS=-C link-arg=-Wl,--no-as-needed
-C link-arg=-lpython3.11 to force the symbol-resolution dependency,
uses the per-ABI sysconfigdata + libpython staged in
android/.build-cache/, prefers `py -3.11` on Windows (Git Bash's
python3.11 is an MSStore stub), uses the .cmd clang wrapper on Windows
(fixes os error 193), and verifies NEEDED via llvm-readelf after each
build. abiFilters restored to the full triple in build.gradle.kts;
multi-ABI debug APK builds cleanly (~99 MB).
2026-04-14 12:36:13 +03:00
alexei.dolgolyov a0b65e3fcb refactor: move build scripts to build/ directory
Lint & Test / test (push) Successful in 2m21s
Declutters the repo root by consolidating build-common.sh,
build-dist.sh, build-dist-windows.sh, build-dist.ps1, and installer.nsi
into build/. Updates all path references in CI workflows, NSIS installer,
and documentation.
2026-04-12 23:16:40 +03:00
alexei.dolgolyov fb98e6e2b8 ci: add manual build workflow for testing artifacts
Lint & Test / test (push) Has been cancelled
workflow_dispatch-triggered build.yml that produces Windows
installer/portable and Linux tarball as CI artifacts without
creating a release. Trigger from Gitea UI → Actions → Run.
2026-03-27 23:41:22 +03:00
alexei.dolgolyov 9fcfdb8570 ci: use sparse checkout for release notes in release workflow
Only fetch RELEASE_NOTES.md instead of full repo checkout, and
simplify the file detection to a direct path check.
2026-03-25 23:43:31 +03:00
alexei.dolgolyov 2eeae4a7c1 feat: add release notes overlay with Markdown rendering
- Replace truncated plaintext release notes with full-screen overlay
  rendered via `marked` library
- Server reconnection does a hard page reload instead of custom event
2026-03-25 21:34:59 +03:00
alexei.dolgolyov f4da47ca2b fix: rename GITEA_TOKEN to DEPLOY_TOKEN in CI workflow
Lint & Test / test (push) Successful in 2m39s
Build Release / create-release (push) Successful in 2s
Build Release / build-linux (push) Successful in 2m11s
Build Release / build-docker (push) Successful in 2m52s
Build Release / build-windows (push) Successful in 3m30s
GITEA_TOKEN is a reserved name in Gitea — the UI and API reject it
when creating action secrets.
2026-03-25 14:41:02 +03:00
alexei.dolgolyov 7da5084337 fix: prevent duplicate release assets on re-triggered CI workflows
Build Release / create-release (push) Successful in 1s
Build Release / build-docker (push) Successful in 37s
Lint & Test / test (push) Successful in 2m15s
Build Release / build-linux (push) Successful in 1m50s
Build Release / build-windows (push) Successful in 3m24s
Gitea silently appends duplicate asset names. Added delete-before-upload
logic to both Windows and Linux asset upload steps.
2026-03-25 13:20:05 +03:00
alexei.dolgolyov 382a42755d feat: add auto-update system with release checking, notification UI, and install-type-aware apply
- Abstract ReleaseProvider interface (Gitea impl, swappable for GitHub/GitLab)
- Background UpdateService with periodic checks, debounce, dismissed version persistence
- Install type detection (installer/portable/docker/dev) with platform-aware asset matching
- Download with progress events, silent NSIS reinstall, portable ZIP/tarball swap scripts
- Version badge pulse animation, dismissible banner with icon buttons, Settings > Updates tab
- Single source of truth: pyproject.toml version via importlib.metadata, CI stamps tag with sed
- API: GET/POST status, check, dismiss, apply, GET/PUT settings
- i18n: en, ru, zh (27+ keys each)
2026-03-25 13:16:18 +03:00
alexei.dolgolyov fc62d5d3b1 chore: sync CI/CD with upstream guide and update context docs
Lint & Test / test (push) Failing after 30s
release.yml: add fallback for existing releases on tag re-push.
installer.nsi: add .onInit file lock check, use LaunchApp function
instead of RUN_PARAMETERS to fix NSIS quoting bug.
build-dist.ps1: copy start-hidden.vbs to dist scripts/.
start-hidden.vbs: embedded Python fallback for installed/dev envs.

Update ci-cd.md with version detection, NSIS best practices, local
build testing, Gitea vs GitHub differences, troubleshooting.
Update frontend.md with full entity type checklist and common pitfalls.
2026-03-24 13:59:27 +03:00
alexei.dolgolyov 52c8614a3c fix: escape release body via Python to avoid YAML parsing errors
Lint & Test / test (push) Successful in 31s
Build Release / create-release (push) Successful in 1s
Build Release / build-linux (push) Successful in 1m14s
Build Release / build-docker (push) Successful in 7s
Build Release / build-windows (push) Successful in 2m41s
2026-03-22 13:59:14 +03:00
alexei.dolgolyov 42bc05c968 fix: update release description to match current build artifacts
Lint & Test / test (push) Failing after 14s
Add Windows installer, Docker volume mount, and first-time setup
instructions to the Gitea release body. Fix Docker registry URL.
Add CI/Release sync rule to CLAUDE.md.
2026-03-22 13:50:46 +03:00
alexei.dolgolyov 0e54616000 fix: use msiextract for tkinter, fix step numbering, graceful Docker fallback
Build Release / create-release (push) Successful in 0s
Lint & Test / test (push) Failing after 14s
Build Release / build-linux (push) Successful in 1m27s
Build Release / build-docker (push) Successful in 6s
Build Release / build-windows (push) Successful in 3m26s
- Replace 7z with msiextract (msitools) to extract tkinter from
  python.org's individual MSI packages (tcltk.msi + lib.msi)
- Fix build step numbering to /9
- Docker job continues on login failure (registry may not be enabled)
- Show makensis output for debugging
2026-03-22 03:44:37 +03:00
alexei.dolgolyov 3633793972 fix: extract tkinter from Python installer via 7z, fix NSIS icon path
Build Release / create-release (push) Successful in 1s
Lint & Test / test (push) Failing after 15s
Build Release / build-linux (push) Successful in 1m20s
Build Release / build-docker (push) Failing after 9s
Build Release / build-windows (push) Successful in 3m19s
- Replace nuget approach (doesn't contain tkinter) with extracting
  from the official Python amd64.exe installer using 7z
- Remove MUI_ICON/MUI_UNICON (no .ico file available, use NSIS default)
- Add p7zip-full to CI dependencies
2026-03-22 03:40:06 +03:00
alexei.dolgolyov 7f799a914d feat: add NSIS Windows installer to release workflow
Build Release / create-release (push) Successful in 1s
Lint & Test / test (push) Failing after 15s
Build Release / build-linux (push) Successful in 1m21s
Build Release / build-docker (push) Failing after 9s
Build Release / build-windows (push) Failing after 1m37s
- installer.nsi: per-user install to AppData, Start Menu shortcuts,
  optional desktop shortcut and autostart, clean uninstall (preserves
  data/), Add/Remove Programs registration
- build-dist-windows.sh: runs makensis after ZIP if available
- release.yml: install nsis in CI, upload both ZIP and setup.exe
- Fix Docker registry login (sed -E for https:// stripping)
2026-03-22 03:35:34 +03:00
alexei.dolgolyov 39e3d64654 fix: replace Docker Buildx with plain docker build/push
Lint & Test / test (push) Successful in 1m51s
Buildx requires container networking that fails on TrueNAS runners.
Plain docker build + docker push works without Buildx setup.
2026-03-22 03:20:37 +03:00
alexei.dolgolyov 62fdb093d6 feat: cross-build Windows ZIP from Linux CI runner
Lint & Test / test (push) Successful in 1m50s
Build Release / create-release (push) Successful in 1s
Build Release / build-linux (push) Successful in 1m54s
Build Release / build-windows (push) Successful in 2m0s
Build Release / build-docker (push) Failing after 1m48s
Replace Windows runner requirement with cross-compilation:
download Windows embedded Python + win_amd64 wheels from PyPI,
package into the same ZIP structure as build-dist.ps1.

All 4 release jobs now run on ubuntu-latest.
2026-03-22 03:05:40 +03:00
alexei.dolgolyov 67860b02ac feat: add Linux tarball and Docker image to release workflow
Lint & Test / test (push) Successful in 1m53s
Restructure release.yml into 4 jobs:
- create-release: shared Gitea release with download table
- build-windows: existing portable ZIP (unchanged)
- build-linux: new tarball with venv + run.sh launcher
- build-docker: push image to Gitea Container Registry

Add build-dist.sh as Linux equivalent of build-dist.ps1.
Docker tags: version + latest (stable only, no latest for alpha/beta/rc).
2026-03-22 03:00:20 +03:00
alexei.dolgolyov 34f142ee61 fix: add opencv-python-headless to dev deps and libportaudio2 to CI
Lint & Test / test (push) Failing after 21s
The test import chain (conftest → storage → filters → cv2) requires
opencv-python-headless. Also install libportaudio2 for sounddevice.
2026-03-22 01:32:52 +03:00
alexei.dolgolyov f2871319cb refactor: comprehensive code quality, security, and release readiness improvements
Lint & Test / test (push) Failing after 48s
Security: tighten CORS defaults, add webhook rate limiting, fix XSS in
automations, guard WebSocket JSON.parse, validate ADB address input,
seal debug exception leak, URL-encode WS tokens, CSS.escape in selectors.

Code quality: add Pydantic models for brightness/power endpoints, fix
thread safety and name uniqueness in DeviceStore, immutable update
pattern, split 6 oversized files into 16 focused modules, enable
TypeScript strictNullChecks (741→102 errors), type state variables,
add dom-utils helper, migrate 3 modules from inline onclick to event
delegation, ProcessorDependencies dataclass.

Performance: async store saves, health endpoint log level, command
palette debounce, optimized entity-events comparison, fix service
worker precache list.

Testing: expand from 45 to 293 passing tests — add store tests (141),
route tests (25), core logic tests (42), E2E flow tests (33), organize
into tests/api/, tests/storage/, tests/core/, tests/e2e/.

DevOps: CI test pipeline, pre-commit config, Dockerfile multi-stage
build with non-root user and health check, docker-compose improvements,
version bump to 0.2.0.

Docs: rewrite CLAUDE.md (202→56 lines), server/CLAUDE.md (212→76),
create contexts/server-operations.md, fix .js→.ts references, fix env
var prefix in README, rewrite INSTALLATION.md, add CONTRIBUTING.md and
.env.example.
2026-03-22 00:38:28 +03:00
alexei.dolgolyov 55772b58dd Replace deploy workflow with portable Windows release build
- Remove old Docker-based deploy.yml
- Add release.yml: builds portable ZIP on tag push, uploads to Gitea
- Add build-dist.ps1: downloads embedded Python, installs deps, bundles app
- Add scrollbar-gutter: stable to prevent layout shift

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 11:21:55 +03:00
alexei.dolgolyov 99d8c4b8fb Add connection overlay and Gitea CI/CD workflow
Show full-screen overlay with spinner when server is unreachable,
with periodic health checks that auto-hide on reconnect.
Add Gitea Actions workflow for auto-deploy on release tags.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 11:07:13 +03:00