From f95ac4c8ea76d7b3543478a81df98c5227b0644e Mon Sep 17 00:00:00 2001 From: Manuel Alessandro Collazo Date: Thu, 2 Apr 2026 11:01:10 +0700 Subject: [PATCH 1/4] fix: fall back to compatible initia binary release ## Summary - fix `weave init` failing when the chain-reported Initia version has no matching GitHub release asset - prefer the exact release tag when available - fall back to the highest downloadable release in the same major.minor series ## Testing - `go test ./cosmosutils` - built local binary and verified `weave init` passes the previous failure point --- cosmosutils/binary.go | 97 +++++++++++++++++++++++++++++++- cosmosutils/binary_test.go | 110 +++++++++++++++++++++++++++++++++++++ 2 files changed, 205 insertions(+), 2 deletions(-) diff --git a/cosmosutils/binary.go b/cosmosutils/binary.go index 76d0cc1..48b0a19 100644 --- a/cosmosutils/binary.go +++ b/cosmosutils/binary.go @@ -233,6 +233,94 @@ func GetMinitiadBinaryUrlFromLcd(httpClient *client.HTTPClient, rest string) (vm return vm, version, url, nil } +func getPlatformAssetURL(release BinaryRelease) (string, bool, error) { + goos, arch, err := getOSArch() + if err != nil { + return "", false, err + } + + searchString := fmt.Sprintf("%s_%s.tar.gz", goos, arch) + for _, asset := range release.Assets { + if strings.Contains(asset.BrowserDownloadURL, searchString) { + return asset.BrowserDownloadURL, true, nil + } + } + + return "", false, nil +} + +func majorMinorVersion(version string) (string, error) { + version = strings.TrimPrefix(version, "v") + mainVersion, _ := splitVersion(version) + parts := strings.Split(mainVersion, ".") + if len(parts) < 2 { + return "", fmt.Errorf("invalid semantic version: %s", version) + } + return fmt.Sprintf("%s.%s", parts[0], parts[1]), nil +} + +func selectCompatibleReleaseForVersion(releases []BinaryRelease, targetVersion string) (string, string, error) { + if len(releases) < 1 { + return "", "", fmt.Errorf("no releases found") + } + + targetVersion = normalizeVersion(targetVersion) + if !semverPattern.MatchString(targetVersion) { + return "", "", fmt.Errorf("invalid version format after normalization: %q", targetVersion) + } + + for _, release := range releases { + if release.TagName != targetVersion { + continue + } + + downloadURL, ok, err := getPlatformAssetURL(release) + if err != nil { + return "", "", err + } + if ok { + return release.TagName, downloadURL, nil + } + } + + targetSeries, err := majorMinorVersion(targetVersion) + if err != nil { + return "", "", err + } + + var selectedRelease *BinaryRelease + var selectedURL string + for _, release := range releases { + if !semverPattern.MatchString(release.TagName) { + continue + } + + releaseSeries, err := majorMinorVersion(release.TagName) + if err != nil || releaseSeries != targetSeries { + continue + } + + downloadURL, ok, err := getPlatformAssetURL(release) + if err != nil { + return "", "", err + } + if !ok { + continue + } + + if selectedRelease == nil || CompareSemVer(release.TagName, selectedRelease.TagName) { + selectedRelease = &release + selectedURL = downloadURL + } + } + + if selectedRelease != nil { + return selectedRelease.TagName, selectedURL, nil + } + + return "", "", fmt.Errorf("no compatible downloadable release found for chain version %s", targetVersion) +} + func detectMinitiaVM(versionString string) string { lower := strings.ToLower(versionString) switch { @@ -502,12 +590,17 @@ func GetInitiaBinaryUrlFromLcd(httpClient *client.HTTPClient, rest string) (stri } version := normalizeVersion(result.ApplicationVersion.Version) - url, err := getBinaryURL(version) + releases, err := fetchReleases("https://api.github.com/repos/initia-labs/initia/releases") + if err != nil { + return "", "", fmt.Errorf("failed to fetch initia releases: %w", err) + } + + selectedVersion, url, err := selectCompatibleReleaseForVersion(releases, version) if err != nil { return "", "", err } - return version, url, nil + return selectedVersion, url, nil } func getBinaryURL(version string) (string, error) { diff --git a/cosmosutils/binary_test.go b/cosmosutils/binary_test.go index e50708c..6317186 100644 --- a/cosmosutils/binary_test.go +++ b/cosmosutils/binary_test.go @@ -218,6 +218,116 @@ func TestGetLatestVersionFromReleases(t *testing.T) { } } +func TestSelectCompatibleReleaseForVersion(t *testing.T) { + currentOS, currentArch, err := getOSArch() + if err != nil { + t.Fatalf("Failed to get OS/arch: %v", err) + } + + assetURL := func(version string) string { + return fmt.Sprintf("example.com/initia_%s_%s_%s.tar.gz", version, currentOS, currentArch) + } + + tests := []struct { + name string + releases []BinaryRelease + targetVersion string + expectedTag string + expectedURL string + expectedErrStr string + }{ + { + name: "uses exact matching release when available", + targetVersion: "v1.3.1", + releases: []BinaryRelease{ + { + TagName: "v1.3.1", + Assets: []struct { + BrowserDownloadURL string `json:"browser_download_url"` + }{ + {BrowserDownloadURL: assetURL("v1.3.1")}, + }, + }, + }, + expectedTag: "v1.3.1", + expectedURL: assetURL("v1.3.1"), + }, + { + name: "falls back to highest patch in same minor series", + targetVersion: "v1.4.1", + releases: []BinaryRelease{ + { + TagName: "v1.3.9", + Assets: []struct { + BrowserDownloadURL string `json:"browser_download_url"` + }{ + {BrowserDownloadURL: assetURL("v1.3.9")}, + }, + }, + { + TagName: "v1.4.0", + Assets: []struct { + BrowserDownloadURL string `json:"browser_download_url"` + }{ + {BrowserDownloadURL: assetURL("v1.4.0")}, + }, + }, + { + TagName: "v1.4.2", + Assets: []struct { + BrowserDownloadURL string `json:"browser_download_url"` + }{ + {BrowserDownloadURL: assetURL("v1.4.2")}, + }, + }, + }, + expectedTag: "v1.4.2", + expectedURL: assetURL("v1.4.2"), + }, + { + name: "fails when no compatible downloadable release exists", + targetVersion: "v1.4.1", + releases: []BinaryRelease{ + { + TagName: "v1.3.9", + Assets: []struct { + BrowserDownloadURL string `json:"browser_download_url"` + }{ + {BrowserDownloadURL: assetURL("v1.3.9")}, + }, + }, + }, + expectedErrStr: "no compatible downloadable release found for chain version v1.4.1", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tag, url, err := selectCompatibleReleaseForVersion(tt.releases, tt.targetVersion) + + if tt.expectedErrStr != "" { + if err == nil { + t.Fatalf("expected error containing %q, got nil", tt.expectedErrStr) + } + if !strings.Contains(err.Error(), tt.expectedErrStr) { + t.Fatalf("expected error containing %q, got %q", tt.expectedErrStr, err.Error()) + } + return + } + + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if tag != tt.expectedTag { + t.Fatalf("expected tag %q, got %q", tt.expectedTag, tag) + } + if url != tt.expectedURL { + t.Fatalf("expected URL %q, got %q", tt.expectedURL, url) + } + }) + } +} + func TestNormalizeVersion(t *testing.T) { tests := []struct { name string From 6d1519a4e7e537996567dc0a0410f6369b5323dd Mon Sep 17 00:00:00 2001 From: Manuel Alessandro Collazo Date: Thu, 2 Apr 2026 11:08:29 +0700 Subject: [PATCH 2/4] fix: remove dead initia binary helper --- Makefile | 2 +- cosmosutils/binary.go | 23 ----------------------- 2 files changed, 1 insertion(+), 24 deletions(-) diff --git a/Makefile b/Makefile index e1833ca..7d92003 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ GO_SYSTEM_VERSION := $(shell go version | cut -c 14- | cut -d' ' -f1 | cut -d'.' REQUIRE_GO_VERSION := $(GO_VERSION) # Project version -WEAVE_VERSION := $(shell git describe --tags) +WEAVE_VERSION := $(shell git describe --tags 2>/dev/null || git rev-parse --short HEAD 2>/dev/null || echo dev) # Build directory BUILDDIR ?= $(CURDIR)/build diff --git a/cosmosutils/binary.go b/cosmosutils/binary.go index 48b0a19..aea0706 100644 --- a/cosmosutils/binary.go +++ b/cosmosutils/binary.go @@ -603,29 +603,6 @@ func GetInitiaBinaryUrlFromLcd(httpClient *client.HTTPClient, rest string) (stri return selectedVersion, url, nil } -func getBinaryURL(version string) (string, error) { - goos := runtime.GOOS - goarch := runtime.GOARCH - - switch goos { - case "darwin": - switch goarch { - case "amd64": - return fmt.Sprintf("https://github.com/initia-labs/initia/releases/download/%s/initia_%s_Darwin_x86_64.tar.gz", version, version), nil - case "arm64": - return fmt.Sprintf("https://github.com/initia-labs/initia/releases/download/%s/initia_%s_Darwin_aarch64.tar.gz", version, version), nil - } - case "linux": - switch goarch { - case "amd64": - return fmt.Sprintf("https://github.com/initia-labs/initia/releases/download/%s/initia_%s_Linux_x86_64.tar.gz", version, version), nil - case "arm64": - return fmt.Sprintf("https://github.com/initia-labs/initia/releases/download/%s/initia_%s_Linux_aarch64.tar.gz", version, version), nil - } - } - return "", fmt.Errorf("unsupported OS or architecture: %v %v", goos, goarch) -} - func GetInitiaBinaryPath(version string) (string, error) { if strings.Contains(version, "@") { parts := strings.Split(version, "@") From 5abf0d45a456828cd32851db1068eac8f3ce7d68 Mon Sep 17 00:00:00 2001 From: Manuel Alessandro Collazo Date: Thu, 2 Apr 2026 12:00:21 +0700 Subject: [PATCH 3/4] fix: use semver fallback for build version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7d92003..bd8fa66 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ GO_SYSTEM_VERSION := $(shell go version | cut -c 14- | cut -d' ' -f1 | cut -d'.' REQUIRE_GO_VERSION := $(GO_VERSION) # Project version -WEAVE_VERSION := $(shell git describe --tags 2>/dev/null || git rev-parse --short HEAD 2>/dev/null || echo dev) +WEAVE_VERSION := $(shell git describe --tags 2>/dev/null || echo v0.0.0-dev) # Build directory BUILDDIR ?= $(CURDIR)/build From e6fa251ee7722acdfe732da2144b6b2259522bfa Mon Sep 17 00:00:00 2001 From: Manuel Alessandro Collazo Date: Thu, 2 Apr 2026 12:02:41 +0700 Subject: [PATCH 4/4] fix: request more GitHub releases per page --- cosmosutils/binary.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cosmosutils/binary.go b/cosmosutils/binary.go index aea0706..db0d296 100644 --- a/cosmosutils/binary.go +++ b/cosmosutils/binary.go @@ -70,7 +70,7 @@ func filterPreReleases(releases []BinaryRelease) []BinaryRelease { func fetchReleases(url string) ([]BinaryRelease, error) { httpClient := client.NewHTTPClient() var releases []BinaryRelease - _, err := httpClient.Get(url, "", nil, &releases) + _, err := httpClient.Get(url, "", map[string]string{"per_page": "100"}, &releases) if err != nil { return nil, fmt.Errorf("failed to fetch releases: %v", err) }