Skip to content

Commit

Permalink
Check for new releases (#463)
Browse files Browse the repository at this point in the history
  • Loading branch information
jbygdell authored Nov 12, 2024
2 parents 18aee45 + d0b91d3 commit e4ef2a3
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 3 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ require (
github.com/aws/aws-sdk-go v1.55.5
github.com/dustin/go-humanize v1.0.1
github.com/golang-jwt/jwt v3.2.2+incompatible
github.com/hashicorp/go-version v1.7.0
github.com/inhies/go-bytesize v0.0.0-20210819104631-275770b98743
github.com/johannesboyne/gofakes3 v0.0.0-20220627085814-c3ac35da23b2
github.com/manifoldco/promptui v0.9.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/inhies/go-bytesize v0.0.0-20210819104631-275770b98743 h1:X3Xxno5Ji8idrNiUoFc7QyXpqhSYlDRYQmc7mlpMBzU=
github.com/inhies/go-bytesize v0.0.0-20210819104631-275770b98743/go.mod h1:KrtyD5PFj++GKkFS/7/RRrfnRhAMGQwy75GLCHWrCNs=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
Expand Down
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
log "github.com/sirupsen/logrus"
)

var Version = "development"
var Version = "0-development"

var Usage = `USAGE: %s <command> [command-args]
Expand Down
84 changes: 84 additions & 0 deletions version/version.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
package version

import (
"encoding/json"
"errors"
"flag"
"fmt"
"io"
"net/http"
"os"
"time"

"github.com/hashicorp/go-version"
)

// Help text and command line flags.
Expand All @@ -26,11 +33,88 @@ var ArgHelp = `
// main program help
var Args = flag.NewFlagSet("version", flag.ExitOnError)

type ghResponse struct {
Name string `json:"name"`
Published string `json:"published_at"`
URL string `json:"html_url"`
}

// this is just so we can mock bad internet connection
var url = "https://api.github.com/repos/NBISweden/sda-cli/releases/latest"
var timeout = 30 * time.Second

// Returns the version of the sda-cli tool.
func Version(ver string) error {
if len(Args.Args()) > 0 {
return errors.New("version does not take any arguments")
}

req, err := http.NewRequest(http.MethodGet, url, http.NoBody)
if err != nil {
fmt.Fprintf(os.Stderr, "failed to initiate request")
fmt.Println("sda-cli version: ", ver)

return nil
}
req.Header.Add("X-GitHub-Api-Version", "2022-11-28")
req.Header.Add("Accept", "application/vnd.github+json")

client := &http.Client{Timeout: timeout}
resp, err := client.Do(req)
if err != nil {
fmt.Fprintf(os.Stderr, "failed to fetch releases, reason: %s\n", err.Error())
fmt.Println("sda-cli version: ", ver)

return nil
}
if resp.StatusCode >= 400 {
fmt.Fprintf(os.Stderr, "failed to fetch releases, reason: %s\n", resp.Status)
fmt.Println("sda-cli version: ", ver)

return nil
}
defer resp.Body.Close()

body, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Fprintln(os.Stderr, "failed to read response")
fmt.Println("sda-cli version: ", ver)

return nil
}

ghVersion := ghResponse{}
if err := json.Unmarshal(body, &ghVersion); err != nil {
fmt.Fprintln(os.Stderr, "failed to unmarshal response")
fmt.Println("sda-cli version: ", ver)

return nil
}

appVer, err := version.NewVersion(ver)
if err != nil {
fmt.Fprintln(os.Stderr, "failed to parse app version")
fmt.Println("sda-cli version: ", ver)

return nil
}
ghVer, err := version.NewVersion(ghVersion.Name)
if err != nil {
fmt.Fprintln(os.Stderr, "failed to parse release version")
fmt.Println("sda-cli version: ", ver)

return nil
}

if appVer.LessThan(ghVer) {
pt, _ := time.Parse(time.RFC3339, ghVersion.Published)
fmt.Printf("Newer version of sda-cli is available, %s\n", ghVersion.Name)
fmt.Printf("Published: %s\n", pt.Format(time.DateTime))
fmt.Printf("Download it from here: %s\n", ghVersion.URL)

return nil
}

fmt.Println("sda-cli version: ", ver)

return nil
Expand Down
79 changes: 77 additions & 2 deletions version/version_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
package version

import (
"io"
"net/http"
"net/http/httptest"
"os"
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
Expand All @@ -16,9 +21,79 @@ func TestVersionTestSuite(t *testing.T) {
}

func (suite *VersionTests) TestGetVersion() {
mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(`{"html_url": "https://github.com/NBISweden/sda-cli/releases/tag/v0.1.3","name": "v0.1.3","published_at": "2024-09-19T09:23:33Z"}`))
}))
defer mockServer.Close()
url = mockServer.URL

// get version
err := Version("development")
err := Version("1.0.0")
assert.NoError(suite.T(), err)
}

func (suite *VersionTests) TestGetVersion_newerAvailable() {
mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(`{"html_url": "https://github.com/NBISweden/sda-cli/releases/tag/v0.1.3","name": "v0.1.3","published_at": "2024-09-19T09:23:33Z"}`))
}))
defer mockServer.Close()
url = mockServer.URL

storeStdout := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w

err := Version("0.0.1")
assert.NoError(suite.T(), err)

w.Close()
out, _ := io.ReadAll(r)
os.Stdout = storeStdout

assert.Contains(suite.T(), string(out), "Newer version of sda-cli is available")
}

func (suite *VersionTests) TestGetVersion_badGateway() {
mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusBadGateway)
}))
defer mockServer.Close()
url = mockServer.URL

storeStderr := os.Stderr
r, w, _ := os.Pipe()
os.Stderr = w

err := Version("0.0.3")
assert.NoError(suite.T(), err)

w.Close()
out, _ := io.ReadAll(r)
os.Stderr = storeStderr

assert.Equal(suite.T(), string(out), "failed to fetch releases, reason: 502 Bad Gateway\n")
}

func (suite *VersionTests) TestGetVersion_networkTimeout() {
mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
time.Sleep(20 * time.Millisecond)
w.WriteHeader(http.StatusOK)
}))
defer mockServer.Close()
url = mockServer.URL
timeout = 10 * time.Millisecond

storeStderr := os.Stderr
r, w, _ := os.Pipe()
os.Stderr = w

err := Version("0.0.3")
assert.NoError(suite.T(), err)

w.Close()
out, _ := io.ReadAll(r)
os.Stderr = storeStderr

assert.Contains(suite.T(), string(out), "context deadline exceeded")
}

0 comments on commit e4ef2a3

Please sign in to comment.