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
+14
View File
@@ -0,0 +1,14 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_21
import (
"testing"
"gitea.dev/modelmigration/migrationtest"
)
func TestMain(m *testing.M) {
migrationtest.MainTest(m)
}
+24
View File
@@ -0,0 +1,24 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_21
import (
"gitea.dev/modelmigration/base"
)
func DropCustomLabelsColumnOfActionRunner(x base.EngineMigration) error {
sess := x.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
return err
}
// drop "custom_labels" cols
if err := base.DropTableColumns(sess, "action_runner", "custom_labels"); err != nil {
return err
}
return sess.Commit()
}
+23
View File
@@ -0,0 +1,23 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_21
import (
"gitea.dev/modelmigration/base"
"gitea.dev/modules/timeutil"
)
func CreateVariableTable(x base.EngineMigration) error {
type ActionVariable struct {
ID int64 `xorm:"pk autoincr"`
OwnerID int64 `xorm:"UNIQUE(owner_repo_name)"`
RepoID int64 `xorm:"INDEX UNIQUE(owner_repo_name)"`
Name string `xorm:"UNIQUE(owner_repo_name) NOT NULL"`
Data string `xorm:"LONGTEXT NOT NULL"`
CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"`
UpdatedUnix timeutil.TimeStamp `xorm:"updated"`
}
return x.Sync(new(ActionVariable))
}
+14
View File
@@ -0,0 +1,14 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_21
import "gitea.dev/modelmigration/base"
func AddTriggerEventToActionRun(x base.EngineMigration) error {
type ActionRun struct {
TriggerEvent string
}
return x.Sync(new(ActionRun))
}
+46
View File
@@ -0,0 +1,46 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_21
import (
"fmt"
"gitea.dev/modelmigration/base"
)
// AddGitSizeAndLFSSizeToRepositoryTable: add GitSize and LFSSize columns to Repository
func AddGitSizeAndLFSSizeToRepositoryTable(x base.EngineMigration) error {
type Repository struct {
GitSize int64 `xorm:"NOT NULL DEFAULT 0"`
LFSSize int64 `xorm:"NOT NULL DEFAULT 0"`
}
sess := x.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
return err
}
if err := sess.Sync(new(Repository)); err != nil {
return fmt.Errorf("Sync: %w", err)
}
_, err := sess.Exec(`UPDATE repository SET lfs_size=(SELECT SUM(size) FROM lfs_meta_object WHERE lfs_meta_object.repository_id=repository.ID) WHERE EXISTS (SELECT 1 FROM lfs_meta_object WHERE lfs_meta_object.repository_id=repository.ID)`)
if err != nil {
return err
}
_, err = sess.Exec(`UPDATE repository SET size = 0 WHERE size IS NULL`)
if err != nil {
return err
}
_, err = sess.Exec(`UPDATE repository SET git_size = size - lfs_size WHERE size > lfs_size`)
if err != nil {
return err
}
return sess.Commit()
}
+92
View File
@@ -0,0 +1,92 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_21
import (
"context"
"errors"
"gitea.dev/modelmigration/base"
"gitea.dev/models/db"
"gitea.dev/modules/timeutil"
)
func AddBranchTable(x base.EngineMigration) error {
type Branch struct {
ID int64
RepoID int64 `xorm:"UNIQUE(s)"`
Name string `xorm:"UNIQUE(s) NOT NULL"`
CommitID string
CommitMessage string `xorm:"TEXT"`
PusherID int64
IsDeleted bool `xorm:"index"`
DeletedByID int64
DeletedUnix timeutil.TimeStamp `xorm:"index"`
CommitTime timeutil.TimeStamp // The commit
CreatedUnix timeutil.TimeStamp `xorm:"created"`
UpdatedUnix timeutil.TimeStamp `xorm:"updated"`
}
if err := x.Sync(new(Branch)); err != nil {
return err
}
if exist, err := x.IsTableExist("deleted_branches"); err != nil {
return err
} else if !exist {
return nil
}
type DeletedBranch struct {
ID int64
RepoID int64 `xorm:"index UNIQUE(s)"`
Name string `xorm:"UNIQUE(s) NOT NULL"`
Commit string
DeletedByID int64
DeletedUnix timeutil.TimeStamp
}
var adminUserID int64
has, err := x.Table("user").
Select("id").
Where("is_admin=?", true).
Asc("id"). // Reliably get the admin with the lowest ID.
Get(&adminUserID)
if err != nil {
return err
} else if !has {
return errors.New("no admin user found")
}
branches := make([]Branch, 0, 100)
if err := db.Iterate(context.Background(), nil, func(ctx context.Context, deletedBranch *DeletedBranch) error {
branches = append(branches, Branch{
RepoID: deletedBranch.RepoID,
Name: deletedBranch.Name,
CommitID: deletedBranch.Commit,
PusherID: adminUserID,
IsDeleted: true,
DeletedByID: deletedBranch.DeletedByID,
DeletedUnix: deletedBranch.DeletedUnix,
})
if len(branches) >= 100 {
_, err := x.Insert(&branches)
if err != nil {
return err
}
branches = branches[:0]
}
return nil
}); err != nil {
return err
}
if len(branches) > 0 {
if _, err := x.Insert(&branches); err != nil {
return err
}
}
return x.DropTables(new(DeletedBranch))
}
+17
View File
@@ -0,0 +1,17 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_21
import "gitea.dev/modelmigration/base"
func AlterActionArtifactTable(x base.EngineMigration) error {
// ActionArtifact is a file that is stored in the artifact storage.
type ActionArtifact struct {
RunID int64 `xorm:"index unique(runid_name_path)"` // The run id of the artifact
ArtifactPath string `xorm:"index unique(runid_name_path)"` // The path to the artifact when runner uploads it
ArtifactName string `xorm:"index unique(runid_name_path)"` // The name of the artifact when
}
return x.Sync(new(ActionArtifact))
}
+21
View File
@@ -0,0 +1,21 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_21
import "gitea.dev/modelmigration/base"
func ReduceCommitStatus(x base.EngineMigration) error {
sess := x.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
return err
}
if _, err := sess.Exec(`UPDATE commit_status SET state='pending' WHERE state='running'`); err != nil {
return err
}
return sess.Commit()
}
+22
View File
@@ -0,0 +1,22 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_21
import (
"gitea.dev/modelmigration/base"
"gitea.dev/modules/timeutil"
)
func CreateActionTasksVersionTable(x base.EngineMigration) error {
type ActionTasksVersion struct {
ID int64 `xorm:"pk autoincr"`
OwnerID int64 `xorm:"UNIQUE(owner_repo)"`
RepoID int64 `xorm:"INDEX UNIQUE(owner_repo)"`
Version int64
CreatedUnix timeutil.TimeStamp `xorm:"created"`
UpdatedUnix timeutil.TimeStamp `xorm:"updated"`
}
return x.Sync(new(ActionTasksVersion))
}
+14
View File
@@ -0,0 +1,14 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_21
import "gitea.dev/modelmigration/base"
// UpdateActionsRefIndex updates the index of actions ref field
func UpdateActionsRefIndex(x base.EngineMigration) error {
type ActionRun struct {
Ref string `xorm:"index"` // the commit/tag/… causing the run
}
return x.Sync(new(ActionRun))
}
+10
View File
@@ -0,0 +1,10 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_21
import "gitea.dev/modelmigration/base"
func DropDeletedBranchTable(x base.EngineMigration) error {
return x.DropTables("deleted_branch")
}
+24
View File
@@ -0,0 +1,24 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_21
import "gitea.dev/modelmigration/base"
func FixPackagePropertyTypo(x base.EngineMigration) error {
sess := x.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
return err
}
if _, err := sess.Exec(`UPDATE package_property SET name = 'rpm.metadata' WHERE name = 'rpm.metdata'`); err != nil {
return err
}
if _, err := sess.Exec(`UPDATE package_property SET name = 'conda.metadata' WHERE name = 'conda.metdata'`); err != nil {
return err
}
return sess.Commit()
}
+16
View File
@@ -0,0 +1,16 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_21
import (
"gitea.dev/modelmigration/base"
"gitea.dev/modules/timeutil"
)
func AddArchivedUnixColumInLabelTable(x base.EngineMigration) error {
type Label struct {
ArchivedUnix timeutil.TimeStamp `xorm:"DEFAULT NULL"`
}
return x.Sync(new(Label))
}
+13
View File
@@ -0,0 +1,13 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_21
import "gitea.dev/modelmigration/base"
func AddVersionToActionRunTable(x base.EngineMigration) error {
type ActionRun struct {
Version int `xorm:"version default 0"`
}
return x.Sync(new(ActionRun))
}
+45
View File
@@ -0,0 +1,45 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_21
import (
"gitea.dev/modelmigration/base"
"gitea.dev/modules/timeutil"
)
func AddActionScheduleTable(x base.EngineMigration) error {
type ActionSchedule struct {
ID int64
Title string
Specs []string
RepoID int64 `xorm:"index"`
OwnerID int64 `xorm:"index"`
WorkflowID string
TriggerUserID int64
Ref string
CommitSHA string
Event string
EventPayload string `xorm:"LONGTEXT"`
Content []byte
Created timeutil.TimeStamp `xorm:"created"`
Updated timeutil.TimeStamp `xorm:"updated"`
}
type ActionScheduleSpec struct {
ID int64
RepoID int64 `xorm:"index"`
ScheduleID int64 `xorm:"index"`
Spec string
Next timeutil.TimeStamp `xorm:"index"`
Prev timeutil.TimeStamp
Created timeutil.TimeStamp `xorm:"created"`
Updated timeutil.TimeStamp `xorm:"updated"`
}
return x.Sync(
new(ActionSchedule),
new(ActionScheduleSpec),
)
}
+36
View File
@@ -0,0 +1,36 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_21
import (
"time"
"gitea.dev/modelmigration/base"
"gitea.dev/modules/timeutil"
)
func AddExpiredUnixColumnInActionArtifactTable(x base.EngineMigration) error {
type ActionArtifact struct {
ExpiredUnix timeutil.TimeStamp `xorm:"index"` // time when the artifact will be expired
}
if err := x.Sync(new(ActionArtifact)); err != nil {
return err
}
return updateArtifactsExpiredUnixTo90Days(x)
}
func updateArtifactsExpiredUnixTo90Days(x base.EngineMigration) error {
sess := x.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
return err
}
expiredTime := time.Now().AddDate(0, 0, 90).Unix()
if _, err := sess.Exec(`UPDATE action_artifact SET expired_unix=? WHERE status='2' AND expired_unix is NULL`, expiredTime); err != nil {
return err
}
return sess.Commit()
}
+13
View File
@@ -0,0 +1,13 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_21
import "gitea.dev/modelmigration/base"
func AddScheduleIDForActionRun(x base.EngineMigration) error {
type ActionRun struct {
ScheduleID int64
}
return x.Sync(new(ActionRun))
}
+174
View File
@@ -0,0 +1,174 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_21
import (
"context"
"gitea.dev/modelmigration/base"
repo_model "gitea.dev/models/repo"
"gitea.dev/modules/gitrepo"
"gitea.dev/modules/setting"
)
func AddRemoteAddressToMirrors(x base.EngineMigration) error {
type Mirror struct {
RemoteAddress string `xorm:"VARCHAR(2048)"`
}
type PushMirror struct {
RemoteAddress string `xorm:"VARCHAR(2048)"`
}
if err := x.Sync(new(Mirror), new(PushMirror)); err != nil {
return err
}
if err := migratePullMirrors(x); err != nil {
return err
}
return migratePushMirrors(x)
}
func migratePullMirrors(x base.EngineMigration) error {
type Mirror struct {
ID int64 `xorm:"pk autoincr"`
RepoID int64 `xorm:"INDEX"`
RemoteAddress string `xorm:"VARCHAR(2048)"`
RepoOwner string
RepoName string
}
sess := x.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
return err
}
limit := setting.Database.IterateBufferSize
if limit <= 0 {
limit = 50
}
start := 0
for {
var mirrors []Mirror
if err := sess.Select("mirror.id, mirror.repo_id, mirror.remote_address, repository.owner_name as repo_owner, repository.name as repo_name").
Join("INNER", "repository", "repository.id = mirror.repo_id").
Limit(limit, start).Find(&mirrors); err != nil {
return err
}
if len(mirrors) == 0 {
break
}
start += len(mirrors)
for _, m := range mirrors {
remoteAddress, err := getRemoteAddress(m.RepoOwner, m.RepoName, "origin")
if err != nil {
return err
}
m.RemoteAddress = remoteAddress
if _, err = sess.ID(m.ID).Cols("remote_address").Update(m); err != nil {
return err
}
}
if start%1000 == 0 { // avoid a too big transaction
if err := sess.Commit(); err != nil {
return err
}
if err := sess.Begin(); err != nil {
return err
}
}
}
return sess.Commit()
}
func migratePushMirrors(x base.EngineMigration) error {
type PushMirror struct {
ID int64 `xorm:"pk autoincr"`
RepoID int64 `xorm:"INDEX"`
RemoteName string
RemoteAddress string `xorm:"VARCHAR(2048)"`
RepoOwner string
RepoName string
}
sess := x.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
return err
}
limit := setting.Database.IterateBufferSize
if limit <= 0 {
limit = 50
}
start := 0
for {
var mirrors []PushMirror
if err := sess.Select("push_mirror.id, push_mirror.repo_id, push_mirror.remote_name, push_mirror.remote_address, repository.owner_name as repo_owner, repository.name as repo_name").
Join("INNER", "repository", "repository.id = push_mirror.repo_id").
Limit(limit, start).Find(&mirrors); err != nil {
return err
}
if len(mirrors) == 0 {
break
}
start += len(mirrors)
for _, m := range mirrors {
remoteAddress, err := getRemoteAddress(m.RepoOwner, m.RepoName, m.RemoteName)
if err != nil {
return err
}
m.RemoteAddress = remoteAddress
if _, err = sess.ID(m.ID).Cols("remote_address").Update(m); err != nil {
return err
}
}
if start%1000 == 0 { // avoid a too big transaction
if err := sess.Commit(); err != nil {
return err
}
if err := sess.Begin(); err != nil {
return err
}
}
}
return sess.Commit()
}
func getRemoteAddress(ownerName, repoName, remoteName string) (string, error) {
ctx := context.Background()
repo := repo_model.CodeRepoByName(ownerName, repoName)
if exist, _ := gitrepo.IsRepositoryExist(ctx, repo); !exist {
return "", nil
}
u, err := gitrepo.GitRemoteGetURL(ctx, repo, remoteName)
if err != nil {
return "", err
}
u.User = nil
return u.String(), nil
}
+14
View File
@@ -0,0 +1,14 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_21
import "gitea.dev/modelmigration/base"
func AddIndexToIssueUserIssueID(x base.EngineMigration) error {
type IssueUser struct {
IssueID int64 `xorm:"INDEX"`
}
return x.Sync(new(IssueUser))
}
+14
View File
@@ -0,0 +1,14 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_21
import "gitea.dev/modelmigration/base"
func AddIndexToCommentDependentIssueID(x base.EngineMigration) error {
type Comment struct {
DependentIssueID int64 `xorm:"index"`
}
return x.Sync(new(Comment))
}
+22
View File
@@ -0,0 +1,22 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_21
import (
"gitea.dev/modelmigration/base"
"xorm.io/xorm"
)
func AddIndexToActionUserID(x base.EngineMigration) error {
type Action struct {
UserID int64 `xorm:"INDEX"`
}
_, err := x.SyncWithOptions(xorm.SyncOptions{
IgnoreDropIndices: true,
IgnoreConstrains: true,
}, new(Action))
return err
}