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 <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>
This commit is contained in:
parent
e18ea9e349
commit
8edda8b446
8 changed files with 195 additions and 3 deletions
|
@ -1925,6 +1925,19 @@ PATH =
|
||||||
;SCHEDULE = @every 168h
|
;SCHEDULE = @every 168h
|
||||||
;OLDER_THAN = 8760h
|
;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
|
;; Git Operation timeout in seconds
|
||||||
|
|
|
@ -23,8 +23,8 @@ or any corresponding location. When installing from a distribution, this will
|
||||||
typically be found at `/etc/gitea/conf/app.ini`.
|
typically be found at `/etc/gitea/conf/app.ini`.
|
||||||
|
|
||||||
The defaults provided here are best-effort (not built automatically). They are
|
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)
|
accurately recorded in [app.example.ini](https://github.com/go-gitea/gitea/blob/main/custom/conf/app.example.ini)
|
||||||
(s/master/\<tag|release\>). Any string in the format `%(X)s` is a feature powered
|
(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.
|
by [ini](https://github.com/go-ini/ini/#recursive-values), for reading values recursively.
|
||||||
|
|
||||||
Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
|
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.
|
- `ENABLED`: **false**: Enable service.
|
||||||
- `RUN_AT_START`: **false**: Run tasks at start up time (if ENABLED).
|
- `RUN_AT_START`: **false**: Run tasks at start up time (if ENABLED).
|
||||||
- `NO_SUCCESS_NOTICE`: **false**: Set to true to switch off success notices.
|
- `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.
|
- `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`)
|
## Git (`git`)
|
||||||
|
|
||||||
- `PATH`: **""**: The path of git executable. If empty, Gitea searches through the PATH environment.
|
- `PATH`: **""**: The path of git executable. If empty, Gitea searches through the PATH environment.
|
||||||
|
|
|
@ -350,6 +350,8 @@ var migrations = []Migration{
|
||||||
NewMigration("Add renamed_branch table", addRenamedBranchTable),
|
NewMigration("Add renamed_branch table", addRenamedBranchTable),
|
||||||
// v198 -> v199
|
// v198 -> v199
|
||||||
NewMigration("Add issue content history table", addTableIssueContentHistory),
|
NewMigration("Add issue content history table", addTableIssueContentHistory),
|
||||||
|
// v199 -> v200
|
||||||
|
NewMigration("Add remote version table", addRemoteVersionTable),
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCurrentDBVersion returns the current db version
|
// GetCurrentDBVersion returns the current db version
|
||||||
|
|
23
models/migrations/v199.go
Normal file
23
models/migrations/v199.go
Normal file
|
@ -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
|
||||||
|
}
|
121
models/update_checker.go
Normal file
121
models/update_checker.go
Normal file
|
@ -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)
|
||||||
|
}
|
|
@ -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() {
|
func initExtendedTasks() {
|
||||||
registerDeleteInactiveUsers()
|
registerDeleteInactiveUsers()
|
||||||
registerDeleteRepositoryArchives()
|
registerDeleteRepositoryArchives()
|
||||||
|
@ -142,4 +160,5 @@ func initExtendedTasks() {
|
||||||
registerDeleteMissingRepositories()
|
registerDeleteMissingRepositories()
|
||||||
registerRemoveRandomAvatars()
|
registerRemoveRandomAvatars()
|
||||||
registerDeleteOldActions()
|
registerDeleteOldActions()
|
||||||
|
registerUpdateGiteaChecker()
|
||||||
}
|
}
|
||||||
|
|
|
@ -125,6 +125,8 @@ func Dashboard(ctx *context.Context) {
|
||||||
ctx.Data["PageIsAdmin"] = true
|
ctx.Data["PageIsAdmin"] = true
|
||||||
ctx.Data["PageIsAdminDashboard"] = true
|
ctx.Data["PageIsAdminDashboard"] = true
|
||||||
ctx.Data["Stats"] = models.GetStatistic()
|
ctx.Data["Stats"] = models.GetStatistic()
|
||||||
|
ctx.Data["NeedUpdate"] = models.GetNeedUpdate()
|
||||||
|
ctx.Data["RemoteVersion"] = models.GetRemoteVersion()
|
||||||
// FIXME: update periodically
|
// FIXME: update periodically
|
||||||
updateSystemStatus()
|
updateSystemStatus()
|
||||||
ctx.Data["SysStatus"] = sysStatus
|
ctx.Data["SysStatus"] = sysStatus
|
||||||
|
|
|
@ -3,6 +3,11 @@
|
||||||
{{template "admin/navbar" .}}
|
{{template "admin/navbar" .}}
|
||||||
<div class="ui container">
|
<div class="ui container">
|
||||||
{{template "base/alert" .}}
|
{{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">
|
<h4 class="ui top attached header">
|
||||||
{{.i18n.Tr "admin.dashboard.statistic"}}
|
{{.i18n.Tr "admin.dashboard.statistic"}}
|
||||||
</h4>
|
</h4>
|
||||||
|
|
Reference in a new issue