diff --git a/assets/index.html b/assets/index.html index bfbbe7f1c..338a9ccbf 100644 --- a/assets/index.html +++ b/assets/index.html @@ -58,8 +58,6 @@
- - + +
@@ -113,7 +128,7 @@
-
+
diff --git a/assets/js/app.js b/assets/js/app.js index d6da99a97..a7147beea 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -181,8 +181,14 @@ Vue.component('version', { data: function () { return { state: store.state, + notesShown: false, }; }, + mounted: function () { + $(this.$refs.notes) + .on('show.bs.collapse', function () { this.notesShown = true; }.bind(this)) + .on('hide.bs.collapse', function () { this.notesShown = false; }.bind(this)); + }, watch: { "state.availableVersion": function () { if (this.installed != "<<.Version>>" && // go template parsed? diff --git a/go.mod b/go.mod index 80fa724e3..468e85dff 100644 --- a/go.mod +++ b/go.mod @@ -11,11 +11,13 @@ require ( github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible github.com/godbus/dbus/v5 v5.0.3 github.com/golang/mock v1.4.3 + github.com/google/go-github/v32 v32.1.0 github.com/gorilla/handlers v1.4.2 github.com/gorilla/mux v1.7.4 github.com/gorilla/websocket v1.4.2 github.com/gregdel/pushover v0.0.0-20200416074932-c8ad547caed4 github.com/grid-x/modbus v0.0.0-20200704184817-73c05928caa1 + github.com/hashicorp/go-version v1.2.1 github.com/influxdata/influxdb-client-go v1.4.0 github.com/itchyny/gojq v0.11.0 github.com/joeshaw/carwings v0.0.0-20191118152321-61b46581307a @@ -32,6 +34,7 @@ require ( github.com/spf13/viper v1.7.0 github.com/tcnksm/go-latest v0.0.0-20170313132115-e3007ae9052e github.com/volkszaehler/mbmd v0.0.0-20200717102329-c4d965bd1eac + github.com/yuin/goldmark v1.1.32 golang.org/x/net v0.0.0-20200707034311-ab3426394381 golang.org/x/tools v0.0.0-20200717024301-6ddee64345a6 gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c diff --git a/go.sum b/go.sum index e7d85aaf5..e6dbb8dae 100644 --- a/go.sum +++ b/go.sum @@ -108,6 +108,8 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= +github.com/google/go-github/v32 v32.1.0 h1:GWkQOdXqviCPx7Q7Fj+KyPoGm4SwHRh8rheoPhd27II= +github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI= github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= @@ -349,6 +351,7 @@ github.com/volkszaehler/mbmd v0.0.0-20200717102329-c4d965bd1eac/go.mod h1:sldLyJ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32 h1:5tjfNdR2ki3yYQ842+eX2sQHeiwpKJ0RnHO4IYOc4V8= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= diff --git a/server/assets.go b/server/assets.go index 376e773d2..8584865c1 100644 --- a/server/assets.go +++ b/server/assets.go @@ -3561,144 +3561,147 @@ oJE6K0E084u3ea7ne0X73qsc2P2KOB+ngKecxITsMAgTVJfqMwAA//+21HeD5gEAAA== "/index.html": { name: "index.html", local: "assets/index.html", - size: 19915, + size: 20467, modtime: 1566640112, compressed: ` -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 +AAA= `, }, "/js/app.js": { name: "app.js", local: "assets/js/app.js", - size: 8796, + size: 9041, modtime: 1566640112, compressed: ` -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 -l6X/BQAA//9E4YQ5XCIAAA== +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 +AAAA//9Hvxx7USMAAA== `, }, diff --git a/server/socket.go b/server/socket.go index be4e377af..b384854ab 100644 --- a/server/socket.go +++ b/server/socket.go @@ -1,6 +1,7 @@ package server import ( + "encoding/json" "fmt" "net/http" "strings" @@ -92,12 +93,13 @@ func encode(v interface{}) (string, error) { case time.Duration: // must be before stringer to convert to seconds instead of string s = fmt.Sprintf("%d", int64(val.Seconds())) - case fmt.Stringer, string: - s = fmt.Sprintf("\"%s\"", val) case float64: s = fmt.Sprintf("%.3f", val) default: - s = fmt.Sprintf("%v", val) + // s = fmt.Sprintf("%v", val) + if b, err := json.Marshal(v); err == nil { + s = string(b) + } } return s, nil } diff --git a/server/updater/updater.go b/server/updater/updater.go index e53d8afad..172e4d255 100644 --- a/server/updater/updater.go +++ b/server/updater/updater.go @@ -1,11 +1,20 @@ package updater import ( + "bytes" + "context" + "fmt" + "strings" "time" "github.com/andig/evcc/server" "github.com/andig/evcc/util" + "github.com/google/go-github/v32/github" + "github.com/hashicorp/go-version" latest "github.com/tcnksm/go-latest" + "github.com/yuin/goldmark" + "github.com/yuin/goldmark/extension" + "github.com/yuin/goldmark/renderer/html" ) var instance *updater @@ -15,6 +24,17 @@ type updater struct { cache chan<- util.Param } +func tag2semver(tag string) string { + if strings.Count(tag, ".") < 2 { + tag += ".0" + } + return tag +} + +func semver2tag(ver string) string { + return strings.TrimSuffix(ver, ".0") +} + // Run regularly checks version func Run(log *util.Logger, cache chan<- util.Param) { instance = &updater{ @@ -31,19 +51,85 @@ func Run(log *util.Logger, cache chan<- util.Param) { // checkVersion validates if updates are available func (u *updater) checkVersion() { githubTag := &latest.GithubTag{ - Owner: "andig", - Repository: "evcc", + Owner: server.Owner, + Repository: server.Repository, } - if res, err := latest.Check(githubTag, server.Version); err == nil { + installed := tag2semver(server.Version) + if res, err := latest.Check(githubTag, installed); err == nil { + tag := semver2tag(res.Current) if res.Outdated { - u.log.INFO.Printf("new version available - please upgrade to %s", res.Current) + u.log.INFO.Printf("new version available - please upgrade to %s", tag) } + u.cache <- util.Param{ Key: "availableVersion", - Val: res.Current, + Val: tag, } + + u.fetchReleaseNotes(res.Current) } else { u.log.ERROR.Println("version check failed:", err) } } + +// fetchReleaseNotes retrieves release notes up to semver and sends to client +func (u *updater) fetchReleaseNotes(to string) { + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + if notes, err := releaseNotes(ctx, tag2semver(server.Version), to); err == nil { + u.cache <- util.Param{ + Key: "releaseNotes", + Val: notes, + } + } else { + u.log.WARN.Printf("couldn't download release notes: %v", err) + } +} + +// releaseNotes returns github release notes for the (from,to] semver interval +func releaseNotes(ctx context.Context, from, to string) (rendered string, err error) { + var fromVersion, toVersion *version.Version + if fromVersion, err = version.NewVersion(from); err != nil { + return + } + if toVersion, err = version.NewVersion(to); err != nil { + return + } + + client := github.NewClient(nil) + releases, _, err := client.Repositories.ListReleases(ctx, server.Owner, server.Repository, nil) + if err != nil { + return + } + + notes := bytes.NewBuffer([]byte{}) + gm := goldmark.New( + goldmark.WithExtensions(extension.GFM), + goldmark.WithRendererOptions(html.WithHardWraps()), + ) + + for _, rel := range releases { + tag := *rel.TagName + + var ver *version.Version + if ver, err = version.NewVersion(tag2semver(tag)); err != nil { + return + } + + if ver.GreaterThan(fromVersion) && ver.LessThanOrEqual(toVersion) { + body := strings.TrimSpace(rel.GetBody()) + if body == "" { + continue + } + + notes.WriteString(fmt.Sprintf("

%s

\n", tag)) + if err = gm.Convert([]byte(body), notes); err != nil { + return + } + } + } + + return notes.String(), nil +} diff --git a/server/version.go b/server/version.go index 45605ebff..b8617d805 100644 --- a/server/version.go +++ b/server/version.go @@ -1,8 +1,15 @@ package server var ( + // Repository name + Repository = "evcc" + + // Owner of repository + Owner = "andig" + // Version of executable Version = "0.0.1-alpha" + // Commit of executable Commit = "HEAD" )