Skip to content
Merged
Show file tree
Hide file tree
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
14 changes: 12 additions & 2 deletions sn-manager/internal/updater/updater.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,14 @@ func (u *AutoUpdater) ShouldUpdate(current, latest string) bool {
current = strings.TrimPrefix(current, "v")
latest = strings.TrimPrefix(latest, "v")

// Allow testnet-tagged releases (e.g., v1.2.3-testnet.1).
if utils.IsTestnetReleaseTag(latest) {
if !utils.SameMajor(current, latest) {
return false
}
return utils.CompareVersions(current, latest) < 0
}

// Skip pre-release targets (beta, alpha, rc, etc.)
if strings.Contains(latest, "-") {
return false
Expand Down Expand Up @@ -192,8 +200,10 @@ func (u *AutoUpdater) ForceSyncToLatest(_ context.Context) {
// If force is true, bypass gateway idleness and version policy checks.
func (u *AutoUpdater) checkAndUpdateCombined(force bool) {

// Fetch latest stable release once
release, err := u.githubClient.GetLatestStableRelease()
chainID, _ := utils.ReadSupernodeChainID()

// Fetch latest release once (testnet prefers "-testnet" tags, otherwise stable)
release, err := utils.LatestReleaseForChainID(u.githubClient, chainID)
if err != nil {
log.Printf("Failed to check releases: %v", err)
return
Expand Down
85 changes: 85 additions & 0 deletions sn-manager/internal/utils/network.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package utils

import (
"fmt"
"os"
"path/filepath"
"strings"

"github.com/LumeraProtocol/supernode/v2/pkg/github"
"gopkg.in/yaml.v3"
)

const testnetTagMarker = "-testnet"

// SupernodeConfigPath returns the expected path for the SuperNode config file
// based on the current process HOME/user.
func SupernodeConfigPath() string {
home, _ := os.UserHomeDir()
if home == "" {
home = os.Getenv("HOME")
}
return filepath.Join(home, ".supernode", "config.yml")
}

// ReadSupernodeChainID reads lumera.chain_id from the SuperNode config file.
func ReadSupernodeChainID() (string, error) {
path := SupernodeConfigPath()
data, err := os.ReadFile(path)
if err != nil {
return "", err
}

var cfg struct {
Lumera struct {
ChainID string `yaml:"chain_id"`
} `yaml:"lumera"`
}
if err := yaml.Unmarshal(data, &cfg); err != nil {
return "", fmt.Errorf("failed to parse supernode config %s: %w", path, err)
}

chainID := strings.TrimSpace(cfg.Lumera.ChainID)
if chainID == "" {
return "", fmt.Errorf("chain_id not set in %s", path)
}
return chainID, nil
}

func IsTestnetChainID(chainID string) bool {
return strings.Contains(strings.ToLower(chainID), "testnet")
}

func IsTestnetReleaseTag(tag string) bool {
return strings.Contains(strings.ToLower(tag), testnetTagMarker)
}

// LatestTestnetRelease returns the most recent non-draft release whose tag
// contains "-testnet". Release ordering is taken from the GitHub API response.
func LatestTestnetRelease(client github.GithubClient) (*github.Release, error) {
releases, err := client.ListReleases()
if err != nil {
return nil, err
}
for _, r := range releases {
if r == nil || r.Draft {
continue
}
if IsTestnetReleaseTag(r.TagName) {
return r, nil
}
}
return nil, fmt.Errorf("no testnet releases found")
}

// LatestReleaseForChainID selects the appropriate "latest" release based on the
// chain ID. Testnet chains prefer "-testnet" tagged releases; otherwise it
// falls back to the latest stable release.
func LatestReleaseForChainID(client github.GithubClient, chainID string) (*github.Release, error) {
if IsTestnetChainID(chainID) {
if r, err := LatestTestnetRelease(client); err == nil {
return r, nil
}
}
return client.GetLatestStableRelease()
}