refactor: prepare to decouple the "model migration" package and "models" package (#38533)

Migrations should never use model structs directly, because the model
structs can be different in different releases. e.g. if one migration uses
"User" model, it works in the early releases, then one day, when the
User model changes, the migration breaks because it will use the
new (incorrect) User model, it should only use the old User model.

The same to "modules/structs".

---------

Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: delvh <dev.lh@web.de>
This commit is contained in:
wxiaoguang
2026-07-20 03:42:02 +00:00
committed by GitHub
co-authored by delvh
parent 775e3bdb34
commit fff32e9469
378 changed files with 708 additions and 721 deletions
+82
View File
@@ -0,0 +1,82 @@
// Copyright 2019 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_10
import (
"net/url"
"strings"
"time"
"gitea.dev/modelmigration/base"
)
func UpdateMigrationServiceTypes(x base.EngineMigration) error {
type Repository struct {
ID int64
OriginalServiceType int `xorm:"index default(0)"`
OriginalURL string `xorm:"VARCHAR(2048)"`
}
if err := x.Sync(new(Repository)); err != nil {
return err
}
var last int
const batchSize = 50
for {
results := make([]Repository, 0, batchSize)
err := x.Where("original_url <> '' AND original_url IS NOT NULL").
And("original_service_type = 0 OR original_service_type IS NULL").
OrderBy("id").
Limit(batchSize, last).
Find(&results)
if err != nil {
return err
}
if len(results) == 0 {
break
}
last += len(results)
const PlainGitService = 1 // 1 plain git service
const GithubService = 2 // 2 github.com
for _, res := range results {
u, err := url.Parse(res.OriginalURL)
if err != nil {
return err
}
serviceType := PlainGitService
if strings.EqualFold(u.Host, "github.com") {
serviceType = GithubService
}
_, err = x.Exec("UPDATE repository SET original_service_type = ? WHERE id = ?", serviceType, res.ID)
if err != nil {
return err
}
}
}
type ExternalLoginUser struct {
ExternalID string `xorm:"pk NOT NULL"`
UserID int64 `xorm:"INDEX NOT NULL"`
LoginSourceID int64 `xorm:"pk NOT NULL"`
RawData map[string]any `xorm:"TEXT JSON"`
Provider string `xorm:"index VARCHAR(25)"`
Email string
Name string
FirstName string
LastName string
NickName string
Description string
AvatarURL string
Location string
AccessToken string
AccessTokenSecret string
RefreshToken string
ExpiresAt time.Time
}
return x.Sync(new(ExternalLoginUser))
}
+16
View File
@@ -0,0 +1,16 @@
// Copyright 2019 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_10
import "gitea.dev/modelmigration/base"
func ChangeSomeColumnsLengthOfExternalLoginUser(x base.EngineMigration) error {
type ExternalLoginUser struct {
AccessToken string `xorm:"TEXT"`
AccessTokenSecret string `xorm:"TEXT"`
RefreshToken string `xorm:"TEXT"`
}
return x.Sync(new(ExternalLoginUser))
}
+65
View File
@@ -0,0 +1,65 @@
// Copyright 2019 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_10
import (
"crypto/sha1"
"fmt"
"gitea.dev/modelmigration/base"
)
func hashContext(context string) string {
return fmt.Sprintf("%x", sha1.Sum([]byte(context)))
}
func AddCommitStatusContext(x base.EngineMigration) error {
type CommitStatus struct {
ID int64 `xorm:"pk autoincr"`
ContextHash string `xorm:"char(40) index"`
Context string `xorm:"TEXT"`
}
if err := x.Sync(new(CommitStatus)); err != nil {
return err
}
sess := x.NewSession()
defer sess.Close()
start := 0
for {
statuses := make([]*CommitStatus, 0, 100)
err := sess.OrderBy("id").Limit(100, start).Find(&statuses)
if err != nil {
return err
}
if len(statuses) == 0 {
break
}
if err = sess.Begin(); err != nil {
return err
}
for _, status := range statuses {
status.ContextHash = hashContext(status.Context)
if _, err := sess.ID(status.ID).Cols("context_hash").Update(status); err != nil {
return err
}
}
if err := sess.Commit(); err != nil {
return err
}
if len(statuses) < 100 {
break
}
start += len(statuses)
}
return nil
}
+35
View File
@@ -0,0 +1,35 @@
// Copyright 2019 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_10
import "gitea.dev/modelmigration/base"
func AddOriginalMigrationInfo(x base.EngineMigration) error {
// Issue see models/issue.go
type Issue struct {
OriginalAuthor string
OriginalAuthorID int64
}
if err := x.Sync(new(Issue)); err != nil {
return err
}
// Issue see models/issue_comment.go
type Comment struct {
OriginalAuthor string
OriginalAuthorID int64
}
if err := x.Sync(new(Comment)); err != nil {
return err
}
// Issue see models/repo.go
type Repository struct {
OriginalURL string
}
return x.Sync(new(Repository))
}
+17
View File
@@ -0,0 +1,17 @@
// Copyright 2019 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_10
import "gitea.dev/modelmigration/base"
func ChangeSomeColumnsLengthOfRepo(x base.EngineMigration) error {
type Repository struct {
ID int64 `xorm:"pk autoincr"`
Description string `xorm:"TEXT"`
Website string `xorm:"VARCHAR(2048)"`
OriginalURL string `xorm:"VARCHAR(2048)"`
}
return x.Sync(new(Repository))
}
+25
View File
@@ -0,0 +1,25 @@
// Copyright 2019 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_10
import "gitea.dev/modelmigration/base"
func AddIndexOnRepositoryAndComment(x base.EngineMigration) error {
type Repository struct {
ID int64 `xorm:"pk autoincr"`
OwnerID int64 `xorm:"index"`
}
if err := x.Sync(new(Repository)); err != nil {
return err
}
type Comment struct {
ID int64 `xorm:"pk autoincr"`
Type int `xorm:"index"`
ReviewID int64 `xorm:"index"`
}
return x.Sync(new(Comment))
}
+15
View File
@@ -0,0 +1,15 @@
// Copyright 2019 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_10
import (
"gitea.dev/modelmigration/base"
"xorm.io/builder"
)
func RemoveLingeringIndexStatus(x base.EngineMigration) error {
_, err := x.Exec(builder.Delete(builder.NotIn("`repo_id`", builder.Select("`id`").From("`repository`"))).From("`repo_indexer_status`"))
return err
}
+15
View File
@@ -0,0 +1,15 @@
// Copyright 2019 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_10
import "gitea.dev/modelmigration/base"
func AddEmailNotificationEnabledToUser(x base.EngineMigration) error {
// User see models/user.go
type User struct {
EmailNotificationsPreference string `xorm:"VARCHAR(20) NOT NULL DEFAULT 'enabled'"`
}
return x.Sync(new(User))
}
+23
View File
@@ -0,0 +1,23 @@
// Copyright 2019 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_10
import "gitea.dev/modelmigration/base"
func AddStatusCheckColumnsForProtectedBranches(x base.EngineMigration) error {
type ProtectedBranch struct {
EnableStatusCheck bool `xorm:"NOT NULL DEFAULT false"`
StatusCheckContexts []string `xorm:"JSON TEXT"`
}
if err := x.Sync(new(ProtectedBranch)); err != nil {
return err
}
_, err := x.Cols("enable_status_check", "status_check_contexts").Update(&ProtectedBranch{
EnableStatusCheck: false,
StatusCheckContexts: []string{},
})
return err
}
+19
View File
@@ -0,0 +1,19 @@
// Copyright 2019 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_10
import "gitea.dev/modelmigration/base"
func AddCrossReferenceColumns(x base.EngineMigration) error {
// Comment see models/comment.go
type Comment struct {
RefRepoID int64 `xorm:"index"`
RefIssueID int64 `xorm:"index"`
RefCommentID int64 `xorm:"index"`
RefAction int64 `xorm:"SMALLINT"`
RefIsPull bool
}
return x.Sync(new(Comment))
}
+63
View File
@@ -0,0 +1,63 @@
// Copyright 2019 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_10
import (
"path/filepath"
"gitea.dev/modelmigration/base"
"gitea.dev/modules/setting"
"gitea.dev/modules/util"
)
func DeleteOrphanedAttachments(x base.EngineMigration) error {
type Attachment struct {
ID int64 `xorm:"pk autoincr"`
UUID string `xorm:"uuid UNIQUE"`
IssueID int64 `xorm:"INDEX"`
ReleaseID int64 `xorm:"INDEX"`
CommentID int64
}
sess := x.NewSession()
defer sess.Close()
limit := setting.Database.IterateBufferSize
if limit <= 0 {
limit = 50
}
for {
attachments := make([]Attachment, 0, limit)
if err := sess.Where("`issue_id` = 0 and (`release_id` = 0 or `release_id` not in (select `id` from `release`))").
Cols("id, uuid").Limit(limit).
Asc("id").
Find(&attachments); err != nil {
return err
}
if len(attachments) == 0 {
return nil
}
ids := make([]int64, 0, limit)
for _, attachment := range attachments {
ids = append(ids, attachment.ID)
}
if len(ids) > 0 {
if _, err := sess.In("id", ids).Delete(new(Attachment)); err != nil {
return err
}
}
for _, attachment := range attachments {
uuid := attachment.UUID
if err := util.RemoveAll(filepath.Join(setting.Attachment.Storage.Path, uuid[0:1], uuid[1:2], uuid)); err != nil {
return err
}
}
if len(attachments) < limit {
return nil
}
}
}
+14
View File
@@ -0,0 +1,14 @@
// Copyright 2019 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_10
import "gitea.dev/modelmigration/base"
func AddRepoAdminChangeTeamAccessColumnForUser(x base.EngineMigration) error {
type User struct {
RepoAdminChangeTeamAccess bool `xorm:"NOT NULL DEFAULT false"`
}
return x.Sync(new(User))
}
+16
View File
@@ -0,0 +1,16 @@
// Copyright 2019 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_10
import "gitea.dev/modelmigration/base"
func AddOriginalAuthorOnMigratedReleases(x base.EngineMigration) error {
type Release struct {
ID int64
OriginalAuthor string
OriginalAuthorID int64 `xorm:"index"`
}
return x.Sync(new(Release))
}
+37
View File
@@ -0,0 +1,37 @@
// Copyright 2019 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_10
import (
"gitea.dev/modelmigration/base"
"gitea.dev/modules/timeutil"
)
func AddTaskTable(x base.EngineMigration) error {
// TaskType defines task type
type TaskType int
// TaskStatus defines task status
type TaskStatus int
type Task struct {
ID int64
DoerID int64 `xorm:"index"` // operator
OwnerID int64 `xorm:"index"` // repo owner id, when creating, the repoID maybe zero
RepoID int64 `xorm:"index"`
Type TaskType
Status TaskStatus `xorm:"index"`
StartTime timeutil.TimeStamp
EndTime timeutil.TimeStamp
PayloadContent string `xorm:"TEXT"`
Errors string `xorm:"TEXT"` // if task failed, saved the error reason
Created timeutil.TimeStamp `xorm:"created"`
}
type Repository struct {
Status int `xorm:"NOT NULL DEFAULT 0"`
}
return x.Sync(new(Task), new(Repository))
}