code.vegaprotocol.io/vega@v0.79.0/libs/version/version.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package version 17 18 import ( 19 "fmt" 20 "strings" 21 22 "github.com/blang/semver/v4" 23 ) 24 25 // ReleasesGetter return the list of releases as semantic version strings. 26 type ReleasesGetter func() ([]*Version, error) 27 28 // IsUnreleased tells if the version in parameter is an unreleased version or 29 // not. An unreleased version is a development version from the semantic 30 // versioning point of view. 31 // This doesn't probe GitHub for its metadata on the version, and this is 32 // intended. A release flagged as a pre-release in GitHub is just to mark mainnet 33 // incompatibility. 34 func IsUnreleased(version string) bool { 35 v, err := NewVersionFromString(version) 36 if err != nil { 37 // unsupported version, considered unreleased 38 return true 39 } 40 41 return !v.IsReleased 42 } 43 44 // Check returns a newer version, or an error or nil for both if no error 45 // happened, and no updates are needed. 46 func Check(releasesGetterFn ReleasesGetter, currentRelease string) (*semver.Version, error) { 47 currentVersion, err := NewVersionFromString(currentRelease) 48 if err != nil { 49 return nil, fmt.Errorf("couldn't extract version from release: %w", err) 50 } 51 latestVersion := currentVersion 52 53 releases, err := releasesGetterFn() 54 if err != nil { 55 return nil, fmt.Errorf("couldn't get releases: %w", err) 56 } 57 58 var updateAvailable bool 59 for _, newVersion := range releases { 60 if shouldUpdate(latestVersion, newVersion) { 61 updateAvailable = true 62 latestVersion = newVersion 63 } 64 } 65 66 if !updateAvailable { 67 return nil, nil 68 } 69 70 return latestVersion.Version, nil 71 } 72 73 func shouldUpdate(latestVersion *Version, newVersion *Version) bool { 74 if newVersion.IsDraft { 75 return false 76 } 77 78 if latestVersion.IsReleased && !newVersion.IsReleased { 79 return false 80 } 81 82 if latestVersion.IsDevelopment && nonDevelopmentVersionAvailable(latestVersion, newVersion) { 83 return true 84 } 85 86 return newVersion.Version.GT(*latestVersion.Version) 87 } 88 89 // nonDevelopmentVersionAvailable verifies if the compared version is the 90 // non-development equivalent of the latest version. 91 // For example, 0.9.0-pre1 is the non-development version of 0.9.0-pre1+dev. 92 // In semantic versioning, we don't compare the `build` annotation, so verifying 93 // equality between 0.9.0-pre1 and 0.9.0-pre1+dev results in comparing: 94 // 95 // 0.9.0-pre1 <> 0.9.0-pre1 96 // 97 // So if it's equal, it means we have a. 98 func nonDevelopmentVersionAvailable(latestVersion *Version, comparedVersion *Version) bool { 99 return comparedVersion.Version.EQ(*latestVersion.Version) 100 } 101 102 // NewVersionFromString creates a Version and set the appropriate flags on it 103 // based on the segments that compose the version. 104 func NewVersionFromString(release string) (*Version, error) { 105 v, err := semver.New(strings.TrimPrefix(release, "v")) 106 if err != nil { 107 return nil, err 108 } 109 110 version := &Version{ 111 Version: v, 112 } 113 114 for _, build := range v.Build { 115 if build == "dev" { 116 version.IsDevelopment = true 117 } 118 } 119 120 version.IsPreReleased = len(v.Pre) != 0 121 122 version.IsReleased = !version.IsDevelopment && !version.IsPreReleased && !version.IsDraft 123 124 return version, nil 125 } 126 127 type Version struct { 128 Version *semver.Version 129 IsDraft bool 130 IsDevelopment bool 131 IsPreReleased bool 132 IsReleased bool 133 }