From 315cab71fc16b49d23b864a0a34c76981ad8cf2a Mon Sep 17 00:00:00 2001 From: Alper Polat Date: Wed, 21 Feb 2024 23:07:37 +0200 Subject: [PATCH 1/2] Find new versions by parsing json Keeping the current functionality, but just changing how the version numbers are found. Instead of issuing HEAD requests, parse https://go.dev/dl/?mode=json for available versions and compare with what we currently have in the repo. Signed-off-by: Alper Polat --- cmd/builder-bumper/main.go | 96 +++++++++++++++++++++++++++----------- 1 file changed, 69 insertions(+), 27 deletions(-) diff --git a/cmd/builder-bumper/main.go b/cmd/builder-bumper/main.go index aa24f2b..3bc1dc6 100644 --- a/cmd/builder-bumper/main.go +++ b/cmd/builder-bumper/main.go @@ -16,6 +16,7 @@ package main import ( "bufio" + "encoding/json" "flag" "fmt" "io" @@ -46,6 +47,10 @@ type goVersion struct { minor int } +type VersionInfo struct { + Version string `json:"version"` +} + func newGoVersion(v string) *goVersion { c := semver.Canonical("v" + v) if c == "" { @@ -101,6 +106,48 @@ func (g *goVersion) url() string { return fmt.Sprintf("https://dl.google.com/go/go%s.linux-amd64.tar.gz", g.golangVersion()) } +func fetchJSON(url string) ([]byte, error) { + resp, err := http.Get(url) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("unexpected status code: %d", resp.StatusCode) + } + + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + return body, nil +} + +func availableVersions() []goVersion { + + url := "https://go.dev/dl/?mode=json" + + jsonData, err := fetchJSON(url) + if err != nil { + fmt.Println("Error fetching JSON:", err) + } + + var availableVersionsJSON []VersionInfo + var availableVersions []goVersion + if err := json.Unmarshal(jsonData, &availableVersionsJSON); err != nil { + fmt.Println("Error parsing JSON:", err) + } + for i := range availableVersionsJSON { + // replace "go" from a string like "go1.22.0" + availableVersionsJSON[i].Version = strings.Replace(availableVersionsJSON[i].Version, "go", "", 1) + newGoVersion := newGoVersion(availableVersionsJSON[i].Version) + availableVersions = append(availableVersions, *newGoVersion) + } + return availableVersions +} + // getSHA256 returns the SHA256 of the Go archive. func (g *goVersion) getSHA256() (string, error) { resp, err := http.Get(g.url() + ".sha256") @@ -116,40 +163,34 @@ func (g *goVersion) getSHA256() (string, error) { } // getLastMinorVersion returns the last minor version for a given Go version. -func (g *goVersion) getLastMinorVersion() (*goVersion, error) { +// if no new minor version available, it will return the given Go version back. +func (g *goVersion) getLastMinorVersion(availableVersions []goVersion) *goVersion { last := *g - for { - next := last + next := last + // let's check max 40 minor revisions for now before giving up + for next.minor < 40 { next.minor++ - resp, err := http.Head(next.url()) - if err != nil { - return nil, err - } - defer resp.Body.Close() - - if resp.StatusCode/100 != 2 { - return &last, nil + for _, availableVersion := range availableVersions { + if next == availableVersion { + return &next + } } - last = next } + return &last } // getNextMajor returns the next Go major version for a given Go version. // It returns nil if the current version is already the latest. -func (g *goVersion) getNextMajor() *goVersion { +func (g *goVersion) getNextMajor(availableVersions []goVersion) *goVersion { version := newGoVersion(g.Major() + ".0") version.major++ - resp, err := http.Head(version.url()) - if err != nil { - return nil - } - defer resp.Body.Close() - if resp.StatusCode/100 != 2 { - return nil + for _, availableVersion := range availableVersions { + if version.major == availableVersion.major { + return version + } } - - return version + return nil } // getExactVersionFromDir reads the current Go version from a directory. @@ -301,10 +342,8 @@ func updateNextMinor(dir string) (*goVersion, error) { return nil, fmt.Errorf("failed to detect current version of %s: %w", dir, err) } - next, err := current.getLastMinorVersion() - if err != nil { - return nil, err - } + next := current.getLastMinorVersion(availableVersions()) + if next.equal(current) { log.Printf("no version change for Go %s", next.golangVersion()) return nil, nil @@ -374,9 +413,12 @@ func run() error { return fmt.Errorf("Expected 2 versions of Go but got %d\n", len(dirs)) } + // Get list of available versions + availableVersions := availableVersions() + // Check if a new major Go version exists. nexts := make([]*goVersion, 0) - if next := newGoVersion(dirs[1] + ".0").getNextMajor(); next != nil { + if next := newGoVersion(dirs[1] + ".0").getNextMajor(availableVersions); next != nil { log.Printf("found a new major version of Go: %s", next) old, err := getExactVersionFromDir(dirs[0]) if err != nil { From 174763709ba7e3580d0653ea11c7531665afd3d1 Mon Sep 17 00:00:00 2001 From: Alper Polat Date: Thu, 22 Feb 2024 17:52:33 +0200 Subject: [PATCH 2/2] Make the additions simpler `url` is now constant, no extra work for string replacing anymore. Signed-off-by: Alper Polat --- cmd/builder-bumper/main.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/cmd/builder-bumper/main.go b/cmd/builder-bumper/main.go index 3bc1dc6..f1d5631 100644 --- a/cmd/builder-bumper/main.go +++ b/cmd/builder-bumper/main.go @@ -127,7 +127,7 @@ func fetchJSON(url string) ([]byte, error) { func availableVersions() []goVersion { - url := "https://go.dev/dl/?mode=json" + const url = "https://go.dev/dl/?mode=json" jsonData, err := fetchJSON(url) if err != nil { @@ -140,9 +140,8 @@ func availableVersions() []goVersion { fmt.Println("Error parsing JSON:", err) } for i := range availableVersionsJSON { - // replace "go" from a string like "go1.22.0" - availableVersionsJSON[i].Version = strings.Replace(availableVersionsJSON[i].Version, "go", "", 1) - newGoVersion := newGoVersion(availableVersionsJSON[i].Version) + // remove "go" from a string like "go1.22.0" + newGoVersion := newGoVersion(strings.TrimLeft("go", availableVersionsJSON[i].Version)) availableVersions = append(availableVersions, *newGoVersion) } return availableVersions