]> source.dussan.org Git - gitea.git/commitdiff
Add simple update checker to Gitea (#17212)
authortechknowlogick <techknowlogick@gitea.io>
Sat, 16 Oct 2021 06:14:34 +0000 (02:14 -0400)
committerGitHub <noreply@github.com>
Sat, 16 Oct 2021 06:14:34 +0000 (02:14 -0400)
* 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 <dev.lh@web.de>
* Update custom/conf/app.example.ini

Co-authored-by: delvh <dev.lh@web.de>
* Update docs/content/doc/advanced/config-cheat-sheet.en-us.md

Co-authored-by: delvh <dev.lh@web.de>
* 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 <wxiaoguang@gmail.com>
* Update custom/conf/app.example.ini

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
* 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 <dev.lh@web.de>
Co-authored-by: Steven <61625851+justusbunsi@users.noreply.github.com>
Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
custom/conf/app.example.ini
docs/content/doc/advanced/config-cheat-sheet.en-us.md
models/migrations/migrations.go
models/migrations/v199.go [new file with mode: 0644]
models/update_checker.go [new file with mode: 0644]
modules/cron/tasks_extended.go
routers/web/admin/admin.go
templates/admin/dashboard.tmpl

index 07ca9f84099869e3d6d5ab8c08610e866c35dcc3..bdc42480e443ec6d3bcc224422865ce2eafa746c 100644 (file)
@@ -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
index f02d8cbc3775946ae97dd67e6914b475728b5ac4..251f6bd51a9dfe98b4d3bc91df99dd8dd39c1044 100644 (file)
@@ -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/\<tag|release\>). 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/\<tag|release\>). 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.
index ef0c0714176539d83bb59a9c2ca6cd0f00e5b928..3a41cf88918d34e32d31ea1ba5d5b2be933514cc 100644 (file)
@@ -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 (file)
index 0000000..64b2117
--- /dev/null
@@ -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 (file)
index 0000000..5b4fce6
--- /dev/null
@@ -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)
+}
index 680f83e50c87b203286886172bd0a8460257f5d1..6645e71d2cb26e5e85bba67fb13a61ec062f7176 100644 (file)
@@ -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()
 }
index ce177ea090872f06409c250ae5ecee927af6311a..ca5b157523c5082678480a4bf0541b0df078d61c 100644 (file)
@@ -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
index de01f95eabd7bb09427c788d8b2a7acb0a6182a7..79f031882e332509c12ba292d6c45037e21c7a0d 100644 (file)
@@ -3,6 +3,11 @@
        {{template "admin/navbar" .}}
        <div class="ui container">
                {{template "base/alert" .}}
+               {{if .NeedUpdate}}
+                       <div class="ui negative message flash-error">
+                               <p>"Gitea {{.RemoteVersion | Str2html}} is now available, you are running {{.AppVer | Str2html}}. Check the <a href="https://blog.gitea.io">blog</a> for more details.</p>
+                       </div>
+               {{end}}
                <h4 class="ui top attached header">
                        {{.i18n.Tr "admin.dashboard.statistic"}}
                </h4>