mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-04 03:52:04 +00:00 
			
		
		
		
	Refactor update checker to use AppState (#17387)
We have the `AppState` module now, it can store app related data easily. We do not need to create separate tables for each feature. So the update checker can use `AppState` instead of a one-row dedicate table. And the code of update checker is moved from `models` to `modules`.
This commit is contained in:
		@@ -351,9 +351,11 @@ var migrations = []Migration{
 | 
			
		||||
	// v198 -> v199
 | 
			
		||||
	NewMigration("Add issue content history table", addTableIssueContentHistory),
 | 
			
		||||
	// v199 -> v200
 | 
			
		||||
	NewMigration("Add remote version table", addRemoteVersionTable),
 | 
			
		||||
	NewMigration("No-op (remote version is using AppState now)", addRemoteVersionTableNoop),
 | 
			
		||||
	// v200 -> v201
 | 
			
		||||
	NewMigration("Add table app_state", addTableAppState),
 | 
			
		||||
	// v201 -> v202
 | 
			
		||||
	NewMigration("Drop table remote_version (if exists)", dropTableRemoteVersion),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetCurrentDBVersion returns the current db version
 | 
			
		||||
 
 | 
			
		||||
@@ -5,19 +5,10 @@
 | 
			
		||||
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)
 | 
			
		||||
	}
 | 
			
		||||
func addRemoteVersionTableNoop(x *xorm.Engine) error {
 | 
			
		||||
	// we used to use a table `remote_version` to store information for updater, now we use `AppState`, so this migration task is a no-op now.
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										15
									
								
								models/migrations/v201.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								models/migrations/v201.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
// 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 (
 | 
			
		||||
	"xorm.io/xorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func dropTableRemoteVersion(x *xorm.Engine) error {
 | 
			
		||||
	// drop the orphaned table introduced in `v199`, now the update checker also uses AppState, do not need this table
 | 
			
		||||
	_ = x.DropTables("remote_version")
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
@@ -11,6 +11,7 @@ import (
 | 
			
		||||
	"code.gitea.io/gitea/models"
 | 
			
		||||
	repo_module "code.gitea.io/gitea/modules/repository"
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
	"code.gitea.io/gitea/modules/updatechecker"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func registerDeleteInactiveUsers() {
 | 
			
		||||
@@ -145,7 +146,7 @@ func registerUpdateGiteaChecker() {
 | 
			
		||||
		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)
 | 
			
		||||
		return updatechecker.GiteaUpdateChecker(updateCheckerConfig.HTTPEndpoint)
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,29 +2,28 @@
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package models
 | 
			
		||||
package updatechecker
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/modules/appstate"
 | 
			
		||||
	"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)"`
 | 
			
		||||
// CheckerState stores the remote version from the JSON endpoint
 | 
			
		||||
type CheckerState struct {
 | 
			
		||||
	LatestVersion string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	db.RegisterModel(new(RemoteVersion))
 | 
			
		||||
// Name returns the name of the state item for update checker
 | 
			
		||||
func (r *CheckerState) Name() string {
 | 
			
		||||
	return "update-checker"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GiteaUpdateChecker returns error when new version of Gitea is available
 | 
			
		||||
@@ -49,60 +48,33 @@ func GiteaUpdateChecker(httpEndpoint string) error {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	type v struct {
 | 
			
		||||
	type respType struct {
 | 
			
		||||
		Latest struct {
 | 
			
		||||
			Version string `json:"version"`
 | 
			
		||||
		} `json:"latest"`
 | 
			
		||||
	}
 | 
			
		||||
	ver := v{}
 | 
			
		||||
	err = json.Unmarshal(body, &ver)
 | 
			
		||||
	respData := respType{}
 | 
			
		||||
	err = json.Unmarshal(body, &respData)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return UpdateRemoteVersion(ver.Latest.Version)
 | 
			
		||||
	return UpdateRemoteVersion(respData.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()
 | 
			
		||||
	return appstate.AppState.Set(&CheckerState{LatestVersion: version})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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
 | 
			
		||||
	item := new(CheckerState)
 | 
			
		||||
	if err := appstate.AppState.Get(item); err != nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
	return v.Version
 | 
			
		||||
	return item.LatestVersion
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetNeedUpdate returns true whether a newer version of Gitea is available
 | 
			
		||||
@@ -112,7 +84,12 @@ func GetNeedUpdate() bool {
 | 
			
		||||
		// return false to fail silently
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	remoteVer, err := version.NewVersion(GetRemoteVersion())
 | 
			
		||||
	remoteVerStr := GetRemoteVersion()
 | 
			
		||||
	if remoteVerStr == "" {
 | 
			
		||||
		// no remote version is known
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	remoteVer, err := version.NewVersion(remoteVerStr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		// return false to fail silently
 | 
			
		||||
		return false
 | 
			
		||||
@@ -26,6 +26,7 @@ import (
 | 
			
		||||
	"code.gitea.io/gitea/modules/queue"
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
	"code.gitea.io/gitea/modules/timeutil"
 | 
			
		||||
	"code.gitea.io/gitea/modules/updatechecker"
 | 
			
		||||
	"code.gitea.io/gitea/modules/web"
 | 
			
		||||
	"code.gitea.io/gitea/services/forms"
 | 
			
		||||
	"code.gitea.io/gitea/services/mailer"
 | 
			
		||||
@@ -125,8 +126,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()
 | 
			
		||||
	ctx.Data["NeedUpdate"] = updatechecker.GetNeedUpdate()
 | 
			
		||||
	ctx.Data["RemoteVersion"] = updatechecker.GetRemoteVersion()
 | 
			
		||||
	// FIXME: update periodically
 | 
			
		||||
	updateSystemStatus()
 | 
			
		||||
	ctx.Data["SysStatus"] = sysStatus
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user