mirror of
https://github.com/go-gitea/gitea.git
synced 2026-09-08 14:03:24 +09:00
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:
@@ -0,0 +1,49 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package v1_13
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gitea.dev/modelmigration/base"
|
||||
"gitea.dev/modules/setting"
|
||||
)
|
||||
|
||||
func FixLanguageStatsToSaveSize(x base.EngineMigration) error {
|
||||
// LanguageStat see models/repo_language_stats.go
|
||||
type LanguageStat struct {
|
||||
Size int64 `xorm:"NOT NULL DEFAULT 0"`
|
||||
}
|
||||
|
||||
// RepoIndexerType specifies the repository indexer type
|
||||
type RepoIndexerType int
|
||||
|
||||
const RepoIndexerTypeStats RepoIndexerType = 1
|
||||
|
||||
// RepoIndexerStatus see models/repo_indexer.go
|
||||
type RepoIndexerStatus struct {
|
||||
IndexerType RepoIndexerType `xorm:"INDEX(s) NOT NULL DEFAULT 0"`
|
||||
}
|
||||
|
||||
if err := x.Sync(new(LanguageStat)); err != nil {
|
||||
return fmt.Errorf("Sync: %w", err)
|
||||
}
|
||||
|
||||
_, _ = x.Delete(&RepoIndexerStatus{IndexerType: RepoIndexerTypeStats})
|
||||
|
||||
// Delete language stat statuses
|
||||
truncExpr := "TRUNCATE TABLE"
|
||||
if setting.Database.Type.IsSQLite3() {
|
||||
truncExpr = "DELETE FROM"
|
||||
}
|
||||
|
||||
// Delete language stats
|
||||
if _, err := x.Exec(truncExpr + " language_stat"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sess.Close()
|
||||
return base.DropTableColumns(sess, "language_stat", "percentage")
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package v1_13
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gitea.dev/modelmigration/base"
|
||||
)
|
||||
|
||||
func AddKeepActivityPrivateUserColumn(x base.EngineMigration) error {
|
||||
type User struct {
|
||||
KeepActivityPrivate bool `xorm:"NOT NULL DEFAULT false"`
|
||||
}
|
||||
|
||||
if err := x.Sync(new(User)); err != nil {
|
||||
return fmt.Errorf("Sync: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package v1_13
|
||||
|
||||
import (
|
||||
"gitea.dev/modelmigration/base"
|
||||
"gitea.dev/modules/log"
|
||||
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
func SetIsArchivedToFalse(x base.EngineMigration) error {
|
||||
type Repository struct {
|
||||
IsArchived bool `xorm:"INDEX"`
|
||||
}
|
||||
count, err := x.Where(builder.IsNull{"is_archived"}).Cols("is_archived").Update(&Repository{
|
||||
IsArchived: false,
|
||||
})
|
||||
if err == nil {
|
||||
log.Debug("Updated %d repositories with is_archived IS NULL", count)
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package v1_13
|
||||
|
||||
import (
|
||||
"gitea.dev/modelmigration/base"
|
||||
"gitea.dev/modules/log"
|
||||
)
|
||||
|
||||
func RecalculateStars(x base.EngineMigration) (err error) {
|
||||
// because of issue https://github.com/go-gitea/gitea/issues/11949,
|
||||
// recalculate Stars number for all users to fully fix it.
|
||||
|
||||
type User struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
}
|
||||
|
||||
const batchSize = 100
|
||||
sess := x.NewSession()
|
||||
defer sess.Close()
|
||||
|
||||
for start := 0; ; start += batchSize {
|
||||
users := make([]User, 0, batchSize)
|
||||
if err := sess.Limit(batchSize, start).Where("type = ?", 0).Cols("id").Find(&users); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(users) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
if err := sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, user := range users {
|
||||
if _, err := sess.Exec("UPDATE `user` SET num_stars=(SELECT COUNT(*) FROM `star` WHERE uid=?) WHERE id=?", user.ID, user.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := sess.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
log.Debug("recalculate Stars number for all user finished")
|
||||
|
||||
return err
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package v1_13
|
||||
|
||||
import (
|
||||
"gitea.dev/modelmigration/base"
|
||||
"gitea.dev/modules/log"
|
||||
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
func UpdateMatrixWebhookHTTPMethod(x base.EngineMigration) error {
|
||||
matrixHookTaskType := 9 // value comes from the models package
|
||||
type Webhook struct {
|
||||
HTTPMethod string
|
||||
}
|
||||
|
||||
cond := builder.Eq{"hook_task_type": matrixHookTaskType}.And(builder.Neq{"http_method": "PUT"})
|
||||
count, err := x.Where(cond).Cols("http_method").Update(&Webhook{HTTPMethod: "PUT"})
|
||||
if err == nil {
|
||||
log.Debug("Updated %d Matrix webhooks with http_method 'PUT'", count)
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package v1_13
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gitea.dev/modelmigration/base"
|
||||
"gitea.dev/modules/setting"
|
||||
)
|
||||
|
||||
func IncreaseLanguageField(x base.EngineMigration) error {
|
||||
type LanguageStat struct {
|
||||
RepoID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"`
|
||||
Language string `xorm:"VARCHAR(50) UNIQUE(s) INDEX NOT NULL"`
|
||||
}
|
||||
|
||||
if err := x.Sync(new(LanguageStat)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if setting.Database.Type.IsSQLite3() {
|
||||
// SQLite maps VARCHAR to TEXT without size so we're done
|
||||
return nil
|
||||
}
|
||||
|
||||
// need to get the correct type for the new column
|
||||
inferredTable, err := x.TableInfo(new(LanguageStat))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
column := inferredTable.GetColumn("language")
|
||||
sqlType := x.Dialect().SQLType(column)
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sess.Close()
|
||||
if err := sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch {
|
||||
case setting.Database.Type.IsMySQL():
|
||||
if _, err := sess.Exec("ALTER TABLE language_stat MODIFY COLUMN language " + sqlType); err != nil {
|
||||
return err
|
||||
}
|
||||
case setting.Database.Type.IsMSSQL():
|
||||
// Yet again MSSQL just has to be awkward.
|
||||
// Here we have to drop the constraints first and then rebuild them
|
||||
constraints := make([]string, 0)
|
||||
if err := sess.SQL(`SELECT i.name AS Name
|
||||
FROM sys.indexes i INNER JOIN sys.index_columns ic
|
||||
ON i.index_id = ic.index_id AND i.object_id = ic.object_id
|
||||
INNER JOIN sys.tables AS t
|
||||
ON t.object_id = i.object_id
|
||||
INNER JOIN sys.columns c
|
||||
ON t.object_id = c.object_id AND ic.column_id = c.column_id
|
||||
WHERE t.name = 'language_stat' AND c.name = 'language'`).Find(&constraints); err != nil {
|
||||
return fmt.Errorf("Find constraints: %w", err)
|
||||
}
|
||||
for _, constraint := range constraints {
|
||||
if _, err := sess.Exec(fmt.Sprintf("DROP INDEX [%s] ON `language_stat`", constraint)); err != nil {
|
||||
return fmt.Errorf("Drop table `language_stat` constraint `%s`: %w", constraint, err)
|
||||
}
|
||||
}
|
||||
if _, err := sess.Exec("ALTER TABLE language_stat ALTER COLUMN language " + sqlType); err != nil {
|
||||
return err
|
||||
}
|
||||
// Finally restore the constraint
|
||||
if err := sess.CreateUniques(new(LanguageStat)); err != nil {
|
||||
return err
|
||||
}
|
||||
case setting.Database.Type.IsPostgreSQL():
|
||||
if _, err := sess.Exec("ALTER TABLE language_stat ALTER COLUMN language TYPE " + sqlType); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package v1_13
|
||||
|
||||
import (
|
||||
"gitea.dev/modelmigration/base"
|
||||
"gitea.dev/modules/timeutil"
|
||||
)
|
||||
|
||||
func AddProjectsInfo(x base.EngineMigration) error {
|
||||
// Create new tables
|
||||
type (
|
||||
ProjectType uint8
|
||||
ProjectBoardType uint8
|
||||
)
|
||||
|
||||
type Project struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
Title string `xorm:"INDEX NOT NULL"`
|
||||
Description string `xorm:"TEXT"`
|
||||
RepoID int64 `xorm:"INDEX"`
|
||||
CreatorID int64 `xorm:"NOT NULL"`
|
||||
IsClosed bool `xorm:"INDEX"`
|
||||
|
||||
BoardType ProjectBoardType
|
||||
Type ProjectType
|
||||
|
||||
ClosedDateUnix timeutil.TimeStamp
|
||||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
|
||||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
|
||||
}
|
||||
|
||||
if err := x.Sync(new(Project)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
type Comment struct {
|
||||
OldProjectID int64
|
||||
ProjectID int64
|
||||
}
|
||||
|
||||
if err := x.Sync(new(Comment)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
type Repository struct {
|
||||
ID int64
|
||||
NumProjects int `xorm:"NOT NULL DEFAULT 0"`
|
||||
NumClosedProjects int `xorm:"NOT NULL DEFAULT 0"`
|
||||
}
|
||||
|
||||
if err := x.Sync(new(Repository)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// ProjectIssue saves relation from issue to a project
|
||||
type ProjectIssue struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
IssueID int64 `xorm:"INDEX"`
|
||||
ProjectID int64 `xorm:"INDEX"`
|
||||
ProjectBoardID int64 `xorm:"INDEX"`
|
||||
}
|
||||
|
||||
if err := x.Sync(new(ProjectIssue)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
type ProjectBoard struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
Title string
|
||||
Default bool `xorm:"NOT NULL DEFAULT false"`
|
||||
|
||||
ProjectID int64 `xorm:"INDEX NOT NULL"`
|
||||
CreatorID int64 `xorm:"NOT NULL"`
|
||||
|
||||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
|
||||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
|
||||
}
|
||||
|
||||
return x.Sync(new(ProjectBoard))
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package v1_13
|
||||
|
||||
import (
|
||||
"gitea.dev/modelmigration/base"
|
||||
"gitea.dev/modules/timeutil"
|
||||
)
|
||||
|
||||
func CreateReviewsForCodeComments(x base.EngineMigration) error {
|
||||
// Review
|
||||
type Review struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
Type int
|
||||
ReviewerID int64 `xorm:"index"`
|
||||
OriginalAuthor string
|
||||
OriginalAuthorID int64
|
||||
IssueID int64 `xorm:"index"`
|
||||
Content string `xorm:"TEXT"`
|
||||
// Official is a review made by an assigned approver (counts towards approval)
|
||||
Official bool `xorm:"NOT NULL DEFAULT false"`
|
||||
CommitID string `xorm:"VARCHAR(40)"`
|
||||
Stale bool `xorm:"NOT NULL DEFAULT false"`
|
||||
|
||||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
|
||||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
|
||||
}
|
||||
|
||||
const ReviewTypeComment = 2
|
||||
|
||||
// Comment represents a comment in commit and issue page.
|
||||
type Comment struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
Type int `xorm:"INDEX"`
|
||||
PosterID int64 `xorm:"INDEX"`
|
||||
OriginalAuthor string
|
||||
OriginalAuthorID int64
|
||||
IssueID int64 `xorm:"INDEX"`
|
||||
LabelID int64
|
||||
OldProjectID int64
|
||||
ProjectID int64
|
||||
OldMilestoneID int64
|
||||
MilestoneID int64
|
||||
AssigneeID int64
|
||||
RemovedAssignee bool
|
||||
ResolveDoerID int64
|
||||
OldTitle string
|
||||
NewTitle string
|
||||
OldRef string
|
||||
NewRef string
|
||||
DependentIssueID int64
|
||||
|
||||
CommitID int64
|
||||
Line int64 // - previous line / + proposed line
|
||||
TreePath string
|
||||
Content string `xorm:"TEXT"`
|
||||
|
||||
// Path represents the 4 lines of code cemented by this comment
|
||||
PatchQuoted string `xorm:"TEXT patch"`
|
||||
|
||||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
|
||||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
|
||||
|
||||
// Reference issue in commit message
|
||||
CommitSHA string `xorm:"VARCHAR(40)"`
|
||||
|
||||
ReviewID int64 `xorm:"index"`
|
||||
Invalidated bool
|
||||
|
||||
// Reference an issue or pull from another comment, issue or PR
|
||||
// All information is about the origin of the reference
|
||||
RefRepoID int64 `xorm:"index"` // Repo where the referencing
|
||||
RefIssueID int64 `xorm:"index"`
|
||||
RefCommentID int64 `xorm:"index"` // 0 if origin is Issue title or content (or PR's)
|
||||
RefAction int `xorm:"SMALLINT"` // What happens if RefIssueID resolves
|
||||
RefIsPull bool
|
||||
}
|
||||
|
||||
if err := x.Sync(new(Review), new(Comment)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
updateComment := func(comments []*Comment) error {
|
||||
sess := x.NewSession()
|
||||
defer sess.Close()
|
||||
if err := sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, comment := range comments {
|
||||
review := &Review{
|
||||
Type: ReviewTypeComment,
|
||||
ReviewerID: comment.PosterID,
|
||||
IssueID: comment.IssueID,
|
||||
Official: false,
|
||||
CommitID: comment.CommitSHA,
|
||||
Stale: comment.Invalidated,
|
||||
OriginalAuthor: comment.OriginalAuthor,
|
||||
OriginalAuthorID: comment.OriginalAuthorID,
|
||||
CreatedUnix: comment.CreatedUnix,
|
||||
UpdatedUnix: comment.CreatedUnix,
|
||||
}
|
||||
if _, err := sess.NoAutoTime().Insert(review); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
reviewComment := &Comment{
|
||||
Type: 22,
|
||||
PosterID: comment.PosterID,
|
||||
Content: "",
|
||||
IssueID: comment.IssueID,
|
||||
ReviewID: review.ID,
|
||||
OriginalAuthor: comment.OriginalAuthor,
|
||||
OriginalAuthorID: comment.OriginalAuthorID,
|
||||
CreatedUnix: comment.CreatedUnix,
|
||||
UpdatedUnix: comment.CreatedUnix,
|
||||
}
|
||||
if _, err := sess.NoAutoTime().Insert(reviewComment); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
comment.ReviewID = review.ID
|
||||
if _, err := sess.ID(comment.ID).Cols("review_id").NoAutoTime().Update(comment); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
start := 0
|
||||
batchSize := 100
|
||||
for {
|
||||
comments := make([]*Comment, 0, batchSize)
|
||||
if err := x.Where("review_id = 0 and type = 21").Limit(batchSize, start).Find(&comments); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := updateComment(comments); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
start += len(comments)
|
||||
|
||||
if len(comments) < batchSize {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package v1_13
|
||||
|
||||
import "gitea.dev/modelmigration/base"
|
||||
|
||||
func PurgeInvalidDependenciesComments(x base.EngineMigration) error {
|
||||
_, err := x.Exec("DELETE FROM comment WHERE dependent_issue_id != 0 AND dependent_issue_id NOT IN (SELECT id FROM issue)")
|
||||
return err
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package v1_13
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gitea.dev/modelmigration/base"
|
||||
"gitea.dev/modules/timeutil"
|
||||
)
|
||||
|
||||
func AddCreatedAndUpdatedToMilestones(x base.EngineMigration) error {
|
||||
type Milestone struct {
|
||||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
|
||||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
|
||||
}
|
||||
|
||||
if err := x.Sync(new(Milestone)); err != nil {
|
||||
return fmt.Errorf("Sync: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package v1_13
|
||||
|
||||
import (
|
||||
"gitea.dev/modelmigration/base"
|
||||
"gitea.dev/modules/timeutil"
|
||||
)
|
||||
|
||||
func AddPrimaryKeyToRepoTopic(x base.EngineMigration) error {
|
||||
// Topic represents a topic of repositories
|
||||
type Topic struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
Name string `xorm:"UNIQUE VARCHAR(25)"`
|
||||
RepoCount int
|
||||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
|
||||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
|
||||
}
|
||||
|
||||
// RepoTopic represents associated repositories and topics
|
||||
type RepoTopic struct {
|
||||
RepoID int64 `xorm:"pk"`
|
||||
TopicID int64 `xorm:"pk"`
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sess.Close()
|
||||
if err := sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_ = base.RecreateTable(sess, &Topic{})
|
||||
_ = base.RecreateTable(sess, &RepoTopic{})
|
||||
|
||||
return sess.Commit()
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package v1_13
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"gitea.dev/modelmigration/base"
|
||||
"gitea.dev/modules/log"
|
||||
"gitea.dev/modules/setting"
|
||||
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
func SetDefaultPasswordToArgon2(x base.EngineMigration) error {
|
||||
switch {
|
||||
case setting.Database.Type.IsMySQL():
|
||||
_, err := x.Exec("ALTER TABLE `user` ALTER passwd_hash_algo SET DEFAULT 'argon2';")
|
||||
return err
|
||||
case setting.Database.Type.IsPostgreSQL():
|
||||
_, err := x.Exec("ALTER TABLE `user` ALTER COLUMN passwd_hash_algo SET DEFAULT 'argon2';")
|
||||
return err
|
||||
case setting.Database.Type.IsMSSQL():
|
||||
// need to find the constraint and drop it, then recreate it.
|
||||
sess := x.NewSession()
|
||||
defer sess.Close()
|
||||
if err := sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
res, err := sess.QueryString("SELECT [name] FROM sys.default_constraints WHERE parent_object_id=OBJECT_ID(?) AND COL_NAME(parent_object_id, parent_column_id)=?;", "user", "passwd_hash_algo")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(res) > 0 {
|
||||
constraintName := res[0]["name"]
|
||||
log.Error("Results of select constraint: %s", constraintName)
|
||||
_, err := sess.Exec("ALTER TABLE [user] DROP CONSTRAINT " + constraintName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = sess.Exec("ALTER TABLE [user] ADD CONSTRAINT " + constraintName + " DEFAULT 'argon2' FOR passwd_hash_algo")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
_, err := sess.Exec("ALTER TABLE [user] ADD DEFAULT('argon2') FOR passwd_hash_algo")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return sess.Commit()
|
||||
|
||||
case setting.Database.Type.IsSQLite3():
|
||||
// drop through
|
||||
default:
|
||||
log.Fatal("Unrecognized DB")
|
||||
}
|
||||
|
||||
tables, err := x.DBMetas()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Now for SQLite we have to recreate the table
|
||||
var table *schemas.Table
|
||||
tableName := "user"
|
||||
|
||||
for _, table = range tables {
|
||||
if table.Name == tableName {
|
||||
break
|
||||
}
|
||||
}
|
||||
if table == nil || table.Name != tableName {
|
||||
type User struct {
|
||||
PasswdHashAlgo string `xorm:"NOT NULL DEFAULT 'argon2'"`
|
||||
}
|
||||
return x.Sync(new(User))
|
||||
}
|
||||
column := table.GetColumn("passwd_hash_algo")
|
||||
if column == nil {
|
||||
type User struct {
|
||||
PasswdHashAlgo string `xorm:"NOT NULL DEFAULT 'argon2'"`
|
||||
}
|
||||
return x.Sync(new(User))
|
||||
}
|
||||
|
||||
tempTableName := "tmp_recreate__user"
|
||||
column.Default = "'argon2'"
|
||||
|
||||
createTableSQL, _, err := x.Dialect().CreateTableSQL(context.Background(), x.DB(), table, tempTableName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sess.Close()
|
||||
if err := sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := sess.Exec(createTableSQL); err != nil {
|
||||
log.Error("Unable to create table %s. Error: %v\n", tempTableName, err, createTableSQL)
|
||||
return err
|
||||
}
|
||||
for _, index := range table.Indexes {
|
||||
if _, err := sess.Exec(x.Dialect().CreateIndexSQL(tempTableName, index)); err != nil {
|
||||
log.Error("Unable to create indexes on temporary table %s. Error: %v", tempTableName, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
newTableColumns := table.Columns()
|
||||
if len(newTableColumns) == 0 {
|
||||
return errors.New("no columns in new table")
|
||||
}
|
||||
hasID := false
|
||||
for _, column := range newTableColumns {
|
||||
hasID = hasID || (column.IsPrimaryKey && column.IsAutoIncrement)
|
||||
}
|
||||
|
||||
sqlStringBuilder := &strings.Builder{}
|
||||
_, _ = sqlStringBuilder.WriteString("INSERT INTO `")
|
||||
_, _ = sqlStringBuilder.WriteString(tempTableName)
|
||||
_, _ = sqlStringBuilder.WriteString("` (`")
|
||||
_, _ = sqlStringBuilder.WriteString(newTableColumns[0].Name)
|
||||
_, _ = sqlStringBuilder.WriteString("`")
|
||||
for _, column := range newTableColumns[1:] {
|
||||
_, _ = sqlStringBuilder.WriteString(", `")
|
||||
_, _ = sqlStringBuilder.WriteString(column.Name)
|
||||
_, _ = sqlStringBuilder.WriteString("`")
|
||||
}
|
||||
_, _ = sqlStringBuilder.WriteString(")")
|
||||
_, _ = sqlStringBuilder.WriteString(" SELECT ")
|
||||
if newTableColumns[0].Default != "" {
|
||||
_, _ = sqlStringBuilder.WriteString("COALESCE(`")
|
||||
_, _ = sqlStringBuilder.WriteString(newTableColumns[0].Name)
|
||||
_, _ = sqlStringBuilder.WriteString("`, ")
|
||||
_, _ = sqlStringBuilder.WriteString(newTableColumns[0].Default)
|
||||
_, _ = sqlStringBuilder.WriteString(")")
|
||||
} else {
|
||||
_, _ = sqlStringBuilder.WriteString("`")
|
||||
_, _ = sqlStringBuilder.WriteString(newTableColumns[0].Name)
|
||||
_, _ = sqlStringBuilder.WriteString("`")
|
||||
}
|
||||
|
||||
for _, column := range newTableColumns[1:] {
|
||||
if column.Default != "" {
|
||||
_, _ = sqlStringBuilder.WriteString(", COALESCE(`")
|
||||
_, _ = sqlStringBuilder.WriteString(column.Name)
|
||||
_, _ = sqlStringBuilder.WriteString("`, ")
|
||||
_, _ = sqlStringBuilder.WriteString(column.Default)
|
||||
_, _ = sqlStringBuilder.WriteString(")")
|
||||
} else {
|
||||
_, _ = sqlStringBuilder.WriteString(", `")
|
||||
_, _ = sqlStringBuilder.WriteString(column.Name)
|
||||
_, _ = sqlStringBuilder.WriteString("`")
|
||||
}
|
||||
}
|
||||
_, _ = sqlStringBuilder.WriteString(" FROM `")
|
||||
_, _ = sqlStringBuilder.WriteString(tableName)
|
||||
_, _ = sqlStringBuilder.WriteString("`")
|
||||
|
||||
if _, err := sess.Exec(sqlStringBuilder.String()); err != nil {
|
||||
log.Error("Unable to set copy data in to temp table %s. Error: %v", tempTableName, err)
|
||||
return err
|
||||
}
|
||||
|
||||
// SQLite will drop all the constraints on the old table
|
||||
if _, err := sess.Exec(fmt.Sprintf("DROP TABLE `%s`", tableName)); err != nil {
|
||||
log.Error("Unable to drop old table %s. Error: %v", tableName, err)
|
||||
return err
|
||||
}
|
||||
|
||||
for _, index := range table.Indexes {
|
||||
if _, err := sess.Exec(x.Dialect().DropIndexSQL(tempTableName, index)); err != nil {
|
||||
log.Error("Unable to drop indexes on temporary table %s. Error: %v", tempTableName, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := sess.Exec(fmt.Sprintf("ALTER TABLE `%s` RENAME TO `%s`", tempTableName, tableName)); err != nil {
|
||||
log.Error("Unable to rename %s to %s. Error: %v", tempTableName, tableName, err)
|
||||
return err
|
||||
}
|
||||
|
||||
for _, index := range table.Indexes {
|
||||
if _, err := sess.Exec(x.Dialect().CreateIndexSQL(tableName, index)); err != nil {
|
||||
log.Error("Unable to recreate indexes on table %s. Error: %v", tableName, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package v1_13
|
||||
|
||||
import "gitea.dev/modelmigration/base"
|
||||
|
||||
func AddTrustModelToRepository(x base.EngineMigration) error {
|
||||
type Repository struct {
|
||||
TrustModel int
|
||||
}
|
||||
return x.Sync(new(Repository))
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package v1_13
|
||||
|
||||
import "gitea.dev/modelmigration/base"
|
||||
|
||||
func AddTeamReviewRequestSupport(x base.EngineMigration) error {
|
||||
type Review struct {
|
||||
ReviewerTeamID int64 `xorm:"NOT NULL DEFAULT 0"`
|
||||
}
|
||||
|
||||
type Comment struct {
|
||||
AssigneeTeamID int64 `xorm:"NOT NULL DEFAULT 0"`
|
||||
}
|
||||
|
||||
if err := x.Sync(new(Review)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return x.Sync(new(Comment))
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package v1_13
|
||||
|
||||
import (
|
||||
"gitea.dev/modelmigration/base"
|
||||
"gitea.dev/modules/timeutil"
|
||||
)
|
||||
|
||||
func AddTimeStamps(x base.EngineMigration) error {
|
||||
// this will add timestamps where it is useful to have
|
||||
|
||||
// Star represents a starred repo by an user.
|
||||
type Star struct {
|
||||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
|
||||
}
|
||||
if err := x.Sync(new(Star)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Label represents a label of repository for issues.
|
||||
type Label struct {
|
||||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
|
||||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
|
||||
}
|
||||
if err := x.Sync(new(Label)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Follow represents relations of user and their followers.
|
||||
type Follow struct {
|
||||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
|
||||
}
|
||||
if err := x.Sync(new(Follow)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Watch is connection request for receiving repository notification.
|
||||
type Watch struct {
|
||||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
|
||||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
|
||||
}
|
||||
if err := x.Sync(new(Watch)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Collaboration represent the relation between an individual and a repository.
|
||||
type Collaboration struct {
|
||||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
|
||||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
|
||||
}
|
||||
return x.Sync(new(Collaboration))
|
||||
}
|
||||
Reference in New Issue
Block a user