refactor: clean up git repo and model migration packages (#38564)

enable the golangci depguard lint rule: deny "models" and its sub
packages in "modelmigration" package.
This commit is contained in:
wxiaoguang
2026-07-23 09:22:26 +08:00
committed by GitHub
parent fa64b4627a
commit 1acf93d854
43 changed files with 243 additions and 167 deletions
+6 -7
View File
@@ -11,19 +11,14 @@ import (
"regexp"
"strings"
"gitea.dev/models/db"
"gitea.dev/models/db" //nolint:depguard // allow to access db in migration
"gitea.dev/modules/log"
"gitea.dev/modules/setting"
"xorm.io/builder"
"xorm.io/xorm/schemas"
)
// 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".
// However, many the existing migrations already abuses "modules/structs" (search "gitea.dev/models/" in the migrations).
// TODO: need to fully decouple the migration package and models & structs package
type (
EngineMigration = db.EngineMigration
Session = db.Session
@@ -519,3 +514,7 @@ func ModifyColumn(x EngineMigration, tableName string, col *schemas.Column) erro
}
return nil
}
func Iterate[Bean any](ctx context.Context, cond builder.Cond, f func(ctx context.Context, bean *Bean) error) error {
return db.Iterate(ctx, cond, f)
}
-13
View File
@@ -1,13 +0,0 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package base
import (
repo_model "gitea.dev/models/repo"
"gitea.dev/modules/git/gitcmd"
)
func LocalCodeGitRepo(ownerName, repoName string) gitcmd.RepositoryFacade {
return repo_model.CodeRepoByName(ownerName, repoName)
}
+25
View File
@@ -0,0 +1,25 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package base
import (
"gitea.dev/models/db" //nolint:depguard // allow to access db in migration
"gitea.dev/modules/git/gitrepo"
)
// HINT: MIGRATION-STRUCT-FROZEN: the structs used in migrations should not be affected by the changes happen in the future,
// because the details 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 existing migration will break because it will use the new (incorrect) User model,
// it should only use the old User model.
//
// Related: "models", "modules/structs", git repo directory layout on the disk, etc.
//
// If changes happen, the old migrations need to use a snapshot struct/function (copy the code and freeze)
type ResourceIndex = db.ResourceIndex
func LocalCodeGitRepo(ownerName, repoName string) gitrepo.RepositoryFacade {
return gitrepo.CodeRepoByName(ownerName, repoName)
}
+2 -2
View File
@@ -9,8 +9,8 @@ import (
"testing"
"gitea.dev/modelmigration/base"
"gitea.dev/models/db"
"gitea.dev/models/unittest"
"gitea.dev/models/db" //nolint:depguard // allow to access db in migration tests
"gitea.dev/models/unittest" //nolint:depguard // allow to access db in migration tests
"gitea.dev/modules/git"
"gitea.dev/modules/setting"
"gitea.dev/modules/testlogger"
+1 -1
View File
@@ -5,7 +5,7 @@ package v1_17
import (
"gitea.dev/modelmigration/base"
packages_model "gitea.dev/models/packages"
packages_model "gitea.dev/models/packages" //nolint:depguard // only consts are used
container_module "gitea.dev/modules/packages/container"
"xorm.io/xorm/schemas"
+11 -2
View File
@@ -7,7 +7,7 @@ import (
"fmt"
"gitea.dev/modelmigration/base"
"gitea.dev/models/issues"
"gitea.dev/modules/timeutil"
"xorm.io/builder"
)
@@ -19,6 +19,15 @@ func UpdateOpenMilestoneCounts(x base.EngineMigration) error {
return fmt.Errorf("error selecting open milestone IDs: %w", err)
}
type Milestone struct {
ID int64
IsClosed bool
NumIssues int
NumClosedIssues int
Completeness int
UpdatedUnix timeutil.TimeStamp
}
for _, id := range openMilestoneIDs {
_, err := x.ID(id).
Cols("num_issues", "num_closed_issues").
@@ -31,7 +40,7 @@ func UpdateOpenMilestoneCounts(x base.EngineMigration) error {
"is_closed": true,
},
)).
Update(&issues.Milestone{})
Update(&Milestone{})
if err != nil {
return fmt.Errorf("error updating issue counts in milestone %d: %w", id, err)
}
+22 -4
View File
@@ -7,16 +7,34 @@ import (
"testing"
"gitea.dev/modelmigration/migrationtest"
"gitea.dev/models/issues"
"gitea.dev/modules/timeutil"
"github.com/stretchr/testify/assert"
)
func Test_UpdateOpenMilestoneCounts(t *testing.T) {
type ExpectedMilestone issues.Milestone
type Issue struct {
ID int64
RepoID int64
Index int64
MilestoneID int64
IsClosed bool
UpdatedUnix timeutil.TimeStamp
}
type Milestone struct {
ID int64
IsClosed bool
NumIssues int
NumClosedIssues int
Completeness int
UpdatedUnix timeutil.TimeStamp
}
type ExpectedMilestone Milestone
// Prepare and load the testing database
x, deferable := migrationtest.PrepareTestEnv(t, 0, new(issues.Milestone), new(ExpectedMilestone), new(issues.Issue))
x, deferable := migrationtest.PrepareTestEnv(t, 0, new(Milestone), new(ExpectedMilestone), new(Issue))
defer deferable()
if x == nil || t.Failed() {
return
@@ -32,7 +50,7 @@ func Test_UpdateOpenMilestoneCounts(t *testing.T) {
return
}
got := []issues.Milestone{}
got := []Milestone{}
if err := x.Table("milestone").Asc("id").Find(&got); !assert.NoError(t, err) {
return
}
+1 -2
View File
@@ -5,7 +5,6 @@ package v1_19
import (
"gitea.dev/modelmigration/base"
"gitea.dev/models/db"
"gitea.dev/modules/timeutil"
)
@@ -96,7 +95,7 @@ func AddActionsTables(x base.EngineMigration) error {
NumClosedActionRuns int `xorm:"NOT NULL DEFAULT 0"`
}
type ActionRunIndex db.ResourceIndex
type ActionRunIndex base.ResourceIndex
type ActionTask struct {
ID int64
+1 -2
View File
@@ -8,7 +8,6 @@ import (
"errors"
"gitea.dev/modelmigration/base"
"gitea.dev/models/db"
"gitea.dev/modules/timeutil"
)
@@ -60,7 +59,7 @@ func AddBranchTable(x base.EngineMigration) error {
}
branches := make([]Branch, 0, 100)
if err := db.Iterate(context.Background(), nil, func(ctx context.Context, deletedBranch *DeletedBranch) error {
if err := base.Iterate(context.Background(), nil, func(ctx context.Context, deletedBranch *DeletedBranch) error {
branches = append(branches, Branch{
RepoID: deletedBranch.RepoID,
Name: deletedBranch.Name,
+19 -15
View File
@@ -9,6 +9,24 @@ import (
"gitea.dev/modules/timeutil"
)
type ProjectBoardV293 struct {
ID int64 `xorm:"pk autoincr"`
Title string
Default bool `xorm:"NOT NULL DEFAULT false"` // issues not assigned to a specific board will be assigned to this board
Sorting int8 `xorm:"NOT NULL DEFAULT 0"`
Color string `xorm:"VARCHAR(7)"`
ProjectID int64 `xorm:"INDEX NOT NULL"`
CreatorID int64 `xorm:"NOT NULL"`
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
}
func (ProjectBoardV293) TableName() string {
return "project_board"
}
// CheckProjectColumnsConsistency ensures there is exactly one default board per project present
func CheckProjectColumnsConsistency(x base.EngineMigration) error {
sess := x.NewSession()
@@ -25,20 +43,6 @@ func CheckProjectColumnsConsistency(x base.EngineMigration) error {
BoardID int64
}
type ProjectBoard struct {
ID int64 `xorm:"pk autoincr"`
Title string
Default bool `xorm:"NOT NULL DEFAULT false"` // issues not assigned to a specific board will be assigned to this board
Sorting int8 `xorm:"NOT NULL DEFAULT 0"`
Color string `xorm:"VARCHAR(7)"`
ProjectID int64 `xorm:"INDEX NOT NULL"`
CreatorID int64 `xorm:"NOT NULL"`
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
}
for {
if err := sess.Begin(); err != nil {
return err
@@ -56,7 +60,7 @@ func CheckProjectColumnsConsistency(x base.EngineMigration) error {
}
for _, p := range projects {
if _, err := sess.Insert(ProjectBoard{
if _, err := sess.Insert(ProjectBoardV293{
ProjectID: p.ID,
Default: true,
Title: "Uncategorized",
+26 -6
View File
@@ -7,14 +7,30 @@ import (
"testing"
"gitea.dev/modelmigration/migrationtest"
"gitea.dev/models/project"
"gitea.dev/modules/timeutil"
"github.com/stretchr/testify/assert"
)
func Test_CheckProjectColumnsConsistency(t *testing.T) {
// Prepare and load the testing database
x, deferable := migrationtest.PrepareTestEnv(t, 0, new(project.Project), new(project.Column))
type Project struct {
ID int64
Title string
Description string
OwnerID int64
RepoID int64
CreatorID int64
IsClosed bool
TemplateType uint8
BoardType uint8
Type uint8
CreatedUnix timeutil.TimeStamp
UpdatedUnix timeutil.TimeStamp
ClosedDateUnix timeutil.TimeStamp
}
x, deferable := migrationtest.PrepareTestEnv(t, 0, new(Project), new(ProjectBoardV293))
defer deferable()
if x == nil || t.Failed() {
return
@@ -23,7 +39,7 @@ func Test_CheckProjectColumnsConsistency(t *testing.T) {
assert.NoError(t, CheckProjectColumnsConsistency(x))
// check if default column was added
var defaultColumn project.Column
var defaultColumn ProjectBoardV293
has, err := x.Where("project_id=? AND `default` = ?", 1, true).Get(&defaultColumn)
assert.NoError(t, err)
assert.True(t, has)
@@ -31,13 +47,17 @@ func Test_CheckProjectColumnsConsistency(t *testing.T) {
assert.True(t, defaultColumn.Default)
// check if multiple defaults, previous were removed and last will be kept
expectDefaultColumn, err := project.GetColumn(t.Context(), 2)
var expectDefaultColumn ProjectBoardV293
has, err = x.ID(2).Get(&expectDefaultColumn)
assert.NoError(t, err)
assert.True(t, has)
assert.Equal(t, int64(2), expectDefaultColumn.ProjectID)
assert.False(t, expectDefaultColumn.Default)
expectNonDefaultColumn, err := project.GetColumn(t.Context(), 3)
var expectNonDefaultColumn ProjectBoardV293
has, err = x.ID(3).Get(&expectNonDefaultColumn)
assert.NoError(t, err)
assert.True(t, has)
assert.Equal(t, int64(2), expectNonDefaultColumn.ProjectID)
assert.True(t, expectNonDefaultColumn.Default)
}
+1 -2
View File
@@ -5,7 +5,6 @@ package v1_27
import (
"gitea.dev/modelmigration/base"
"gitea.dev/models/db"
"xorm.io/xorm"
)
@@ -25,7 +24,7 @@ func AddReusableWorkflowFieldsToActionRunJob(x base.EngineMigration) error {
ReusableWorkflowContent []byte `xorm:"LONGBLOB"`
}
type ActionRunAttemptJobIDIndex db.ResourceIndex
type ActionRunAttemptJobIDIndex base.ResourceIndex
if _, err := x.SyncWithOptions(xorm.SyncOptions{IgnoreDropIndices: true}, new(ActionRunJob)); err != nil {
return err