@@ -6,18 +6,37 @@ package version
6
6
7
7
import (
8
8
"context"
9
+ "encoding/json"
10
+ "fmt"
11
+ "os"
12
+ "path/filepath"
13
+ "strings"
14
+ "time"
9
15
10
16
"github.com/Masterminds/semver/v3"
11
17
18
+ "github.com/elastic/elastic-package/internal/configuration/locations"
19
+ "github.com/elastic/elastic-package/internal/environment"
12
20
"github.com/elastic/elastic-package/internal/github"
13
21
"github.com/elastic/elastic-package/internal/logger"
14
22
)
15
23
16
24
const (
17
25
repositoryOwner = "elastic"
18
26
repositoryName = "elastic-package"
27
+
28
+ latestVersionFile = "latestVersion"
29
+ defaultCacheDuration = 30 * time .Minute
19
30
)
20
31
32
+ var checkUpdatedDisabledEnv = environment .WithElasticPackagePrefix ("CHECK_UPDATE_DISABLED" )
33
+
34
+ type versionLatest struct {
35
+ TagName string `json:"tag"`
36
+ HtmlURL string `json:"html_url"`
37
+ Timestamp time.Time `json:"timestamp"`
38
+ }
39
+
21
40
// CheckUpdate function checks using Github Release API if newer version is available.
22
41
func CheckUpdate () {
23
42
if Tag == "" {
@@ -26,16 +45,39 @@ func CheckUpdate() {
26
45
return
27
46
}
28
47
29
- githubClient := github .UnauthorizedClient ()
30
- release , _ , err := githubClient .Repositories .GetLatestRelease (context .TODO (), repositoryOwner , repositoryName )
31
- if err != nil {
32
- logger .Debugf ("Error: can't check latest release, %v" , err )
48
+ v , ok := os .LookupEnv (checkUpdatedDisabledEnv )
49
+ if ok && strings .ToLower (v ) != "false" {
50
+ logger .Debug ("Disabled checking updates" )
33
51
return
34
52
}
35
53
36
- if release .TagName == nil || * release .TagName == "" {
37
- logger .Debugf ("Error: release tag is empty" )
38
- return
54
+ expired := true
55
+ latestVersion , err := loadCacheLatestVersion ()
56
+ switch {
57
+ case err != nil :
58
+ logger .Debug ("failed to load latest version from cache: %v" , err )
59
+ default :
60
+ expired = checkCachedLatestVersion (latestVersion , defaultCacheDuration )
61
+ }
62
+
63
+ var release * versionLatest
64
+ switch {
65
+ case ! expired :
66
+ logger .Debugf ("latest version (cached): %s" , latestVersion )
67
+ release = latestVersion
68
+ default :
69
+ logger .Debugf ("checking latest release in Github" )
70
+ githubClient := github .UnauthorizedClient ()
71
+ githubRelease , err := githubClient .LatestRelease (context .TODO (), repositoryOwner , repositoryName )
72
+ if err != nil {
73
+ logger .Debugf ("Error: %v" , err )
74
+ return
75
+ }
76
+ release = & versionLatest {
77
+ TagName : * githubRelease .TagName ,
78
+ HtmlURL : * githubRelease .HTMLURL ,
79
+ Timestamp : time .Now (),
80
+ }
39
81
}
40
82
41
83
currentVersion , err := semver .NewVersion (Tag [1 :]) // strip "v" prefix
@@ -44,13 +86,70 @@ func CheckUpdate() {
44
86
return
45
87
}
46
88
47
- releaseVersion , err := semver .NewVersion (( * release .TagName ) [1 :]) // strip "v" prefix
89
+ releaseVersion , err := semver .NewVersion (release .TagName [1 :]) // strip "v" prefix
48
90
if err != nil {
49
91
logger .Debugf ("Error: can't parse current version tag, %v" , err )
50
92
return
51
93
}
52
94
53
95
if currentVersion .LessThan (releaseVersion ) {
54
- logger .Infof ("New version is available - %s. Download from: %s" , * release .TagName , * release .HTMLURL )
96
+ logger .Infof ("New version is available - %s. Download from: %s" , release .TagName , release .HtmlURL )
97
+ }
98
+
99
+ // if version cached is not expired, do not write contents into file
100
+ if ! expired {
101
+ return
102
+ }
103
+
104
+ if err := writeLatestReleaseToCache (release ); err != nil {
105
+ logger .Debugf ("failed to write latest versoin to cache file: %v" , err )
106
+ }
107
+ }
108
+
109
+ func writeLatestReleaseToCache (release * versionLatest ) error {
110
+ elasticPackagePath , err := locations .NewLocationManager ()
111
+ if err != nil {
112
+ return fmt .Errorf ("failed locating the configuration directory: %w" , err )
113
+ }
114
+
115
+ latestVersionPath := filepath .Join (elasticPackagePath .RootDir (), latestVersionFile )
116
+
117
+ contents , err := json .Marshal (release )
118
+ if err != nil {
119
+ return fmt .Errorf ("failed to encode file %s: %w" , latestVersionPath , err )
120
+ }
121
+ err = os .WriteFile (latestVersionPath , contents , 0644 )
122
+ if err != nil {
123
+ return fmt .Errorf ("writing file failed (path: %s): %w" , latestVersionPath , err )
124
+ }
125
+
126
+ return nil
127
+ }
128
+
129
+ func loadCacheLatestVersion () (* versionLatest , error ) {
130
+ elasticPackagePath , err := locations .NewLocationManager ()
131
+ if err != nil {
132
+ return nil , fmt .Errorf ("failed locating the configuration directory: %w" , err )
55
133
}
134
+
135
+ latestVersionPath := filepath .Join (elasticPackagePath .RootDir (), latestVersionFile )
136
+ contents , err := os .ReadFile (latestVersionPath )
137
+ if err != nil {
138
+ logger .Warnf ("reading version file failed: %w" , err .Error ())
139
+ return nil , fmt .Errorf ("reading version file failed: %w" , err )
140
+ }
141
+
142
+ var infoVersion versionLatest
143
+ err = json .Unmarshal (contents , & infoVersion )
144
+ if err != nil {
145
+ return nil , fmt .Errorf ("failed to decode file %s: %w" , latestVersionPath , err )
146
+ }
147
+
148
+ return & infoVersion , nil
149
+ }
150
+
151
+ func checkCachedLatestVersion (latest * versionLatest , expiration time.Duration ) bool {
152
+ exprirationTime := time .Now ().Add (- expiration )
153
+
154
+ return latest .Timestamp .Before (exprirationTime )
56
155
}
0 commit comments