diff --git a/README.md b/README.md index a21915c22..05ad77ca3 100644 --- a/README.md +++ b/README.md @@ -465,6 +465,22 @@ For development purposes or running directly from source, see the **[DEVELOPMENT ## 🔄 Updating Pulse +### Web-Based Updates (Non-Docker) + +For non-Docker installations, Pulse includes a built-in update mechanism: + +1. Open the Settings modal (gear icon in the top right) +2. Scroll to the "Software Updates" section +3. Click "Check for Updates" +4. If an update is available, review the release notes +5. Click "Apply Update" to install it automatically + +The update process: +- Backs up your configuration files +- Downloads and applies the update +- Preserves your settings +- Automatically restarts the application + ### Community Scripts LXC Installation If you installed using the Community Scripts method, simply re-run the original installation command: @@ -477,7 +493,7 @@ The script will detect the existing installation and update it automatically. ### Docker Compose Installation -To update a Docker Compose installation: +Docker deployments must be updated by pulling the new image: ```bash cd /path/to/your/pulse-config @@ -487,6 +503,8 @@ docker compose up -d This pulls the latest image and recreates the container with the new version. +**Note:** The web-based update feature will detect Docker deployments and provide these instructions instead of attempting an in-place update. + ### Manual LXC Installation If you used the manual installation script, update by re-running it: diff --git a/server/updateManager.js b/server/updateManager.js index a879bdf2d..db5583139 100644 --- a/server/updateManager.js +++ b/server/updateManager.js @@ -39,6 +39,7 @@ class UpdateManager { currentVersion: this.currentVersion, latestVersion, updateAvailable, + isDocker: this.isDockerEnvironment(), releaseNotes: response.data.body || 'No release notes available', releaseUrl: response.data.html_url, publishedAt: response.data.published_at, @@ -49,7 +50,7 @@ class UpdateManager { })) }; - console.log(`[UpdateManager] Current version: ${this.currentVersion}, Latest version: ${latestVersion}`); + console.log(`[UpdateManager] Current version: ${this.currentVersion}, Latest version: ${latestVersion}, Docker: ${updateInfo.isDocker}`); return updateInfo; } catch (error) { @@ -104,6 +105,15 @@ class UpdateManager { } } + /** + * Check if running in Docker + */ + isDockerEnvironment() { + return process.env.DOCKER_DEPLOYMENT === 'true' || + require('fs').existsSync('/.dockerenv') || + (process.env.container === 'docker'); + } + /** * Apply update */ @@ -112,6 +122,16 @@ class UpdateManager { throw new Error('Update already in progress'); } + // Check if running in Docker + if (this.isDockerEnvironment()) { + throw new Error( + 'Automatic updates are not supported in Docker deployments. ' + + 'Please update your Docker image by pulling the latest version:\n' + + 'docker pull rcourtman/pulse:latest\n' + + 'or update your docker-compose.yml to use the new version tag.' + ); + } + this.updateInProgress = true; try { @@ -166,8 +186,6 @@ class UpdateManager { progressCallback({ phase: 'extract', progress: 100 }); } - // Detect deployment type - const isDocker = process.env.DOCKER_DEPLOYMENT === 'true' || require('fs').existsSync('/.dockerenv'); const pulseDir = path.join(__dirname, '..'); if (progressCallback) { @@ -207,20 +225,14 @@ class UpdateManager { // Schedule restart console.log('[UpdateManager] Scheduling restart...'); setTimeout(() => { - if (isDocker) { - // In Docker, just exit - container will be restarted - console.log('[UpdateManager] Exiting for Docker restart...'); + // For systemd/manual deployments, try to restart + console.log('[UpdateManager] Attempting restart...'); + + // Try systemctl first + execAsync('sudo systemctl restart pulse').catch(() => { + // If systemctl fails, just exit process.exit(0); - } else { - // For systemd/manual deployments, try to restart - console.log('[UpdateManager] Attempting restart...'); - - // Try systemctl first - execAsync('sudo systemctl restart pulse').catch(() => { - // If systemctl fails, just exit - process.exit(0); - }); - } + }); }, 2000); // Cleanup diff --git a/src/public/js/ui/settings.js b/src/public/js/ui/settings.js index 5bad0f648..976810a90 100644 --- a/src/public/js/ui/settings.js +++ b/src/public/js/ui/settings.js @@ -878,7 +878,33 @@ PulseApp.ui.settings = (() => { .replace(/^/, '

') .replace(/$/, '

'); - latestVersionInfo.innerHTML = `Update available!`; + // Handle Docker deployments differently + if (updateInfo.isDocker) { + latestVersionInfo.innerHTML = `Update available! (Docker deployment detected)`; + + // Replace the apply button with Docker instructions + const applyButton = document.getElementById('apply-update-button'); + const buttonContainer = applyButton.parentElement; + + buttonContainer.innerHTML = ` +
+

Docker Update Instructions:

+
    +
  1. Pull the latest image: docker pull rcourtman/pulse:latest
  2. +
  3. Recreate your container with the new image
  4. +
  5. Or update your docker-compose.yml to version ${updateInfo.latestVersion}
  6. +
+ + View release on GitHub + + + + +
+ `; + } else { + latestVersionInfo.innerHTML = `Update available!`; + } } else { updateDetails.classList.add('hidden'); latestVersionInfo.innerHTML = `You are running the latest version`;