-
Notifications
You must be signed in to change notification settings - Fork 2
/
version.go
122 lines (106 loc) · 3.19 KB
/
version.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package engine
import (
"encoding/json"
"fmt"
"gatehill.io/imposter/prefs"
"github.com/coreos/go-semver/semver"
"io"
"net/http"
"strings"
"time"
)
const latestReleaseApi = "https://api.github.com/repos/outofcoffee/imposter/releases/latest"
const checkThresholdSeconds = 86_400
func ResolveLatestToVersion(allowCached bool) (string, error) {
logger.Tracef("resolving latest version (cache allowed: %v)", allowCached)
now := time.Now().Unix()
var latest string
if allowCached {
latest = loadCached(now)
}
if latest == "" {
lookup, err := lookupLatest(now, allowCached)
if err != nil {
return "", err
}
latest = lookup
}
logger.Tracef("resolved latest version: %s", latest)
return latest, nil
}
func GetHighestVersion(engines []EngineMetadata) string {
var highest *semver.Version
for _, engine := range engines {
v, err := semver.NewVersion(engine.Version)
if err != nil {
continue
}
if highest == nil || highest.LessThan(*v) {
highest = v
}
}
if highest != nil {
return highest.String()
}
return ""
}
func loadCached(now int64) string {
var latest string
p := getVersionPrefs()
lastCheck, _ := p.ReadPropertyInt("last_version_check")
if now-int64(lastCheck) < checkThresholdSeconds {
latest, _ = p.ReadPropertyString("latest")
}
logger.Tracef("latest version cached value: %s", latest)
return latest
}
func lookupLatest(now int64, allowFallbackToCached bool) (string, error) {
latest, err := fetchLatestFromApi()
if err != nil {
if !allowFallbackToCached {
return "", fmt.Errorf("failed to fetch latest version from API: %s", err)
}
logger.Warnf("failed to fetch latest version from API (%s) - checking cache", err)
latest = loadCached(now)
if latest == "" {
return "", fmt.Errorf("failed to resolve latest version (%s) and no cached version found", err)
} else {
// don't persist the cached version back to the prefs store
return latest, nil
}
}
p := getVersionPrefs()
err = p.WriteProperty("latest", latest)
if err != nil {
logger.Warnf("failed to record latest version: %s", err)
}
err = p.WriteProperty("last_version_check", now)
if err != nil {
logger.Warnf("failed to record last version check time: %s", err)
}
return latest, nil
}
func getVersionPrefs() prefs.Prefs {
return prefs.Load("prefs.json")
}
func fetchLatestFromApi() (string, error) {
logger.Tracef("fetching latest version from: %s", latestReleaseApi)
resp, err := http.Get(latestReleaseApi)
if err != nil {
return "", fmt.Errorf("failed to determine latest version from %s: %s", latestReleaseApi, err)
}
if resp.StatusCode < 200 || resp.StatusCode > 299 {
return "", fmt.Errorf("failed to determine latest version from %s - status code: %d", latestReleaseApi, resp.StatusCode)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("failed to determine latest version from %s - cannot read response body: %s", latestReleaseApi, err)
}
var data map[string]interface{}
err = json.Unmarshal(body, &data)
if err != nil {
return "", fmt.Errorf("failed to determine latest version from %s - cannot unmarshall response body: %s", latestReleaseApi, err)
}
tagName := data["tag_name"].(string)
return strings.TrimPrefix(tagName, "v"), nil
}