diff --git a/.github/workflows/rc-release.yml b/.github/workflows/rc-release.yml index 56c05569b..e3469823d 100644 --- a/.github/workflows/rc-release.yml +++ b/.github/workflows/rc-release.yml @@ -19,11 +19,35 @@ jobs: VERSION=$(node -p "require('./package.json').version") echo "version=$VERSION" >> $GITHUB_OUTPUT + - name: Analyze version for RC release + id: analyze + run: | + # Use the same version analysis logic as stable releases + node -e " + const { analyzeCommitsForVersionBump } = require('./server/versionUtils'); + const analysis = analyzeCommitsForVersionBump(); + + console.log('📊 RC Version Analysis:'); + console.log('Current stable version:', analysis.currentStableVersion); + console.log('Suggested next version:', analysis.suggestedVersion); + console.log('Bump type:', analysis.bumpType); + console.log('Total commits:', analysis.totalCommits); + + // Set base version for RC releases + const fs = require('fs'); + const output = fs.readFileSync(process.env.GITHUB_OUTPUT, 'utf8'); + fs.writeFileSync(process.env.GITHUB_OUTPUT, output + + 'base_version=' + analysis.suggestedVersion + '\\n' + + 'current_stable=' + analysis.currentStableVersion + '\\n' + + 'reasoning=' + analysis.reasoning + '\\n' + ); + " + - name: Check if RC release needed id: check run: | - # Get base version (remove any existing RC suffix) - BASE_VERSION=$(echo "${{ steps.version.outputs.version }}" | sed 's/-rc[0-9]*$//') + # Use analyzed base version instead of package.json + BASE_VERSION="${{ steps.analyze.outputs.base_version }}" # Get the latest RC tag for this base version LATEST_RC=$(git tag -l "v${BASE_VERSION}-rc*" | sort -V | tail -n1) @@ -66,10 +90,34 @@ jobs: git config --local user.email "action@github.com" git config --local user.name "GitHub Action" - # Commit the version change + # Commit the version change with conflict resolution git add package.json git commit -m "chore: bump version to $NEW_VERSION for RC release" - git push origin develop + + # Pull and rebase before pushing to handle any concurrent changes + echo "🔄 Pulling latest changes before push..." + git fetch origin develop + if ! git rebase origin/develop; then + echo "⚠️ Rebase conflicts detected, attempting resolution..." + # For package.json conflicts, prefer our version (the RC version) + git checkout --ours package.json 2>/dev/null || true + git add package.json 2>/dev/null || true + git rebase --continue 2>/dev/null || true + fi + + # Push with retry logic + echo "📤 Pushing to develop..." + for i in {1..3}; do + if git push origin develop; then + echo "✅ Successfully pushed to develop" + break + else + echo "⚠️ Push failed (attempt $i/3), retrying..." + git fetch origin develop + git rebase origin/develop 2>/dev/null || true + sleep $((i * 2)) + fi + done - name: Set up Docker Buildx if: steps.check.outputs.create_release == 'true' diff --git a/.github/workflows/stable-release.yml b/.github/workflows/stable-release.yml index 438554f52..dfda465e0 100644 --- a/.github/workflows/stable-release.yml +++ b/.github/workflows/stable-release.yml @@ -178,9 +178,35 @@ jobs: 🤖 Generated by automated stable release workflow" - # Create and push tag + # Create and push tag with conflict resolution git tag -a "v$NEW_VERSION" -m "Release v$NEW_VERSION" - git push origin main + + # Pull and rebase before pushing to handle any concurrent changes + echo "🔄 Pulling latest changes before push..." + git fetch origin main + if ! git rebase origin/main; then + echo "⚠️ Rebase conflicts detected, attempting resolution..." + # For package.json conflicts, prefer our version (the release version) + git checkout --ours package.json package-lock.json 2>/dev/null || true + git add package.json package-lock.json 2>/dev/null || true + git rebase --continue 2>/dev/null || true + fi + + # Push with retry logic + echo "📤 Pushing to main..." + for i in {1..3}; do + if git push origin main; then + echo "✅ Successfully pushed to main" + break + else + echo "⚠️ Push failed (attempt $i/3), retrying..." + git fetch origin main + git rebase origin/main 2>/dev/null || true + sleep $((i * 2)) + fi + done + + echo "📤 Pushing tag..." git push origin "v$NEW_VERSION" - name: Generate changelog diff --git a/src/public/js/main.js b/src/public/js/main.js index b65d47a7d..d819bea5b 100644 --- a/src/public/js/main.js +++ b/src/public/js/main.js @@ -167,21 +167,9 @@ document.addEventListener('DOMContentLoaded', function() { return; } - // Get user's channel preference from config - let userChannel = 'stable'; // default - try { - const configResponse = await fetch('/api/config'); - if (configResponse.ok) { - const config = await configResponse.json(); - userChannel = config.advanced?.updateChannel || 'stable'; - } - } catch (error) { - console.warn('Could not load user channel preference, using stable'); - } - - // Check version with user's preferred channel - const versionUrl = userChannel === 'stable' ? '/api/version' : `/api/version?channel=${userChannel}`; - fetch(versionUrl) + // Use the user's configured channel from server config + // No need to override - let the server use its configured channel + fetch('/api/version') .then(response => { if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); diff --git a/src/public/js/ui/settings.js b/src/public/js/ui/settings.js index e50ccdc86..92df69e77 100644 --- a/src/public/js/ui/settings.js +++ b/src/public/js/ui/settings.js @@ -196,10 +196,21 @@ PulseApp.ui.settings = (() => { } else if (activeTab === 'system') { // Auto-check for latest version when system tab is opened checkLatestVersion(); - // Initialize update channel warning visibility + // Initialize update channel warning visibility and restore channel preference setTimeout(() => { const channelSelect = document.querySelector('select[name="UPDATE_CHANNEL"]'); if (channelSelect) { + // Check if there's a stored channel preference from a recent update + const storedChannelPreference = localStorage.getItem('pulse_update_channel_preference'); + if (storedChannelPreference && storedChannelPreference !== channelSelect.value) { + // Update the select to match the stored preference + channelSelect.value = storedChannelPreference; + showMessage(`Restored ${storedChannelPreference === 'rc' ? 'RC' : 'Stable'} channel preference from update.`, 'info'); + // Clear the stored preference since we've applied it + localStorage.removeItem('pulse_update_channel_preference'); + // Save the configuration with the restored preference + setTimeout(() => saveConfiguration(), 1000); + } onUpdateChannelChange(channelSelect.value); } }, 0); @@ -2032,6 +2043,25 @@ PulseApp.ui.settings = (() => { progressText.textContent = 'Update complete! Restarting...'; } showMessage('Update applied successfully. The application will restart momentarily.', 'success'); + + // Store the current channel preference for after restart + const currentChannelSelect = document.querySelector('select[name="UPDATE_CHANNEL"]'); + if (currentChannelSelect) { + localStorage.setItem('pulse_update_channel_preference', currentChannelSelect.value); + } + + // Auto-refresh after restart delay + setTimeout(() => { + if (progressText) { + progressText.textContent = 'Reconnecting...'; + } + showMessage('Attempting to reconnect...', 'info'); + + // Try to reload the page after service restart + setTimeout(() => { + window.location.reload(); + }, 2000); + }, 8000); // Wait 8 seconds for service to restart }); window.socket.on('updateError', (data) => { diff --git a/src/public/js/ui/toastNotifications.js b/src/public/js/ui/toastNotifications.js index d8ea4de3a..29288afe8 100644 --- a/src/public/js/ui/toastNotifications.js +++ b/src/public/js/ui/toastNotifications.js @@ -229,6 +229,10 @@ PulseApp.ui.toast = (() => { return showToast(message, 'warning', 5000); } + function info(message) { + return showToast(message, 'info', 4000); + } + function confirm(message, onConfirm, onCancel = null) { return showConfirmToast(message, onConfirm, onCancel); } @@ -242,6 +246,7 @@ PulseApp.ui.toast = (() => { success, error, warning, + info, confirm }; })();