Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 98 additions & 14 deletions src/setup/updater.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,14 @@ type Version struct {
// UpdateExecutable checks for and applies the latest release from GitHub
func UpdateExecutable() error {
if !config.IsUpdateEnabled {
logger.Install.Warn("⚠️ Update check is disabled. Skipping update check.")
logger.Install.Warn("⚠️ Update check is disabled. Skipping update check. Change 'IsUpdateEnabled' in config.json to true to re-enable update checks.")
time.Sleep(1000 * time.Millisecond)
logger.Install.Info("⚠️ Continuing in 3 seconds...")
time.Sleep(1000 * time.Millisecond)
logger.Install.Info("⚠️ Continuing in 2 seconds...")
time.Sleep(1000 * time.Millisecond)
logger.Install.Info("⚠️ Continuing in 1 seconds...")
time.Sleep(1000 * time.Millisecond)
return nil
}

Expand All @@ -47,7 +54,11 @@ func UpdateExecutable() error {
return nil
}

logger.Install.Info("🕵️ Querying GitHub API for the latest release...")
if config.AllowPrereleaseUpdates {
logger.Install.Info("🕵️ Querying GitHub API for the latest (pre)release...")
} else {
logger.Install.Info("🕵️ Querying GitHub API for the latest stable release...")
}
latestRelease, err := getLatestRelease()
if err != nil {
return fmt.Errorf("❌ Failed to fetch latest release: %v", err)
Expand All @@ -65,20 +76,21 @@ func UpdateExecutable() error {

logger.Install.Info(fmt.Sprintf("Current version: %s, Latest version: %s", config.Version, latestRelease.TagName))

// Check pre-release status
if latestRelease.Prerelease && !config.AllowPrereleaseUpdates {
logger.Install.Warn(fmt.Sprintf("⚠️ Latest version %s is a pre-release. Enable 'AllowPrerelease' in config to update.", latestRelease.TagName))
return nil
}

// Check if we should update
updateReason, shouldUpdate := shouldUpdate(currentVer, latestVer)
if !shouldUpdate {
switch updateReason {
case "up-to-date":
logger.Install.Info("🎉 No update needed: you’re already on the latest version.")
case "major-update":
logger.Install.Warn(fmt.Sprintf("⚠️ Latest version %s is a major update from %s. Major Updates include Breaking changes in this project. Read the release notes and backup your Server folder before updating. Enable 'AllowMajorUpdates' in config to proceed.", latestRelease.TagName, config.Version))
logger.Install.Warn(fmt.Sprintf("⚠️ Update found: Latest version %s is a major update from %s. Major Updates include Breaking changes in this project. Read the release notes and backup your Server folder before updating. Enable 'AllowMajorUpdates' in config to proceed.", latestRelease.TagName, config.Version))
time.Sleep(1000 * time.Millisecond)
logger.Install.Info("⚠️ Continuing in 3 seconds...")
time.Sleep(1000 * time.Millisecond)
logger.Install.Info("⚠️ Continuing in 2 seconds...")
time.Sleep(1000 * time.Millisecond)
logger.Install.Info("⚠️ Continuing in 1 seconds...")
time.Sleep(1000 * time.Millisecond)
}
return nil
}
Expand Down Expand Up @@ -188,9 +200,10 @@ func shouldUpdate(current, latest Version) (string, bool) {
return "", true
}

// getLatestRelease fetches the latest release info from GitHub API
// getLatestRelease fetches the most recent release (or prerelease) from GitHub API
func getLatestRelease() (*githubRelease, error) {
resp, err := http.Get("https://api.github.com/repos/JacksonTheMaster/StationeersServerUI/releases/latest")
url := "https://api.github.com/repos/JacksonTheMaster/StationeersServerUI/releases"
resp, err := http.Get(url)
if err != nil {
return nil, err
}
Expand All @@ -200,11 +213,82 @@ func getLatestRelease() (*githubRelease, error) {
return nil, fmt.Errorf("bad response from GitHub API: %s", resp.Status)
}

var release githubRelease
if err := json.NewDecoder(resp.Body).Decode(&release); err != nil {
var releases []githubRelease
if err := json.NewDecoder(resp.Body).Decode(&releases); err != nil {
return nil, fmt.Errorf("failed to parse GitHub API response: %v", err)
}
return &release, nil

if len(releases) == 0 {
return nil, fmt.Errorf("no releases found")
}

// Find the most recent release
var latestRelease *githubRelease
var latestVersion Version
for i, release := range releases {
version, err := parseVersion(release.TagName)
if err != nil {
logger.Install.Warn(fmt.Sprintf("Skipping invalid version tag %s: %v", release.TagName, err))
continue
}
if i == 0 || isReleaseNewerVersion(version, latestVersion) {
latestVersion = version
latestRelease = &releases[i]
}
}

if latestRelease == nil {
return nil, fmt.Errorf("no suitable releases found")
}

// Log warning if the latest release is a prerelease
if latestRelease.Prerelease && !config.AllowPrereleaseUpdates {
logger.Install.Warn(fmt.Sprintf("⚠️ Pre-release Update found: Latest version %s is a pre-release. Enable 'AllowPrereleaseUpdates' in config.json to update to it. Continuing with the latest stable release.", latestRelease.TagName))
time.Sleep(1000 * time.Millisecond)
logger.Install.Info("⚠️ Continuing in 3 seconds...")
time.Sleep(1000 * time.Millisecond)
logger.Install.Info("⚠️ Continuing in 2 seconds...")
time.Sleep(1000 * time.Millisecond)
logger.Install.Info("⚠️ Continuing in 1 seconds...")
time.Sleep(1000 * time.Millisecond)
}

// If prerelease and AllowPrereleaseUpdates is false, find the latest stable release
if latestRelease.Prerelease && !config.AllowPrereleaseUpdates {
var stableRelease *githubRelease
var stableVersion Version
for i, release := range releases {
if release.Prerelease {
continue
}
version, err := parseVersion(release.TagName)
if err != nil {
logger.Install.Warn(fmt.Sprintf("Skipping invalid version tag %s: %v", release.TagName, err))
continue
}
if i == 0 || isReleaseNewerVersion(version, stableVersion) {
stableVersion = version
stableRelease = &releases[i]
}
}
if stableRelease == nil {
return nil, fmt.Errorf("no stable releases found")
}
return stableRelease, nil
}

return latestRelease, nil
}

// isNewerVersion compares two versions to determine if the first is newer
func isReleaseNewerVersion(v1, v2 Version) bool {
if v1.Major != v2.Major {
return v1.Major > v2.Major
}
if v1.Minor != v2.Minor {
return v1.Minor > v2.Minor
}
return v1.Patch > v2.Patch
}

// downloadNewExecutable downloads the new executable with a progress bar
Expand Down