fix: skip update check for source builds and show appropriate UI message
Source builds use commit hashes (main-c147fa1) not semantic versions (v4.23.0), so update checks would always fail or show misleading "Update Available" banners. Changes: - Add IsSourceBuild flag to VersionInfo struct - Detect source builds via BUILD_FROM_SOURCE marker file - Skip update check for source builds (like Docker) - Update frontend to show "Built from source" message - Disable manual update check button for source builds - Return "source" deployment type for source builds Backend: - internal/updates/version.go: Add isSourceBuildEnvironment() detection - internal/updates/manager.go: Skip check with appropriate message - internal/api/types.go: Add isSourceBuild to API response - internal/api/router.go: Include isSourceBuild in version endpoint Frontend: - src/api/updates.ts: Add isSourceBuild to VersionInfo type - src/stores/updates.ts: Don't poll for updates on source builds - src/components/Settings/Settings.tsx: Show "Built from source" message Fixes the confusing "Update Available" banner for users who explicitly chose --source to get latest main branch code. Co-authored-by: Codex AI
This commit is contained in:
parent
0e0661eb68
commit
66b97333f7
7 changed files with 60 additions and 3 deletions
|
|
@ -26,6 +26,7 @@ export interface VersionInfo {
|
||||||
runtime: string;
|
runtime: string;
|
||||||
channel?: string;
|
channel?: string;
|
||||||
isDocker: boolean;
|
isDocker: boolean;
|
||||||
|
isSourceBuild: boolean;
|
||||||
isDevelopment: boolean;
|
isDevelopment: boolean;
|
||||||
deploymentType?: string;
|
deploymentType?: string;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3257,9 +3257,13 @@ const Settings: Component<SettingsProps> = (props) => {
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={checkForUpdates}
|
onClick={checkForUpdates}
|
||||||
disabled={checkingForUpdates() || versionInfo()?.isDocker}
|
disabled={
|
||||||
|
checkingForUpdates() ||
|
||||||
|
versionInfo()?.isDocker ||
|
||||||
|
versionInfo()?.isSourceBuild
|
||||||
|
}
|
||||||
class={`px-4 py-2 text-sm rounded-lg transition-colors flex items-center gap-2 ${
|
class={`px-4 py-2 text-sm rounded-lg transition-colors flex items-center gap-2 ${
|
||||||
versionInfo()?.isDocker
|
versionInfo()?.isDocker || versionInfo()?.isSourceBuild
|
||||||
? 'bg-gray-100 dark:bg-gray-700 text-gray-400 dark:text-gray-500 cursor-not-allowed'
|
? 'bg-gray-100 dark:bg-gray-700 text-gray-400 dark:text-gray-500 cursor-not-allowed'
|
||||||
: 'bg-blue-600 text-white hover:bg-blue-700'
|
: 'bg-blue-600 text-white hover:bg-blue-700'
|
||||||
}`}
|
}`}
|
||||||
|
|
@ -3284,6 +3288,15 @@ const Settings: Component<SettingsProps> = (props) => {
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
|
<Show when={versionInfo()?.isSourceBuild}>
|
||||||
|
<div class="p-3 bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg">
|
||||||
|
<p class="text-xs text-blue-800 dark:text-blue-200">
|
||||||
|
<strong>Built from source:</strong> Pull the latest code from git and
|
||||||
|
rebuild to update.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
|
|
||||||
<Show when={Boolean(updateInfo()?.warning)}>
|
<Show when={Boolean(updateInfo()?.warning)}>
|
||||||
<div class="p-3 bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-700 rounded-lg">
|
<div class="p-3 bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-700 rounded-lg">
|
||||||
<p class="text-xs text-amber-800 dark:text-amber-200">
|
<p class="text-xs text-amber-800 dark:text-amber-200">
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@ const checkForUpdates = async (force = false): Promise<void> => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't check for updates in Docker or development builds
|
// Don't check for updates in Docker or development builds
|
||||||
if (version.isDocker || version.isDevelopment) {
|
if (version.isDocker || version.isDevelopment || version.isSourceBuild) {
|
||||||
setUpdateAvailable(false);
|
setUpdateAvailable(false);
|
||||||
setUpdateInfo(null);
|
setUpdateInfo(null);
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -2244,6 +2244,7 @@ func (r *Router) handleVersion(w http.ResponseWriter, req *http.Request) {
|
||||||
Runtime: runtime.Version(),
|
Runtime: runtime.Version(),
|
||||||
Channel: "stable",
|
Channel: "stable",
|
||||||
IsDocker: false,
|
IsDocker: false,
|
||||||
|
IsSourceBuild: false,
|
||||||
IsDevelopment: true,
|
IsDevelopment: true,
|
||||||
}
|
}
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
|
@ -2260,6 +2261,7 @@ func (r *Router) handleVersion(w http.ResponseWriter, req *http.Request) {
|
||||||
Runtime: versionInfo.Runtime,
|
Runtime: versionInfo.Runtime,
|
||||||
Channel: versionInfo.Channel,
|
Channel: versionInfo.Channel,
|
||||||
IsDocker: versionInfo.IsDocker,
|
IsDocker: versionInfo.IsDocker,
|
||||||
|
IsSourceBuild: versionInfo.IsSourceBuild,
|
||||||
IsDevelopment: versionInfo.IsDevelopment,
|
IsDevelopment: versionInfo.IsDevelopment,
|
||||||
DeploymentType: versionInfo.DeploymentType,
|
DeploymentType: versionInfo.DeploymentType,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ type VersionResponse struct {
|
||||||
Runtime string `json:"runtime,omitempty"`
|
Runtime string `json:"runtime,omitempty"`
|
||||||
Channel string `json:"channel,omitempty"`
|
Channel string `json:"channel,omitempty"`
|
||||||
IsDocker bool `json:"isDocker"`
|
IsDocker bool `json:"isDocker"`
|
||||||
|
IsSourceBuild bool `json:"isSourceBuild"`
|
||||||
IsDevelopment bool `json:"isDevelopment"`
|
IsDevelopment bool `json:"isDevelopment"`
|
||||||
DeploymentType string `json:"deploymentType,omitempty"`
|
DeploymentType string `json:"deploymentType,omitempty"`
|
||||||
UpdateAvailable bool `json:"updateAvailable"`
|
UpdateAvailable bool `json:"updateAvailable"`
|
||||||
|
|
|
||||||
|
|
@ -164,6 +164,23 @@ func (m *Manager) CheckForUpdatesWithChannel(ctx context.Context, channel string
|
||||||
return info, nil
|
return info, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Skip update check for source builds
|
||||||
|
if currentInfo.IsSourceBuild {
|
||||||
|
info := &UpdateInfo{
|
||||||
|
Available: false,
|
||||||
|
CurrentVersion: currentInfo.Version,
|
||||||
|
LatestVersion: currentInfo.Version,
|
||||||
|
}
|
||||||
|
if useCache {
|
||||||
|
m.statusMu.Lock()
|
||||||
|
m.checkCache[channel] = info
|
||||||
|
m.cacheTime[channel] = time.Now()
|
||||||
|
m.statusMu.Unlock()
|
||||||
|
}
|
||||||
|
m.updateStatus("idle", 0, "Updates not available for source builds")
|
||||||
|
return info, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Parse current version first
|
// Parse current version first
|
||||||
currentVer, err := ParseVersion(currentInfo.Version)
|
currentVer, err := ParseVersion(currentInfo.Version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ type VersionInfo struct {
|
||||||
Runtime string `json:"runtime"`
|
Runtime string `json:"runtime"`
|
||||||
Channel string `json:"channel,omitempty"`
|
Channel string `json:"channel,omitempty"`
|
||||||
IsDocker bool `json:"isDocker"`
|
IsDocker bool `json:"isDocker"`
|
||||||
|
IsSourceBuild bool `json:"isSourceBuild"`
|
||||||
IsDevelopment bool `json:"isDevelopment"`
|
IsDevelopment bool `json:"isDevelopment"`
|
||||||
DeploymentType string `json:"deploymentType"`
|
DeploymentType string `json:"deploymentType"`
|
||||||
}
|
}
|
||||||
|
|
@ -128,6 +129,7 @@ func GetCurrentVersion() (*VersionInfo, error) {
|
||||||
Channel: detectChannelFromVersion(normalized),
|
Channel: detectChannelFromVersion(normalized),
|
||||||
IsDevelopment: isDev,
|
IsDevelopment: isDev,
|
||||||
IsDocker: isDockerEnvironment(),
|
IsDocker: isDockerEnvironment(),
|
||||||
|
IsSourceBuild: isSourceBuildEnvironment(),
|
||||||
DeploymentType: GetDeploymentType(),
|
DeploymentType: GetDeploymentType(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -287,6 +289,23 @@ func isDockerEnvironment() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isSourceBuildEnvironment checks if running from a source build
|
||||||
|
func isSourceBuildEnvironment() bool {
|
||||||
|
markerPaths := []string{
|
||||||
|
"BUILD_FROM_SOURCE",
|
||||||
|
"/opt/pulse/BUILD_FROM_SOURCE",
|
||||||
|
filepath.Join(filepath.Dir(os.Args[0]), "BUILD_FROM_SOURCE"),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, path := range markerPaths {
|
||||||
|
if fileExists(path) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// fileExists checks if a file exists
|
// fileExists checks if a file exists
|
||||||
func fileExists(path string) bool {
|
func fileExists(path string) bool {
|
||||||
// Use os.Stat instead of exec.Command for better performance and reliability
|
// Use os.Stat instead of exec.Command for better performance and reliability
|
||||||
|
|
@ -301,6 +320,10 @@ func GetDeploymentType() string {
|
||||||
return "docker"
|
return "docker"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isSourceBuildEnvironment() {
|
||||||
|
return "source"
|
||||||
|
}
|
||||||
|
|
||||||
// Check for ProxmoxVE LXC installation (has update command)
|
// Check for ProxmoxVE LXC installation (has update command)
|
||||||
if fileExists("/bin/update") {
|
if fileExists("/bin/update") {
|
||||||
// Read file directly instead of using exec.Command
|
// Read file directly instead of using exec.Command
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue