Skip to content

feat(updater): auto-update for non-Docker standalone installs#526

Merged
javi11 merged 7 commits intomainfrom
claude/inspiring-jackson-638589
Apr 22, 2026
Merged

feat(updater): auto-update for non-Docker standalone installs#526
javi11 merged 7 commits intomainfrom
claude/inspiring-jackson-638589

Conversation

@javi11
Copy link
Copy Markdown
Owner

@javi11 javi11 commented Apr 22, 2026

Summary

Adds a binary self-update path for standalone (non-Docker) altmount installs and publishes a rolling dev prerelease with CLI binaries so the dev channel works outside Docker too.

Closes #497.

What changed

Backend (internal/updater, internal/api)

  • New internal/updater package: fetches GitHub release metadata, picks the asset matching runtime.GOOS/GOARCH (darwin uses the universal build), verifies SHA-512 against checksums-cli.txt, extracts the binary in-memory from tar.gz/zip, and applies it via minio/selfupdate.
  • Container detection via /.dockerenv and KUBERNETES_SERVICE_HOST — self-update is skipped inside containers so Docker users still get the docker pull path.
  • handleApplyUpdate now routes:
    • inside-container + docker available → existing docker pull + restart
    • else self-update eligible → download + verify + swap + restart
    • else → 400 with guidance
  • UpdateStatusResponse gains binary_update_available so the frontend can reflect the real state.

Frontend (UpdateSection.tsx)

  • Apply button is enabled when either docker_available or binary_update_available is true.
  • Copy adapts per mode ("pull image / restart container" vs. "download binary / restart process").

CI workflows

  • New reusable .github/workflows/build-cli.yml (workflow_call) with the full OS/arch matrix, zig cross-compilation, universal darwin, and checksums. Optionally attaches assets to a GitHub release.
  • release.yml consumes the reusable workflow for stable tag releases.
  • dev-image.yml gets prepare-dev-release + publish-dev-binaries jobs that maintain a rolling dev prerelease with fresh binaries on every push to main.

Why

Before this PR, /api/system/update/apply short-circuited to 400 "Auto-update is not available" whenever /var/run/docker.sock wasn't mounted, and the dev channel shipped only a Docker image — users running the standalone Linux/macOS/Windows binary had no auto-update path at all.

Test plan

  • go build ./...
  • go test -race ./internal/updater/... ./internal/api/... — new tests cover asset selection, checksum verify (happy + mismatch), tar.gz/zip extraction, handler routing for all three branches.
  • bun run check in frontend/ — TS + lint + format clean.
  • Reviewer: smoke-test the dev-image.yml run on merge to confirm the dev prerelease is updated with fresh altmount-cli_* archives + checksums-cli.txt.
  • Reviewer: verify existing Docker path still works (regression check) by triggering an update from a container with docker.sock mounted.

javi11 added 7 commits April 20, 2026 10:25
Adds a generic import_migrations table to track two-phase migration
state (Phase 1 = import NZBs into AltMount; Phase 2 = rewrite arr
library symlinks). Includes goose migrations for SQLite and PostgreSQL,
ImportMigration model + status consts, a full ImportMigrationRepository
with Upsert/MarkImported/MarkFailed/MarkSymlinksMigrated/LookupByExternalID/
ListByStatus/Stats/ExistsForSource/BackfillFromImportQueue, and wires
MigrationRepo into the DB struct.
…avIds

Delete HandleIDMetadataLinks and id_linker.go; remove UpdateIDSymlink and
RemoveIDSymlink methods from MetadataService; remove the .id sidecar write
block from WriteFileMetadata (read path preserved for Phase 2 compatibility);
remove FilterExistingNzbdavIds from QueueRepository, Repository, and the
BatchQueueAdder interface; remove related call sites in nzbfilesystem MOVE
handler and nzbdav scanner processBatch.
- Add MigrationRecorder interface to scanner package with UpsertMigration
  and IsMigrationCompleted methods
- Update NzbDavImporter to accept MigrationRecorder as second constructor
  parameter alongside BatchQueueAdder
- processBatch now checks IsMigrationCompleted before enqueueing (skip
  already-imported/symlinks_migrated items) and calls UpsertMigration for
  new items, then strips nzbdav_id from the queue item metadata leaving
  only extracted_files if present
- createNzbFileAndPrepareItem sets SkipArrNotification=true on all items
- batchQueueAdapterForImporter gains migrationRepo field and implements
  MigrationRecorder via ImportMigrationRepository.Upsert/LookupByExternalID
…lure

Wire s.database.MigrationRepo into handleProcessingSuccess and
handleProcessingFailure so that import_migrations rows are marked
imported/failed when the corresponding queue item finishes. Both
calls are non-fatal: failures are logged as warnings and do not
affect the main processing outcome. If no matching migration row
exists (non-nzbdav import), the UPDATE simply affects 0 rows.
Adds RewriteLibrarySymlinks in internal/importer/migration to walk a
library directory and atomically rewrite arr symlinks that point at
<nzbdav_mount>/.ids/<guid> to the final altmount path.  Introduces
DBSymlinkLookup adapter in internal/database, a new
POST /import/nzbdav/migrate-symlinks handler, and enriches the existing
status endpoint with migration_stats when available.
Add binary self-update path alongside the existing Docker update flow and
publish a rolling `dev` prerelease of CLI binaries so non-Docker users
can track the dev channel.

- internal/updater: fetch GitHub release, verify SHA-512, extract from
  tar.gz/zip, swap binary via minio/selfupdate. Skip when running inside
  a container (/.dockerenv or KUBERNETES_SERVICE_HOST).
- internal/api: route POST /system/update/apply to docker or binary path
  based on environment; expose binary_update_available in status.
- frontend: enable the Apply button whenever either path is available
  and tailor the copy to the active mode.
- .github/workflows/build-cli.yml: reusable workflow_call that builds
  the full OS/arch matrix and (optionally) attaches assets to a release.
- release.yml + dev-image.yml: consume the shared workflow; dev-image
  publishes to a rolling `dev` prerelease.

Closes #497
…son-638589

# Conflicts:
#	internal/api/nzbdav_handlers.go
#	internal/api/server.go
#	internal/database/import_migration_repository.go
#	internal/database/symlink_lookup.go
#	internal/importer/migration/symlinks.go
#	internal/importer/migration/symlinks_test.go
#	internal/importer/scanner/nzbdav.go
#	internal/importer/service.go
@javi11 javi11 merged commit c3fccd2 into main Apr 22, 2026
2 checks passed
@javi11 javi11 deleted the claude/inspiring-jackson-638589 branch April 22, 2026 14:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Auto Update(Dev) for non-Docker instances

1 participant