diff --git a/server/index.js b/server/index.js index 85fbf1bbc..aa048b4f5 100644 --- a/server/index.js +++ b/server/index.js @@ -729,65 +729,16 @@ app.get('/api/alerts/status', (req, res) => { // Version API endpoint app.get('/api/version', async (req, res) => { try { - const { execSync } = require('child_process'); - const packageJson = require('../package.json'); + const { getCurrentVersionInfo } = require('./versionUtils'); + + // Get version info using centralized logic + const versionInfo = getCurrentVersionInfo(); + const currentVersion = versionInfo.version; + const gitBranch = versionInfo.gitBranch; + const isDevelopment = versionInfo.isDevelopment; - let currentVersion = packageJson.version || 'N/A'; let latestVersion = currentVersion; let updateAvailable = false; - let gitBranch = null; - - // Try to detect git branch and calculate dynamic version - try { - const gitDir = path.join(__dirname, '..'); - - // Get current branch - gitBranch = execSync('git branch --show-current', { - cwd: gitDir, - encoding: 'utf8' - }).trim(); - - // If on develop branch, calculate RC version from git - if (gitBranch === 'develop') { - try { - // Get the latest stable release tag - const latestStableTag = execSync('git tag -l "v*" | grep -v "rc\\|alpha\\|beta" | sort -V | tail -1', { - cwd: gitDir, - encoding: 'utf8', - shell: '/bin/bash' - }).trim(); - - if (latestStableTag) { - // Remove 'v' prefix to get base version - const baseVersion = latestStableTag.replace(/^v/, ''); - - // Count commits since the latest stable tag - const commitsSince = execSync(`git rev-list --count ${latestStableTag}..HEAD`, { - cwd: gitDir, - encoding: 'utf8' - }).trim(); - - const commitsCount = parseInt(commitsSince, 10); - - if (commitsCount > 0) { - // Calculate RC version: base version + rc + commit count - currentVersion = `${baseVersion}-rc${commitsCount}`; - } else { - // No commits since stable, use base version - currentVersion = baseVersion; - } - } - } catch (versionError) { - console.log("[Version API] Could not calculate RC version from git, using package.json"); - // Fall back to package.json version - currentVersion = packageJson.version; - } - } - } catch (gitError) { - // Git not available or not a git repo - gitBranch = null; - currentVersion = packageJson.version; - } try { // Try to check for updates, but don't fail if it doesn't work @@ -804,7 +755,7 @@ app.get('/api/version', async (req, res) => { latestVersion: latestVersion, updateAvailable: updateAvailable, gitBranch: gitBranch, - isDevelopment: gitBranch === 'develop' || process.env.NODE_ENV === 'development' + isDevelopment: isDevelopment }); } catch (error) { console.error("[Version API] Error in version endpoint:", error); diff --git a/server/updateManager.js b/server/updateManager.js index 2d4e176f0..c7f0dff7e 100644 --- a/server/updateManager.js +++ b/server/updateManager.js @@ -5,6 +5,7 @@ const path = require('path'); const { exec, spawn } = require('child_process'); const { promisify } = require('util'); const { getUpdateChannelPreference } = require('./configLoader'); +const { getCurrentVersion } = require('./versionUtils'); const execAsync = promisify(exec); class UpdateManager { @@ -64,6 +65,9 @@ class UpdateManager { try { console.log('[UpdateManager] Checking for updates...'); + // Get the current version using centralized logic + const dynamicCurrentVersion = getCurrentVersion(); + // Use override channel if provided and valid, otherwise use config const configChannel = getUpdateChannelPreference(); const updateChannel = (channelOverride && ['stable', 'rc'].includes(channelOverride)) @@ -125,8 +129,8 @@ class UpdateManager { if (!latestRelease) { // No newer RC version found const updateInfo = { - currentVersion: this.currentVersion, - latestVersion: this.currentVersion, + currentVersion: dynamicCurrentVersion, + latestVersion: dynamicCurrentVersion, updateAvailable: false, isDocker: this.isDockerEnvironment(), releaseNotes: 'No newer RC version available', @@ -135,7 +139,7 @@ class UpdateManager { assets: [], updateChannel: channelDescription }; - console.log(`[UpdateManager] No RC updates available: ${this.currentVersion}`); + console.log(`[UpdateManager] No RC updates available: ${dynamicCurrentVersion}`); return updateInfo; } @@ -145,9 +149,9 @@ class UpdateManager { const latestVersion = response.data.tag_name.replace('v', ''); // For stable channel, also consider "downgrade" from RC as an update - const isCurrentRC = this.isReleaseCandidate(); + const isCurrentRC = this.isReleaseCandidate(dynamicCurrentVersion); const isStableChannel = updateChannel === 'stable'; - const isDifferentVersion = latestVersion !== this.currentVersion; + const isDifferentVersion = latestVersion !== dynamicCurrentVersion; let updateAvailable; if (isStableChannel && isCurrentRC && isDifferentVersion) { @@ -155,14 +159,14 @@ class UpdateManager { updateAvailable = true; } else if (updateChannel === 'rc') { // For RC channel, show update if versions differ or if latest is newer - updateAvailable = isDifferentVersion || semver.gt(latestVersion, this.currentVersion); + updateAvailable = isDifferentVersion || semver.gt(latestVersion, dynamicCurrentVersion); } else { // Normal case: only newer versions - updateAvailable = semver.gt(latestVersion, this.currentVersion); + updateAvailable = semver.gt(latestVersion, dynamicCurrentVersion); } const updateInfo = { - currentVersion: this.currentVersion, + currentVersion: dynamicCurrentVersion, latestVersion, updateAvailable, isDocker: this.isDockerEnvironment(), @@ -177,7 +181,7 @@ class UpdateManager { })) }; - console.log(`[UpdateManager] Current version: ${this.currentVersion}, Latest version: ${latestVersion}, Channel: ${channelDescription}, Docker: ${updateInfo.isDocker}`); + console.log(`[UpdateManager] Current version: ${dynamicCurrentVersion}, Latest version: ${latestVersion}, Channel: ${channelDescription}, Docker: ${updateInfo.isDocker}`); return updateInfo; } catch (error) { diff --git a/server/versionUtils.js b/server/versionUtils.js new file mode 100644 index 000000000..28075edfd --- /dev/null +++ b/server/versionUtils.js @@ -0,0 +1,101 @@ +/** + * Centralized version calculation utility + * Used by both /api/version endpoint and UpdateManager to ensure consistency + */ + +const { execSync } = require('child_process'); +const path = require('path'); + +/** + * Calculate the current version dynamically from git + * @returns {Object} Version information including version, branch, and isDevelopment + */ +function getCurrentVersionInfo() { + try { + const packageJson = require('../package.json'); + + let currentVersion = packageJson.version || 'N/A'; + let gitBranch = null; + let isDevelopment = false; + + // Try to detect git branch and calculate dynamic version + try { + const gitDir = path.join(__dirname, '..'); + + // Get current branch + gitBranch = execSync('git branch --show-current', { + cwd: gitDir, + encoding: 'utf8' + }).trim(); + + // If on develop branch, calculate RC version from git + if (gitBranch === 'develop') { + isDevelopment = true; + try { + // Get the latest stable release tag + const latestStableTag = execSync('git tag -l "v*" | grep -v "rc\\\\|alpha\\\\|beta" | sort -V | tail -1', { + cwd: gitDir, + encoding: 'utf8', + shell: '/bin/bash' + }).trim(); + + if (latestStableTag) { + // Remove 'v' prefix to get base version + const baseVersion = latestStableTag.replace(/^v/, ''); + + // Count commits since the latest stable tag + const commitsSince = execSync(`git rev-list --count ${latestStableTag}..HEAD`, { + cwd: gitDir, + encoding: 'utf8' + }).trim(); + + const commitsCount = parseInt(commitsSince, 10); + + if (commitsCount > 0) { + // Calculate RC version: base version + rc + commit count + currentVersion = `${baseVersion}-rc${commitsCount}`; + } else { + // No commits since stable, use base version + currentVersion = baseVersion; + } + } + } catch (versionError) { + console.log('[VersionUtils] Could not calculate RC version from git, using package.json'); + // Fall back to package.json version + currentVersion = packageJson.version; + } + } + } catch (gitError) { + // Git not available or not a git repo + gitBranch = null; + currentVersion = packageJson.version; + } + + return { + version: currentVersion, + gitBranch: gitBranch, + isDevelopment: isDevelopment || gitBranch === 'develop' || process.env.NODE_ENV === 'development' + }; + } catch (error) { + console.warn('[VersionUtils] Error getting current version:', error.message); + const packageJson = require('../package.json'); + return { + version: packageJson.version || 'N/A', + gitBranch: null, + isDevelopment: false + }; + } +} + +/** + * Get just the version string (for backwards compatibility) + * @returns {string} The current version + */ +function getCurrentVersion() { + return getCurrentVersionInfo().version; +} + +module.exports = { + getCurrentVersionInfo, + getCurrentVersion +}; \ No newline at end of file