From 8edda8b446200545b36432b57d00cd1972a5cb7e Mon Sep 17 00:00:00 2001 From: techknowlogick Date: Sat, 16 Oct 2021 02:14:34 -0400 Subject: [PATCH] Add simple update checker to Gitea (#17212) * Add simple update checker to Gitea * update struct and remove comments * fix lint * Update custom/conf/app.example.ini * Update docs/content/doc/advanced/config-cheat-sheet.en-us.md Co-authored-by: delvh * Update custom/conf/app.example.ini Co-authored-by: delvh * Update docs/content/doc/advanced/config-cheat-sheet.en-us.md Co-authored-by: delvh * Update docs/content/doc/advanced/config-cheat-sheet.en-us.md Co-authored-by: Steven <61625851+justusbunsi@users.noreply.github.com> * Update docs/content/doc/advanced/config-cheat-sheet.en-us.md * Update modules/cron/tasks_extended.go Co-authored-by: wxiaoguang * Update custom/conf/app.example.ini Co-authored-by: wxiaoguang * take PR feedback into account and display banner on admin dashboard for alerts * Add more detailed message * placate lint * update per feedback Co-authored-by: delvh Co-authored-by: Steven <61625851+justusbunsi@users.noreply.github.com> Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: wxiaoguang --- custom/conf/app.example.ini | 13 ++ .../doc/advanced/config-cheat-sheet.en-us.md | 13 +- models/migrations/migrations.go | 2 + models/migrations/v199.go | 23 ++++ models/update_checker.go | 121 ++++++++++++++++++ modules/cron/tasks_extended.go | 19 +++ routers/web/admin/admin.go | 2 + templates/admin/dashboard.tmpl | 5 + 8 files changed, 195 insertions(+), 3 deletions(-) create mode 100644 models/migrations/v199.go create mode 100644 models/update_checker.go diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 07ca9f8409986..bdc42480e443e 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -1925,6 +1925,19 @@ PATH = ;SCHEDULE = @every 168h ;OLDER_THAN = 8760h +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Check for new Gitea versions +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;[cron.update_checker] +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;ENABLED = false +;RUN_AT_START = false +;ENABLE_SUCCESS_NOTICE = false +;SCHEDULE = @every 168h +;HTTP_ENDPOINT = https://dl.gitea.io/gitea/version.json + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Git Operation timeout in seconds diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index f02d8cbc37759..251f6bd51a9df 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -23,8 +23,8 @@ or any corresponding location. When installing from a distribution, this will typically be found at `/etc/gitea/conf/app.ini`. The defaults provided here are best-effort (not built automatically). They are -accurately recorded in [app.example.ini](https://github.com/go-gitea/gitea/blob/master/custom/conf/app.example.ini) -(s/master/\). Any string in the format `%(X)s` is a feature powered +accurately recorded in [app.example.ini](https://github.com/go-gitea/gitea/blob/main/custom/conf/app.example.ini) +(s/main/\). Any string in the format `%(X)s` is a feature powered by [ini](https://github.com/go-ini/ini/#recursive-values), for reading values recursively. Values containing `#` or `;` must be quoted using `` ` `` or `"""`. @@ -824,9 +824,16 @@ NB: You must have `DISABLE_ROUTER_LOG` set to `false` for this option to take ef - `ENABLED`: **false**: Enable service. - `RUN_AT_START`: **false**: Run tasks at start up time (if ENABLED). - `NO_SUCCESS_NOTICE`: **false**: Set to true to switch off success notices. -- `SCHEDULE`: **@every 128h**: Cron syntax for scheduling a work, e.g. `@every 128h`. +- `SCHEDULE`: **@every 168h**: Cron syntax to set how often to check. - `OLDER_THAN`: **@every 8760h**: any action older than this expression will be deleted from database, suggest using `8760h` (1 year) because that's the max length of heatmap. +#### Cron - Check for new Gitea versions ('cron.update_checker') +- `ENABLED`: **false**: Enable service. +- `RUN_AT_START`: **false**: Run tasks at start up time (if ENABLED). +- `ENABLE_SUCCESS_NOTICE`: **true**: Set to false to switch off success notices. +- `SCHEDULE`: **@every 168h**: Cron syntax for scheduling a work, e.g. `@every 168h`. +- `HTTP_ENDPOINT`: **https://dl.gitea.io/gitea/version.json**: the endpoint that Gitea will check for newer versions + ## Git (`git`) - `PATH`: **""**: The path of git executable. If empty, Gitea searches through the PATH environment. diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index ef0c071417653..3a41cf88918d3 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -350,6 +350,8 @@ var migrations = []Migration{ NewMigration("Add renamed_branch table", addRenamedBranchTable), // v198 -> v199 NewMigration("Add issue content history table", addTableIssueContentHistory), + // v199 -> v200 + NewMigration("Add remote version table", addRemoteVersionTable), } // GetCurrentDBVersion returns the current db version diff --git a/models/migrations/v199.go b/models/migrations/v199.go new file mode 100644 index 0000000000000..64b21172c103e --- /dev/null +++ b/models/migrations/v199.go @@ -0,0 +1,23 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package migrations + +import ( + "fmt" + + "xorm.io/xorm" +) + +func addRemoteVersionTable(x *xorm.Engine) error { + type RemoteVersion struct { + ID int64 `xorm:"pk autoincr"` + Version string `xorm:"VARCHAR(50)"` + } + + if err := x.Sync2(new(RemoteVersion)); err != nil { + return fmt.Errorf("Sync2: %v", err) + } + return nil +} diff --git a/models/update_checker.go b/models/update_checker.go new file mode 100644 index 0000000000000..5b4fce69ece95 --- /dev/null +++ b/models/update_checker.go @@ -0,0 +1,121 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package models + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/proxy" + "code.gitea.io/gitea/modules/setting" + + "github.com/hashicorp/go-version" +) + +// RemoteVersion stores the remote version from the JSON endpoint +type RemoteVersion struct { + ID int64 `xorm:"pk autoincr"` + Version string `xorm:"VARCHAR(50)"` +} + +func init() { + db.RegisterModel(new(RemoteVersion)) +} + +// GiteaUpdateChecker returns error when new version of Gitea is available +func GiteaUpdateChecker(httpEndpoint string) error { + httpClient := &http.Client{ + Transport: &http.Transport{ + Proxy: proxy.Proxy(), + }, + } + + req, err := http.NewRequest("GET", httpEndpoint, nil) + if err != nil { + return err + } + resp, err := httpClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + + type v struct { + Latest struct { + Version string `json:"version"` + } `json:"latest"` + } + ver := v{} + err = json.Unmarshal(body, &ver) + if err != nil { + return err + } + + return UpdateRemoteVersion(ver.Latest.Version) + +} + +// UpdateRemoteVersion updates the latest available version of Gitea +func UpdateRemoteVersion(version string) (err error) { + sess := db.NewSession(db.DefaultContext) + defer sess.Close() + if err = sess.Begin(); err != nil { + return err + } + + currentVersion := &RemoteVersion{ID: 1} + has, err := sess.Get(currentVersion) + if err != nil { + return fmt.Errorf("get: %v", err) + } else if !has { + currentVersion.ID = 1 + currentVersion.Version = version + + if _, err = sess.InsertOne(currentVersion); err != nil { + return fmt.Errorf("insert: %v", err) + } + return nil + } + + if _, err = sess.Update(&RemoteVersion{ID: 1, Version: version}); err != nil { + return err + } + + return sess.Commit() +} + +// GetRemoteVersion returns the current remote version (or currently installed verson if fail to fetch from DB) +func GetRemoteVersion() string { + e := db.GetEngine(db.DefaultContext) + v := &RemoteVersion{ID: 1} + _, err := e.Get(&v) + if err != nil { + // return current version if fail to fetch from DB + return setting.AppVer + } + return v.Version +} + +// GetNeedUpdate returns true whether a newer version of Gitea is available +func GetNeedUpdate() bool { + curVer, err := version.NewVersion(setting.AppVer) + if err != nil { + // return false to fail silently + return false + } + remoteVer, err := version.NewVersion(GetRemoteVersion()) + if err != nil { + // return false to fail silently + return false + } + return curVer.LessThan(remoteVer) +} diff --git a/modules/cron/tasks_extended.go b/modules/cron/tasks_extended.go index 680f83e50c87b..6645e71d2cb26 100644 --- a/modules/cron/tasks_extended.go +++ b/modules/cron/tasks_extended.go @@ -131,6 +131,24 @@ func registerDeleteOldActions() { }) } +func registerUpdateGiteaChecker() { + type UpdateCheckerConfig struct { + BaseConfig + HTTPEndpoint string + } + RegisterTaskFatal("update_checker", &UpdateCheckerConfig{ + BaseConfig: BaseConfig{ + Enabled: true, + RunAtStart: false, + Schedule: "@every 168h", + }, + HTTPEndpoint: "https://dl.gitea.io/gitea/version.json", + }, func(ctx context.Context, _ *models.User, config Config) error { + updateCheckerConfig := config.(*UpdateCheckerConfig) + return models.GiteaUpdateChecker(updateCheckerConfig.HTTPEndpoint) + }) +} + func initExtendedTasks() { registerDeleteInactiveUsers() registerDeleteRepositoryArchives() @@ -142,4 +160,5 @@ func initExtendedTasks() { registerDeleteMissingRepositories() registerRemoveRandomAvatars() registerDeleteOldActions() + registerUpdateGiteaChecker() } diff --git a/routers/web/admin/admin.go b/routers/web/admin/admin.go index ce177ea090872..ca5b157523c50 100644 --- a/routers/web/admin/admin.go +++ b/routers/web/admin/admin.go @@ -125,6 +125,8 @@ func Dashboard(ctx *context.Context) { ctx.Data["PageIsAdmin"] = true ctx.Data["PageIsAdminDashboard"] = true ctx.Data["Stats"] = models.GetStatistic() + ctx.Data["NeedUpdate"] = models.GetNeedUpdate() + ctx.Data["RemoteVersion"] = models.GetRemoteVersion() // FIXME: update periodically updateSystemStatus() ctx.Data["SysStatus"] = sysStatus diff --git a/templates/admin/dashboard.tmpl b/templates/admin/dashboard.tmpl index de01f95eabd7b..79f031882e332 100644 --- a/templates/admin/dashboard.tmpl +++ b/templates/admin/dashboard.tmpl @@ -3,6 +3,11 @@ {{template "admin/navbar" .}}
{{template "base/alert" .}} + {{if .NeedUpdate}} +
+

"Gitea {{.RemoteVersion | Str2html}} is now available, you are running {{.AppVer | Str2html}}. Check the blog for more details.

+
+ {{end}}

{{.i18n.Tr "admin.dashboard.statistic"}}