Fix #135
This commit is contained in:
58
internal/version/github.go
Normal file
58
internal/version/github.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package version
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
type githubRelease struct {
|
||||
TagName string `json:"tag_name"`
|
||||
Name string `json:"name"`
|
||||
Prerelease bool `json:"prerelease"`
|
||||
PublishedAt time.Time `json:"published_at"`
|
||||
}
|
||||
|
||||
type githubCommit struct {
|
||||
Sha string `json:"sha"`
|
||||
Commit struct {
|
||||
Committer struct {
|
||||
Date time.Time `json:"date"`
|
||||
} `json:"committer"`
|
||||
}
|
||||
}
|
||||
|
||||
func getGithubReleases(client *http.Client) (releases []githubRelease, err error) {
|
||||
const url = "https://api.github.com/repos/qdm12/gluetun/releases"
|
||||
response, err := client.Get(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
b, err := ioutil.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := json.Unmarshal(b, &releases); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return releases, nil
|
||||
}
|
||||
|
||||
func getGithubCommits(client *http.Client) (commits []githubCommit, err error) {
|
||||
const url = "https://api.github.com/repos/qdm12/gluetun/commits"
|
||||
response, err := client.Get(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
b, err := ioutil.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := json.Unmarshal(b, &commits); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return commits, nil
|
||||
}
|
||||
88
internal/version/version.go
Normal file
88
internal/version/version.go
Normal file
@@ -0,0 +1,88 @@
|
||||
package version
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// GetMessage returns a message for the user describing if there is a newer version
|
||||
// available. It should only be called once the tunnel is established.
|
||||
func GetMessage(version, commitShort string, client *http.Client) (message string, err error) {
|
||||
if version == "latest" {
|
||||
// Find # of commits between current commit and latest commit
|
||||
commitsSince, err := getCommitsSince(client, commitShort)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("cannot get version information: %w", err)
|
||||
} else if commitsSince == 0 {
|
||||
return fmt.Sprintf("You are running on the bleeding edge of %s!", version), nil
|
||||
}
|
||||
commits := "commits"
|
||||
if commitsSince == 1 {
|
||||
commits = "commit"
|
||||
}
|
||||
return fmt.Sprintf("You are running %d %s behind the most recent %s", commitsSince, commits, version), nil
|
||||
}
|
||||
tagName, name, releaseTime, err := getLatestRelease(client)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("cannot get version information: %w", err)
|
||||
}
|
||||
if tagName == version {
|
||||
return fmt.Sprintf("You are running the latest release %s", version), nil
|
||||
}
|
||||
timeSinceRelease := formatDuration(time.Since(releaseTime))
|
||||
return fmt.Sprintf("There is a new release %s (%s) created %s ago",
|
||||
tagName, name, timeSinceRelease),
|
||||
nil
|
||||
}
|
||||
|
||||
func formatDuration(duration time.Duration) string {
|
||||
switch {
|
||||
case duration < time.Minute:
|
||||
seconds := int(duration.Round(time.Second).Seconds())
|
||||
if seconds < 2 {
|
||||
return fmt.Sprintf("%d second", seconds)
|
||||
}
|
||||
return fmt.Sprintf("%d seconds", seconds)
|
||||
case duration <= time.Hour:
|
||||
minutes := int(duration.Round(time.Minute).Minutes())
|
||||
if minutes == 1 {
|
||||
return "1 minute"
|
||||
}
|
||||
return fmt.Sprintf("%d minutes", minutes)
|
||||
case duration < 48*time.Hour:
|
||||
hours := int(duration.Truncate(time.Hour).Hours())
|
||||
return fmt.Sprintf("%d hours", hours)
|
||||
default:
|
||||
days := int(duration.Truncate(time.Hour).Hours() / 24)
|
||||
return fmt.Sprintf("%d days", days)
|
||||
}
|
||||
}
|
||||
|
||||
func getLatestRelease(client *http.Client) (tagName, name string, time time.Time, err error) {
|
||||
releases, err := getGithubReleases(client)
|
||||
if err != nil {
|
||||
return "", "", time, err
|
||||
}
|
||||
for _, release := range releases {
|
||||
if release.Prerelease {
|
||||
continue
|
||||
}
|
||||
return release.TagName, release.Name, release.PublishedAt, nil
|
||||
}
|
||||
return "", "", time, fmt.Errorf("no releases found")
|
||||
}
|
||||
|
||||
func getCommitsSince(client *http.Client, commitShort string) (n int, err error) {
|
||||
commits, err := getGithubCommits(client)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
for i := range commits {
|
||||
if commits[i].Sha[:7] == commitShort {
|
||||
return n, nil
|
||||
}
|
||||
n++
|
||||
}
|
||||
return 0, fmt.Errorf("no commit matching %q was found", commitShort)
|
||||
}
|
||||
64
internal/version/version_test.go
Normal file
64
internal/version/version_test.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package version
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_formatDuration(t *testing.T) {
|
||||
t.Parallel()
|
||||
testCases := map[string]struct {
|
||||
duration time.Duration
|
||||
s string
|
||||
}{
|
||||
"zero": {
|
||||
s: "0 second",
|
||||
},
|
||||
"one second": {
|
||||
duration: time.Second,
|
||||
s: "1 second",
|
||||
},
|
||||
"59 seconds": {
|
||||
duration: 59 * time.Second,
|
||||
s: "59 seconds",
|
||||
},
|
||||
"1 minute": {
|
||||
duration: time.Minute,
|
||||
s: "1 minute",
|
||||
},
|
||||
"2 minutes": {
|
||||
duration: 2 * time.Minute,
|
||||
s: "2 minutes",
|
||||
},
|
||||
"1 hour": {
|
||||
duration: time.Hour,
|
||||
s: "60 minutes",
|
||||
},
|
||||
"2 hours": {
|
||||
duration: 2 * time.Hour,
|
||||
s: "2 hours",
|
||||
},
|
||||
"26 hours": {
|
||||
duration: 26 * time.Hour,
|
||||
s: "26 hours",
|
||||
},
|
||||
"28 hours": {
|
||||
duration: 28 * time.Hour,
|
||||
s: "28 hours",
|
||||
},
|
||||
"55 hours": {
|
||||
duration: 55 * time.Hour,
|
||||
s: "2 days",
|
||||
},
|
||||
}
|
||||
for name, testCase := range testCases {
|
||||
testCase := testCase
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
s := formatDuration(testCase.duration)
|
||||
assert.Equal(t, testCase.s, s)
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user