mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 16:40:24 +08:00 
			
		
		
		
	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:
		@@ -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 New Issue
	
	Block a user