Split migrations folder (#21549)

There are too many files in `models/migrations` folder so that I split
them into sub folders.
This commit is contained in:
Lunny Xiao 2022-11-02 16:54:36 +08:00 committed by GitHub
parent 4827f42f56
commit e72acd5e5b
Signed by: GitHub
GPG Key ID: 4AEE18F83AFDEB23
190 changed files with 1711 additions and 1481 deletions

View File

@ -100,7 +100,8 @@ LDFLAGS := $(LDFLAGS) -X "main.MakeVersion=$(MAKE_VERSION)" -X "main.Version=$(G
LINUX_ARCHS ?= linux/amd64,linux/386,linux/arm-5,linux/arm-6,linux/arm64
GO_PACKAGES ?= $(filter-out code.gitea.io/gitea/models/migrations code.gitea.io/gitea/tests/integration/migration-test code.gitea.io/gitea/tests code.gitea.io/gitea/tests/integration code.gitea.io/gitea/tests/e2e,$(shell $(GO) list ./... | grep -v /vendor/))
GO_PACKAGES ?= $(filter-out code.gitea.io/gitea/tests/integration/migration-test code.gitea.io/gitea/tests code.gitea.io/gitea/tests/integration code.gitea.io/gitea/tests/e2e,$(shell $(GO) list ./... | grep -v /vendor/))
GO_TEST_PACKAGES ?= $(filter-out $(shell $(GO) list code.gitea.io/gitea/models/migrations/...) code.gitea.io/gitea/tests/integration/migration-test code.gitea.io/gitea/tests code.gitea.io/gitea/tests/integration code.gitea.io/gitea/tests/e2e,$(shell $(GO) list ./... | grep -v /vendor/))
FOMANTIC_WORK_DIR := web_src/fomantic
@ -366,7 +367,7 @@ test: test-frontend test-backend
.PHONY: test-backend
test-backend:
@echo "Running go test with $(GOTESTFLAGS) -tags '$(TEST_TAGS)'..."
@$(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' $(GO_PACKAGES)
@$(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' $(GO_TEST_PACKAGES)
.PHONY: test-frontend
test-frontend: node_modules
@ -387,7 +388,7 @@ test-check:
.PHONY: test\#%
test\#%:
@echo "Running go test with -tags '$(TEST_TAGS)'..."
@$(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -run $(subst .,/,$*) $(GO_PACKAGES)
@$(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -run $(subst .,/,$*) $(GO_TEST_PACKAGES)
.PHONY: coverage
coverage:
@ -398,7 +399,7 @@ coverage:
.PHONY: unit-test-coverage
unit-test-coverage:
@echo "Running unit-test-coverage $(GOTESTFLAGS) -tags '$(TEST_TAGS)'..."
@$(GO) test $(GOTESTFLAGS) -timeout=20m -tags='$(TEST_TAGS)' -cover -coverprofile coverage.out $(GO_PACKAGES) && echo "\n==>\033[32m Ok\033[m\n" || exit 1
@$(GO) test $(GOTESTFLAGS) -timeout=20m -tags='$(TEST_TAGS)' -cover -coverprofile coverage.out $(GO_TEST_PACKAGES) && echo "\n==>\033[32m Ok\033[m\n" || exit 1
.PHONY: tidy
tidy:
@ -442,14 +443,7 @@ test-sqlite\#%: integrations.sqlite.test generate-ini-sqlite
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./integrations.sqlite.test -test.run $(subst .,/,$*)
.PHONY: test-sqlite-migration
test-sqlite-migration: migrations.sqlite.test migrations.individual.sqlite.test generate-ini-sqlite
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./migrations.sqlite.test
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./migrations.individual.sqlite.test
.PHONY: test-sqlite-migration\#%
test-sqlite-migration\#%: migrations.sqlite.test migrations.individual.sqlite.test generate-ini-sqlite
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./migrations.individual.sqlite.test -test.run $(subst .,/,$*)
test-sqlite-migration: migrations.sqlite.test migrations.individual.sqlite.test
generate-ini-mysql:
sed -e 's|{{TEST_MYSQL_HOST}}|${TEST_MYSQL_HOST}|g' \
@ -470,9 +464,7 @@ test-mysql\#%: integrations.mysql.test generate-ini-mysql
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini ./integrations.mysql.test -test.run $(subst .,/,$*)
.PHONY: test-mysql-migration
test-mysql-migration: migrations.mysql.test migrations.individual.mysql.test generate-ini-mysql
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini ./migrations.mysql.test
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini ./migrations.individual.mysql.test
test-mysql-migration: migrations.mysql.test migrations.individual.mysql.test
generate-ini-mysql8:
sed -e 's|{{TEST_MYSQL8_HOST}}|${TEST_MYSQL8_HOST}|g' \
@ -493,9 +485,7 @@ test-mysql8\#%: integrations.mysql8.test generate-ini-mysql8
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql8.ini ./integrations.mysql8.test -test.run $(subst .,/,$*)
.PHONY: test-mysql8-migration
test-mysql8-migration: migrations.mysql8.test migrations.individual.mysql8.test generate-ini-mysql8
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql8.ini ./migrations.mysql8.test
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql8.ini ./migrations.individual.mysql8.test
test-mysql8-migration: migrations.mysql8.test migrations.individual.mysql8.test
generate-ini-pgsql:
sed -e 's|{{TEST_PGSQL_HOST}}|${TEST_PGSQL_HOST}|g' \
@ -517,9 +507,7 @@ test-pgsql\#%: integrations.pgsql.test generate-ini-pgsql
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini ./integrations.pgsql.test -test.run $(subst .,/,$*)
.PHONY: test-pgsql-migration
test-pgsql-migration: migrations.pgsql.test migrations.individual.pgsql.test generate-ini-pgsql
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini ./migrations.pgsql.test
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini ./migrations.individual.pgsql.test
test-pgsql-migration: migrations.pgsql.test migrations.individual.pgsql.test
generate-ini-mssql:
sed -e 's|{{TEST_MSSQL_HOST}}|${TEST_MSSQL_HOST}|g' \
@ -540,9 +528,7 @@ test-mssql\#%: integrations.mssql.test generate-ini-mssql
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini ./integrations.mssql.test -test.run $(subst .,/,$*)
.PHONY: test-mssql-migration
test-mssql-migration: migrations.mssql.test migrations.individual.mssql.test generate-ini-mssql
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini ./migrations.mssql.test -test.failfast
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini ./migrations.individual.mssql.test -test.failfast
test-mssql-migration: migrations.mssql.test migrations.individual.mssql.test
.PHONY: playwright
playwright: $(PLAYWRIGHT_DIR)
@ -637,50 +623,82 @@ integrations.sqlite.test: git-check $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -o integrations.sqlite.test -tags '$(TEST_TAGS)'
integrations.cover.test: git-check $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -coverpkg $(shell echo $(GO_PACKAGES) | tr ' ' ',') -o integrations.cover.test
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -coverpkg $(shell echo $(GO_TEST_PACKAGES) | tr ' ' ',') -o integrations.cover.test
integrations.cover.sqlite.test: git-check $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -coverpkg $(shell echo $(GO_PACKAGES) | tr ' ' ',') -o integrations.cover.sqlite.test -tags '$(TEST_TAGS)'
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -coverpkg $(shell echo $(GO_TEST_PACKAGES) | tr ' ' ',') -o integrations.cover.sqlite.test -tags '$(TEST_TAGS)'
.PHONY: migrations.mysql.test
migrations.mysql.test: $(GO_SOURCES)
migrations.mysql.test: $(GO_SOURCES) generate-ini-mysql
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.mysql.test
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini ./migrations.mysql.test
.PHONY: migrations.mysql8.test
migrations.mysql8.test: $(GO_SOURCES)
migrations.mysql8.test: $(GO_SOURCES) generate-ini-mysql8
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.mysql8.test
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql8.ini ./migrations.mysql8.test
.PHONY: migrations.pgsql.test
migrations.pgsql.test: $(GO_SOURCES)
migrations.pgsql.test: $(GO_SOURCES) generate-ini-pgsql
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.pgsql.test
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini ./migrations.pgsql.test
.PHONY: migrations.mssql.test
migrations.mssql.test: $(GO_SOURCES)
migrations.mssql.test: $(GO_SOURCES) generate-ini-mssql
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.mssql.test
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini ./migrations.mssql.test
.PHONY: migrations.sqlite.test
migrations.sqlite.test: $(GO_SOURCES)
migrations.sqlite.test: $(GO_SOURCES) generate-ini-sqlite
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.sqlite.test -tags '$(TEST_TAGS)'
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./migrations.sqlite.test
.PHONY: migrations.individual.mysql.test
migrations.individual.mysql.test: $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/models/migrations -o migrations.individual.mysql.test
for pkg in $(shell $(GO) list code.gitea.io/gitea/models/migrations/...); do \
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' $$pkg; \
done
.PHONY: migrations.individual.mysql8.test
migrations.individual.mysql8.test: $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/models/migrations -o migrations.individual.mysql8.test
for pkg in $(shell $(GO) list code.gitea.io/gitea/models/migrations/...); do \
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql8.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' $$pkg; \
done
.PHONY: migrations.individual.mysql8.test\#%
migrations.individual.sqlite.test\#%: $(GO_SOURCES) generate-ini-sqlite
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$*
.PHONY: migrations.individual.pgsql.test
migrations.individual.pgsql.test: $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/models/migrations -o migrations.individual.pgsql.test
for pkg in $(shell $(GO) list code.gitea.io/gitea/models/migrations/...); do \
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' $$pkg; \
done
.PHONY: migrations.individual.pgsql.test\#%
migrations.individual.pgsql.test\#%: $(GO_SOURCES) generate-ini-pgsql
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$*
.PHONY: migrations.individual.mssql.test
migrations.individual.mssql.test: $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/models/migrations -o migrations.individual.mssql.test
migrations.individual.mssql.test: $(GO_SOURCES) generate-ini-mssql
for pkg in $(shell $(GO) list code.gitea.io/gitea/models/migrations/...); do \
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' $$pkg -test.failfast; \
done
.PHONY: migrations.individual.mssql.test\#%
migrations.individual.mssql.test\#%: $(GO_SOURCES) generate-ini-mssql
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$*
.PHONY: migrations.individual.sqlite.test
migrations.individual.sqlite.test: $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/models/migrations -o migrations.individual.sqlite.test -tags '$(TEST_TAGS)'
migrations.individual.sqlite.test: $(GO_SOURCES) generate-ini-sqlite
for pkg in $(shell $(GO) list code.gitea.io/gitea/models/migrations/...); do \
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' $$pkg; \
done
.PHONY: migrations.individual.sqlite.test\#%
migrations.individual.sqlite.test\#%: $(GO_SOURCES) generate-ini-sqlite
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$*
e2e.mysql.test: $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/e2e -o e2e.mysql.test

File diff suppressed because one or more lines are too long

View File

@ -14,6 +14,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/migrations"
migrate_base "code.gitea.io/gitea/models/migrations/base"
"code.gitea.io/gitea/modules/doctor"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
@ -114,7 +115,7 @@ func runRecreateTable(ctx *cli.Context) error {
if err != nil {
return err
}
recreateTables := migrations.RecreateTables(beans...)
recreateTables := migrate_base.RecreateTables(beans...)
return db.InitEngineWithMigration(stdCtx, func(x *xorm.Engine) error {
if err := migrations.EnsureUpToDate(x); err != nil {

View File

@ -0,0 +1,634 @@
// Copyright 2022 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 base
import (
"context"
"database/sql"
"errors"
"fmt"
"os"
"path"
"reflect"
"regexp"
"strings"
"time"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"xorm.io/xorm"
"xorm.io/xorm/schemas"
)
// RecreateTables will recreate the tables for the provided beans using the newly provided bean definition and move all data to that new table
// WARNING: YOU MUST PROVIDE THE FULL BEAN DEFINITION
func RecreateTables(beans ...interface{}) func(*xorm.Engine) error {
return func(x *xorm.Engine) error {
sess := x.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
return err
}
sess = sess.StoreEngine("InnoDB")
for _, bean := range beans {
log.Info("Recreating Table: %s for Bean: %s", x.TableName(bean), reflect.Indirect(reflect.ValueOf(bean)).Type().Name())
if err := RecreateTable(sess, bean); err != nil {
return err
}
}
return sess.Commit()
}
}
// RecreateTable will recreate the table using the newly provided bean definition and move all data to that new table
// WARNING: YOU MUST PROVIDE THE FULL BEAN DEFINITION
// WARNING: YOU MUST COMMIT THE SESSION AT THE END
func RecreateTable(sess *xorm.Session, bean interface{}) error {
// TODO: This will not work if there are foreign keys
tableName := sess.Engine().TableName(bean)
tempTableName := fmt.Sprintf("tmp_recreate__%s", tableName)
// We need to move the old table away and create a new one with the correct columns
// We will need to do this in stages to prevent data loss
//
// First create the temporary table
if err := sess.Table(tempTableName).CreateTable(bean); err != nil {
log.Error("Unable to create table %s. Error: %v", tempTableName, err)
return err
}
if err := sess.Table(tempTableName).CreateUniques(bean); err != nil {
log.Error("Unable to create uniques for table %s. Error: %v", tempTableName, err)
return err
}
if err := sess.Table(tempTableName).CreateIndexes(bean); err != nil {
log.Error("Unable to create indexes for table %s. Error: %v", tempTableName, err)
return err
}
// Work out the column names from the bean - these are the columns to select from the old table and install into the new table
table, err := sess.Engine().TableInfo(bean)
if err != nil {
log.Error("Unable to get table info. Error: %v", err)
return err
}
newTableColumns := table.Columns()
if len(newTableColumns) == 0 {
return fmt.Errorf("no columns in new table")
}
hasID := false
for _, column := range newTableColumns {
hasID = hasID || (column.IsPrimaryKey && column.IsAutoIncrement)
}
if hasID && setting.Database.UseMSSQL {
if _, err := sess.Exec(fmt.Sprintf("SET IDENTITY_INSERT `%s` ON", tempTableName)); err != nil {
log.Error("Unable to set identity insert for table %s. Error: %v", tempTableName, err)
return err
}
}
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
}
if hasID && setting.Database.UseMSSQL {
if _, err := sess.Exec(fmt.Sprintf("SET IDENTITY_INSERT `%s` OFF", tempTableName)); err != nil {
log.Error("Unable to switch off identity insert for table %s. Error: %v", tempTableName, err)
return err
}
}
switch {
case setting.Database.UseSQLite3:
// 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
}
if err := sess.Table(tempTableName).DropIndexes(bean); 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
}
if err := sess.Table(tableName).CreateIndexes(bean); err != nil {
log.Error("Unable to recreate indexes on table %s. Error: %v", tableName, err)
return err
}
if err := sess.Table(tableName).CreateUniques(bean); err != nil {
log.Error("Unable to recreate uniques on table %s. Error: %v", tableName, err)
return err
}
case setting.Database.UseMySQL:
// MySQL 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
}
if err := sess.Table(tempTableName).DropIndexes(bean); err != nil {
log.Error("Unable to drop indexes on temporary table %s. Error: %v", tempTableName, err)
return err
}
// SQLite and MySQL will move all the constraints from the temporary table to the new table
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
}
if err := sess.Table(tableName).CreateIndexes(bean); err != nil {
log.Error("Unable to recreate indexes on table %s. Error: %v", tableName, err)
return err
}
if err := sess.Table(tableName).CreateUniques(bean); err != nil {
log.Error("Unable to recreate uniques on table %s. Error: %v", tableName, err)
return err
}
case setting.Database.UsePostgreSQL:
var originalSequences []string
type sequenceData struct {
LastValue int `xorm:"'last_value'"`
IsCalled bool `xorm:"'is_called'"`
}
sequenceMap := map[string]sequenceData{}
schema := sess.Engine().Dialect().URI().Schema
sess.Engine().SetSchema("")
if err := sess.Table("information_schema.sequences").Cols("sequence_name").Where("sequence_name LIKE ? || '_%' AND sequence_catalog = ?", tableName, setting.Database.Name).Find(&originalSequences); err != nil {
log.Error("Unable to rename %s to %s. Error: %v", tempTableName, tableName, err)
return err
}
sess.Engine().SetSchema(schema)
for _, sequence := range originalSequences {
sequenceData := sequenceData{}
if _, err := sess.Table(sequence).Cols("last_value", "is_called").Get(&sequenceData); err != nil {
log.Error("Unable to get last_value and is_called from %s. Error: %v", sequence, err)
return err
}
sequenceMap[sequence] = sequenceData
}
// CASCADE causes postgres to drop all the constraints on the old table
if _, err := sess.Exec(fmt.Sprintf("DROP TABLE `%s` CASCADE", tableName)); err != nil {
log.Error("Unable to drop old table %s. Error: %v", tableName, err)
return err
}
// CASCADE causes postgres to move all the constraints from the temporary table to the new table
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
}
var indices []string
sess.Engine().SetSchema("")
if err := sess.Table("pg_indexes").Cols("indexname").Where("tablename = ? ", tableName).Find(&indices); err != nil {
log.Error("Unable to rename %s to %s. Error: %v", tempTableName, tableName, err)
return err
}
sess.Engine().SetSchema(schema)
for _, index := range indices {
newIndexName := strings.Replace(index, "tmp_recreate__", "", 1)
if _, err := sess.Exec(fmt.Sprintf("ALTER INDEX `%s` RENAME TO `%s`", index, newIndexName)); err != nil {
log.Error("Unable to rename %s to %s. Error: %v", index, newIndexName, err)
return err
}
}
var sequences []string
sess.Engine().SetSchema("")
if err := sess.Table("information_schema.sequences").Cols("sequence_name").Where("sequence_name LIKE 'tmp_recreate__' || ? || '_%' AND sequence_catalog = ?", tableName, setting.Database.Name).Find(&sequences); err != nil {
log.Error("Unable to rename %s to %s. Error: %v", tempTableName, tableName, err)
return err
}
sess.Engine().SetSchema(schema)
for _, sequence := range sequences {
newSequenceName := strings.Replace(sequence, "tmp_recreate__", "", 1)
if _, err := sess.Exec(fmt.Sprintf("ALTER SEQUENCE `%s` RENAME TO `%s`", sequence, newSequenceName)); err != nil {
log.Error("Unable to rename %s sequence to %s. Error: %v", sequence, newSequenceName, err)
return err
}
val, ok := sequenceMap[newSequenceName]
if newSequenceName == tableName+"_id_seq" {
if ok && val.LastValue != 0 {
if _, err := sess.Exec(fmt.Sprintf("SELECT setval('%s', %d, %t)", newSequenceName, val.LastValue, val.IsCalled)); err != nil {
log.Error("Unable to reset %s to %d. Error: %v", newSequenceName, val, err)
return err
}
} else {
// We're going to try to guess this
if _, err := sess.Exec(fmt.Sprintf("SELECT setval('%s', COALESCE((SELECT MAX(id)+1 FROM `%s`), 1), false)", newSequenceName, tableName)); err != nil {
log.Error("Unable to reset %s. Error: %v", newSequenceName, err)
return err
}
}
} else if ok {
if _, err := sess.Exec(fmt.Sprintf("SELECT setval('%s', %d, %t)", newSequenceName, val.LastValue, val.IsCalled)); err != nil {
log.Error("Unable to reset %s to %d. Error: %v", newSequenceName, val, err)
return err
}
}
}
case setting.Database.UseMSSQL:
// MSSQL 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
}
// MSSQL sp_rename will move all the constraints from the temporary table to the new table
if _, err := sess.Exec(fmt.Sprintf("sp_rename `%s`,`%s`", tempTableName, tableName)); err != nil {
log.Error("Unable to rename %s to %s. Error: %v", tempTableName, tableName, err)
return err
}
default:
log.Fatal("Unrecognized DB")
}
return nil
}
// WARNING: YOU MUST COMMIT THE SESSION AT THE END
func DropTableColumns(sess *xorm.Session, tableName string, columnNames ...string) (err error) {
if tableName == "" || len(columnNames) == 0 {
return nil
}
// TODO: This will not work if there are foreign keys
switch {
case setting.Database.UseSQLite3:
// First drop the indexes on the columns
res, errIndex := sess.Query(fmt.Sprintf("PRAGMA index_list(`%s`)", tableName))
if errIndex != nil {
return errIndex
}
for _, row := range res {
indexName := row["name"]
indexRes, err := sess.Query(fmt.Sprintf("PRAGMA index_info(`%s`)", indexName))
if err != nil {
return err
}
if len(indexRes) != 1 {
continue
}
indexColumn := string(indexRes[0]["name"])
for _, name := range columnNames {
if name == indexColumn {
_, err := sess.Exec(fmt.Sprintf("DROP INDEX `%s`", indexName))
if err != nil {
return err
}
}
}
}
// Here we need to get the columns from the original table
sql := fmt.Sprintf("SELECT sql FROM sqlite_master WHERE tbl_name='%s' and type='table'", tableName)
res, err := sess.Query(sql)
if err != nil {
return err
}
tableSQL := string(res[0]["sql"])
// Get the string offset for column definitions: `CREATE TABLE ( column-definitions... )`
columnDefinitionsIndex := strings.Index(tableSQL, "(")
if columnDefinitionsIndex < 0 {
return errors.New("couldn't find column definitions")
}
// Separate out the column definitions
tableSQL = tableSQL[columnDefinitionsIndex:]
// Remove the required columnNames
for _, name := range columnNames {
tableSQL = regexp.MustCompile(regexp.QuoteMeta("`"+name+"`")+"[^`,)]*?[,)]").ReplaceAllString(tableSQL, "")
}
// Ensure the query is ended properly
tableSQL = strings.TrimSpace(tableSQL)
if tableSQL[len(tableSQL)-1] != ')' {
if tableSQL[len(tableSQL)-1] == ',' {
tableSQL = tableSQL[:len(tableSQL)-1]
}
tableSQL += ")"
}
// Find all the columns in the table
columns := regexp.MustCompile("`([^`]*)`").FindAllString(tableSQL, -1)
tableSQL = fmt.Sprintf("CREATE TABLE `new_%s_new` ", tableName) + tableSQL
if _, err := sess.Exec(tableSQL); err != nil {
return err
}
// Now restore the data
columnsSeparated := strings.Join(columns, ",")
insertSQL := fmt.Sprintf("INSERT INTO `new_%s_new` (%s) SELECT %s FROM %s", tableName, columnsSeparated, columnsSeparated, tableName)
if _, err := sess.Exec(insertSQL); err != nil {
return err
}
// Now drop the old table
if _, err := sess.Exec(fmt.Sprintf("DROP TABLE `%s`", tableName)); err != nil {
return err
}
// Rename the table
if _, err := sess.Exec(fmt.Sprintf("ALTER TABLE `new_%s_new` RENAME TO `%s`", tableName, tableName)); err != nil {
return err
}
case setting.Database.UsePostgreSQL:
cols := ""
for _, col := range columnNames {
if cols != "" {
cols += ", "
}
cols += "DROP COLUMN `" + col + "` CASCADE"
}
if _, err := sess.Exec(fmt.Sprintf("ALTER TABLE `%s` %s", tableName, cols)); err != nil {
return fmt.Errorf("Drop table `%s` columns %v: %v", tableName, columnNames, err)
}
case setting.Database.UseMySQL:
// Drop indexes on columns first
sql := fmt.Sprintf("SHOW INDEX FROM %s WHERE column_name IN ('%s')", tableName, strings.Join(columnNames, "','"))
res, err := sess.Query(sql)
if err != nil {
return err
}
for _, index := range res {
indexName := index["column_name"]
if len(indexName) > 0 {
_, err := sess.Exec(fmt.Sprintf("DROP INDEX `%s` ON `%s`", indexName, tableName))
if err != nil {
return err
}
}
}
// Now drop the columns
cols := ""
for _, col := range columnNames {
if cols != "" {
cols += ", "
}
cols += "DROP COLUMN `" + col + "`"
}
if _, err := sess.Exec(fmt.Sprintf("ALTER TABLE `%s` %s", tableName, cols)); err != nil {
return fmt.Errorf("Drop table `%s` columns %v: %v", tableName, columnNames, err)
}
case setting.Database.UseMSSQL:
cols := ""
for _, col := range columnNames {
if cols != "" {
cols += ", "
}
cols += "`" + strings.ToLower(col) + "`"
}
sql := fmt.Sprintf("SELECT Name FROM sys.default_constraints WHERE parent_object_id = OBJECT_ID('%[1]s') AND parent_column_id IN (SELECT column_id FROM sys.columns WHERE LOWER(name) IN (%[2]s) AND object_id = OBJECT_ID('%[1]s'))",
tableName, strings.ReplaceAll(cols, "`", "'"))
constraints := make([]string, 0)
if err := sess.SQL(sql).Find(&constraints); err != nil {
return fmt.Errorf("Find constraints: %v", err)
}
for _, constraint := range constraints {
if _, err := sess.Exec(fmt.Sprintf("ALTER TABLE `%s` DROP CONSTRAINT `%s`", tableName, constraint)); err != nil {
return fmt.Errorf("Drop table `%s` default constraint `%s`: %v", tableName, constraint, err)
}
}
sql = fmt.Sprintf("SELECT DISTINCT Name FROM sys.indexes INNER JOIN sys.index_columns ON indexes.index_id = index_columns.index_id AND indexes.object_id = index_columns.object_id WHERE indexes.object_id = OBJECT_ID('%[1]s') AND index_columns.column_id IN (SELECT column_id FROM sys.columns WHERE LOWER(name) IN (%[2]s) AND object_id = OBJECT_ID('%[1]s'))",
tableName, strings.ReplaceAll(cols, "`", "'"))
constraints = make([]string, 0)
if err := sess.SQL(sql).Find(&constraints); err != nil {
return fmt.Errorf("Find constraints: %v", err)
}
for _, constraint := range constraints {
if _, err := sess.Exec(fmt.Sprintf("DROP INDEX `%[2]s` ON `%[1]s`", tableName, constraint)); err != nil {
return fmt.Errorf("Drop index `%[2]s` on `%[1]s`: %v", tableName, constraint, err)
}
}
if _, err := sess.Exec(fmt.Sprintf("ALTER TABLE `%s` DROP COLUMN %s", tableName, cols)); err != nil {
return fmt.Errorf("Drop table `%s` columns %v: %v", tableName, columnNames, err)
}
default:
log.Fatal("Unrecognized DB")
}
return nil
}
// ModifyColumn will modify column's type or other property. SQLITE is not supported
func ModifyColumn(x *xorm.Engine, tableName string, col *schemas.Column) error {
var indexes map[string]*schemas.Index
var err error
// MSSQL have to remove index at first, otherwise alter column will fail
// ref. https://sqlzealots.com/2018/05/09/error-message-the-index-is-dependent-on-column-alter-table-alter-column-failed-because-one-or-more-objects-access-this-column/
if x.Dialect().URI().DBType == schemas.MSSQL {
indexes, err = x.Dialect().GetIndexes(x.DB(), context.Background(), tableName)
if err != nil {
return err
}
for _, index := range indexes {
_, err = x.Exec(x.Dialect().DropIndexSQL(tableName, index))
if err != nil {
return err
}
}
}
defer func() {
for _, index := range indexes {
_, err = x.Exec(x.Dialect().CreateIndexSQL(tableName, index))
if err != nil {
log.Error("Create index %s on table %s failed: %v", index.Name, tableName, err)
}
}
}()
alterSQL := x.Dialect().ModifyColumnSQL(tableName, col)
if _, err := x.Exec(alterSQL); err != nil {
return err
}
return nil
}
func removeAllWithRetry(dir string) error {
var err error
for i := 0; i < 20; i++ {
err = os.RemoveAll(dir)
if err == nil {
break
}
time.Sleep(100 * time.Millisecond)
}
return err
}
func newXORMEngine() (*xorm.Engine, error) {
if err := db.InitEngine(context.Background()); err != nil {
return nil, err
}
x := unittest.GetXORMEngine()
return x, nil
}
func deleteDB() error {
switch {
case setting.Database.UseSQLite3:
if err := util.Remove(setting.Database.Path); err != nil {
return err
}
return os.MkdirAll(path.Dir(setting.Database.Path), os.ModePerm)
case setting.Database.UseMySQL:
db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s)/",
setting.Database.User, setting.Database.Passwd, setting.Database.Host))
if err != nil {
return err
}
defer db.Close()
if _, err = db.Exec(fmt.Sprintf("DROP DATABASE IF EXISTS %s", setting.Database.Name)); err != nil {
return err
}
if _, err = db.Exec(fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s", setting.Database.Name)); err != nil {
return err
}
return nil
case setting.Database.UsePostgreSQL:
db, err := sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@%s/?sslmode=%s",
setting.Database.User, setting.Database.Passwd, setting.Database.Host, setting.Database.SSLMode))
if err != nil {
return err
}
defer db.Close()
if _, err = db.Exec(fmt.Sprintf("DROP DATABASE IF EXISTS %s", setting.Database.Name)); err != nil {
return err
}
if _, err = db.Exec(fmt.Sprintf("CREATE DATABASE %s", setting.Database.Name)); err != nil {
return err
}
db.Close()
// Check if we need to setup a specific schema
if len(setting.Database.Schema) != 0 {
db, err = sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@%s/%s?sslmode=%s",
setting.Database.User, setting.Database.Passwd, setting.Database.Host, setting.Database.Name, setting.Database.SSLMode))
if err != nil {
return err
}
defer db.Close()
schrows, err := db.Query(fmt.Sprintf("SELECT 1 FROM information_schema.schemata WHERE schema_name = '%s'", setting.Database.Schema))
if err != nil {
return err
}
defer schrows.Close()
if !schrows.Next() {
// Create and setup a DB schema
_, err = db.Exec(fmt.Sprintf("CREATE SCHEMA %s", setting.Database.Schema))
if err != nil {
return err
}
}
// Make the user's default search path the created schema; this will affect new connections
_, err = db.Exec(fmt.Sprintf(`ALTER USER "%s" SET search_path = %s`, setting.Database.User, setting.Database.Schema))
if err != nil {
return err
}
return nil
}
case setting.Database.UseMSSQL:
host, port := setting.ParseMSSQLHostPort(setting.Database.Host)
db, err := sql.Open("mssql", fmt.Sprintf("server=%s; port=%s; database=%s; user id=%s; password=%s;",
host, port, "master", setting.Database.User, setting.Database.Passwd))
if err != nil {
return err
}
defer db.Close()
if _, err = db.Exec(fmt.Sprintf("DROP DATABASE IF EXISTS [%s]", setting.Database.Name)); err != nil {
return err
}
if _, err = db.Exec(fmt.Sprintf("CREATE DATABASE [%s]", setting.Database.Name)); err != nil {
return err
}
}
return nil
}

View File

@ -0,0 +1,97 @@
// Copyright 2022 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 base
import (
"testing"
"code.gitea.io/gitea/modules/timeutil"
"xorm.io/xorm/names"
)
func Test_DropTableColumns(t *testing.T) {
x, deferable := PrepareTestEnv(t, 0)
if x == nil || t.Failed() {
defer deferable()
return
}
defer deferable()
type DropTest struct {
ID int64 `xorm:"pk autoincr"`
FirstColumn string
ToDropColumn string `xorm:"unique"`
AnotherColumn int64
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
}
columns := []string{
"first_column",
"to_drop_column",
"another_column",
"created_unix",
"updated_unix",
}
for i := range columns {
x.SetMapper(names.GonicMapper{})
if err := x.Sync2(new(DropTest)); err != nil {
t.Errorf("unable to create DropTest table: %v", err)
return
}
sess := x.NewSession()
if err := sess.Begin(); err != nil {
sess.Close()
t.Errorf("unable to begin transaction: %v", err)
return
}
if err := DropTableColumns(sess, "drop_test", columns[i:]...); err != nil {
sess.Close()
t.Errorf("Unable to drop columns[%d:]: %s from drop_test: %v", i, columns[i:], err)
return
}
if err := sess.Commit(); err != nil {
sess.Close()
t.Errorf("unable to commit transaction: %v", err)
return
}
sess.Close()
if err := x.DropTables(new(DropTest)); err != nil {
t.Errorf("unable to drop table: %v", err)
return
}
for j := range columns[i+1:] {
x.SetMapper(names.GonicMapper{})
if err := x.Sync2(new(DropTest)); err != nil {
t.Errorf("unable to create DropTest table: %v", err)
return
}
dropcols := append([]string{columns[i]}, columns[j+i+1:]...)
sess := x.NewSession()
if err := sess.Begin(); err != nil {
sess.Close()
t.Errorf("unable to begin transaction: %v", err)
return
}
if err := DropTableColumns(sess, "drop_test", dropcols...); err != nil {
sess.Close()
t.Errorf("Unable to drop columns: %s from drop_test: %v", dropcols, err)
return
}
if err := sess.Commit(); err != nil {
sess.Close()
t.Errorf("unable to commit transaction: %v", err)
return
}
sess.Close()
if err := x.DropTables(new(DropTest)); err != nil {
t.Errorf("unable to drop table: %v", err)
return
}
}
}
}

View File

@ -0,0 +1,17 @@
// Copyright 2022 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 base
import (
"crypto/sha256"
"fmt"
"golang.org/x/crypto/pbkdf2"
)
func HashToken(token, salt string) string {
tempHash := pbkdf2.Key([]byte(token), []byte(salt), 10000, 50, sha256.New)
return fmt.Sprintf("%x", tempHash)
}

View File

@ -0,0 +1,13 @@
// 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 base
import (
"testing"
)
func TestMain(m *testing.M) {
MainTest(m)
}

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package base
import (
"context"
@ -184,9 +184,3 @@ func (log *TestLogger) ReleaseReopen() error {
func (log *TestLogger) GetName() string {
return "test"
}
func init() {
log.Register("test", NewTestLogger)
_, filename, _, _ := runtime.Caller(0)
prefix = strings.TrimSuffix(filename, "tests/testlogger.go")
}

View File

@ -0,0 +1,170 @@
// Copyright 2022 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 base
import (
"context"
"fmt"
"os"
"path"
"path/filepath"
"runtime"
"strings"
"testing"
"code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"github.com/stretchr/testify/assert"
"xorm.io/xorm"
)
// PrepareTestEnv prepares the test environment and reset the database. The skip parameter should usually be 0.
// Provide models to be sync'd with the database - in particular any models you expect fixtures to be loaded from.
//
// fixtures in `models/migrations/fixtures/<TestName>` will be loaded automatically
func PrepareTestEnv(t *testing.T, skip int, syncModels ...interface{}) (*xorm.Engine, func()) {
t.Helper()
ourSkip := 2
ourSkip += skip
deferFn := PrintCurrentTest(t, ourSkip)
assert.NoError(t, os.RemoveAll(setting.RepoRootPath))
assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "tests/gitea-repositories-meta"), setting.RepoRootPath))
ownerDirs, err := os.ReadDir(setting.RepoRootPath)
if err != nil {
assert.NoError(t, err, "unable to read the new repo root: %v\n", err)
}
for _, ownerDir := range ownerDirs {
if !ownerDir.Type().IsDir() {
continue
}
repoDirs, err := os.ReadDir(filepath.Join(setting.RepoRootPath, ownerDir.Name()))
if err != nil {
assert.NoError(t, err, "unable to read the new repo root: %v\n", err)
}
for _, repoDir := range repoDirs {
_ = os.MkdirAll(filepath.Join(setting.RepoRootPath, ownerDir.Name(), repoDir.Name(), "objects", "pack"), 0o755)
_ = os.MkdirAll(filepath.Join(setting.RepoRootPath, ownerDir.Name(), repoDir.Name(), "objects", "info"), 0o755)
_ = os.MkdirAll(filepath.Join(setting.RepoRootPath, ownerDir.Name(), repoDir.Name(), "refs", "heads"), 0o755)
_ = os.MkdirAll(filepath.Join(setting.RepoRootPath, ownerDir.Name(), repoDir.Name(), "refs", "tag"), 0o755)
}
}
if err := deleteDB(); err != nil {
t.Errorf("unable to reset database: %v", err)
return nil, deferFn
}
x, err := newXORMEngine()
assert.NoError(t, err)
if x != nil {
oldDefer := deferFn
deferFn = func() {
oldDefer()
if err := x.Close(); err != nil {
t.Errorf("error during close: %v", err)
}
if err := deleteDB(); err != nil {
t.Errorf("unable to reset database: %v", err)
}
}
}
if err != nil {
return x, deferFn
}
if len(syncModels) > 0 {
if err := x.Sync2(syncModels...); err != nil {
t.Errorf("error during sync: %v", err)
return x, deferFn
}
}
fixturesDir := filepath.Join(filepath.Dir(setting.AppPath), "models", "migrations", "fixtures", t.Name())
if _, err := os.Stat(fixturesDir); err == nil {
t.Logf("initializing fixtures from: %s", fixturesDir)
if err := unittest.InitFixtures(
unittest.FixturesOptions{
Dir: fixturesDir,
}, x); err != nil {
t.Errorf("error whilst initializing fixtures from %s: %v", fixturesDir, err)
return x, deferFn
}
if err := unittest.LoadFixtures(x); err != nil {
t.Errorf("error whilst loading fixtures from %s: %v", fixturesDir, err)
return x, deferFn
}
} else if !os.IsNotExist(err) {
t.Errorf("unexpected error whilst checking for existence of fixtures: %v", err)
} else {
t.Logf("no fixtures found in: %s", fixturesDir)
}
return x, deferFn
}
func MainTest(m *testing.M) {
log.Register("test", NewTestLogger)
_, filename, _, _ := runtime.Caller(0)
prefix = strings.TrimSuffix(filename, "tests/testlogger.go")
giteaRoot := base.SetupGiteaRoot()
if giteaRoot == "" {
fmt.Println("Environment variable $GITEA_ROOT not set")
os.Exit(1)
}
giteaBinary := "gitea"
if runtime.GOOS == "windows" {
giteaBinary += ".exe"
}
setting.AppPath = path.Join(giteaRoot, giteaBinary)
if _, err := os.Stat(setting.AppPath); err != nil {
fmt.Printf("Could not find gitea binary at %s\n", setting.AppPath)
os.Exit(1)
}
giteaConf := os.Getenv("GITEA_CONF")
if giteaConf == "" {
giteaConf = path.Join(filepath.Dir(setting.AppPath), "tests/sqlite.ini")
fmt.Printf("Environment variable $GITEA_CONF not set - defaulting to %s\n", giteaConf)
}
if !path.IsAbs(giteaConf) {
setting.CustomConf = path.Join(giteaRoot, giteaConf)
} else {
setting.CustomConf = giteaConf
}
tmpDataPath, err := os.MkdirTemp("", "data")
if err != nil {
fmt.Printf("Unable to create temporary data path %v\n", err)
os.Exit(1)
}
setting.AppDataPath = tmpDataPath
setting.SetCustomPathAndConf("", "", "")
setting.LoadForTest()
if err = git.InitFull(context.Background()); err != nil {
fmt.Printf("Unable to InitFull: %v\n", err)
os.Exit(1)
}
setting.InitDBConfig()
setting.NewLogServices(true)
exitStatus := m.Run()
if err := removeAllWithRetry(setting.RepoRootPath); err != nil {
fmt.Fprintf(os.Stderr, "os.RemoveAll: %v\n", err)
}
if err := removeAllWithRetry(tmpDataPath); err != nil {
fmt.Fprintf(os.Stderr, "os.RemoveAll: %v\n", err)
}
os.Exit(exitStatus)
}

View File

@ -6,20 +6,28 @@
package migrations
import (
"context"
"errors"
"fmt"
"os"
"reflect"
"regexp"
"strings"
"code.gitea.io/gitea/models/migrations/v1_10"
"code.gitea.io/gitea/models/migrations/v1_11"
"code.gitea.io/gitea/models/migrations/v1_12"
"code.gitea.io/gitea/models/migrations/v1_13"
"code.gitea.io/gitea/models/migrations/v1_14"
"code.gitea.io/gitea/models/migrations/v1_15"
"code.gitea.io/gitea/models/migrations/v1_16"
"code.gitea.io/gitea/models/migrations/v1_17"
"code.gitea.io/gitea/models/migrations/v1_18"
"code.gitea.io/gitea/models/migrations/v1_19"
"code.gitea.io/gitea/models/migrations/v1_6"
"code.gitea.io/gitea/models/migrations/v1_7"
"code.gitea.io/gitea/models/migrations/v1_8"
"code.gitea.io/gitea/models/migrations/v1_9"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"xorm.io/xorm"
"xorm.io/xorm/names"
"xorm.io/xorm/schemas"
)
const minDBVersion = 70 // Gitea 1.5.3
@ -66,365 +74,365 @@ var migrations = []Migration{
// Gitea 1.5.0 ends at v69
// v70 -> v71
NewMigration("add issue_dependencies", addIssueDependencies),
NewMigration("add issue_dependencies", v1_6.AddIssueDependencies),
// v71 -> v72
NewMigration("protect each scratch token", addScratchHash),
NewMigration("protect each scratch token", v1_6.AddScratchHash),
// v72 -> v73
NewMigration("add review", addReview),
NewMigration("add review", v1_6.AddReview),
// Gitea 1.6.0 ends at v73
// v73 -> v74
NewMigration("add must_change_password column for users table", addMustChangePassword),
NewMigration("add must_change_password column for users table", v1_7.AddMustChangePassword),
// v74 -> v75
NewMigration("add approval whitelists to protected branches", addApprovalWhitelistsToProtectedBranches),
NewMigration("add approval whitelists to protected branches", v1_7.AddApprovalWhitelistsToProtectedBranches),
// v75 -> v76
NewMigration("clear nonused data which not deleted when user was deleted", clearNonusedData),
NewMigration("clear nonused data which not deleted when user was deleted", v1_7.ClearNonusedData),
// Gitea 1.7.0 ends at v76
// v76 -> v77
NewMigration("add pull request rebase with merge commit", addPullRequestRebaseWithMerge),
NewMigration("add pull request rebase with merge commit", v1_8.AddPullRequestRebaseWithMerge),
// v77 -> v78
NewMigration("add theme to users", addUserDefaultTheme),
NewMigration("add theme to users", v1_8.AddUserDefaultTheme),
// v78 -> v79
NewMigration("rename repo is_bare to repo is_empty", renameRepoIsBareToIsEmpty),
NewMigration("rename repo is_bare to repo is_empty", v1_8.RenameRepoIsBareToIsEmpty),
// v79 -> v80
NewMigration("add can close issues via commit in any branch", addCanCloseIssuesViaCommitInAnyBranch),
NewMigration("add can close issues via commit in any branch", v1_8.AddCanCloseIssuesViaCommitInAnyBranch),
// v80 -> v81
NewMigration("add is locked to issues", addIsLockedToIssues),
NewMigration("add is locked to issues", v1_8.AddIsLockedToIssues),
// v81 -> v82
NewMigration("update U2F counter type", changeU2FCounterType),
NewMigration("update U2F counter type", v1_8.ChangeU2FCounterType),
// Gitea 1.8.0 ends at v82
// v82 -> v83
NewMigration("hot fix for wrong release sha1 on release table", fixReleaseSha1OnReleaseTable),
NewMigration("hot fix for wrong release sha1 on release table", v1_9.FixReleaseSha1OnReleaseTable),
// v83 -> v84
NewMigration("add uploader id for table attachment", addUploaderIDForAttachment),
NewMigration("add uploader id for table attachment", v1_9.AddUploaderIDForAttachment),
// v84 -> v85
NewMigration("add table to store original imported gpg keys", addGPGKeyImport),
NewMigration("add table to store original imported gpg keys", v1_9.AddGPGKeyImport),
// v85 -> v86
NewMigration("hash application token", hashAppToken),
NewMigration("hash application token", v1_9.HashAppToken),
// v86 -> v87
NewMigration("add http method to webhook", addHTTPMethodToWebhook),
NewMigration("add http method to webhook", v1_9.AddHTTPMethodToWebhook),
// v87 -> v88
NewMigration("add avatar field to repository", addAvatarFieldToRepository),
NewMigration("add avatar field to repository", v1_9.AddAvatarFieldToRepository),
// Gitea 1.9.0 ends at v88
// v88 -> v89
NewMigration("add commit status context field to commit_status", addCommitStatusContext),
NewMigration("add commit status context field to commit_status", v1_10.AddCommitStatusContext),
// v89 -> v90
NewMigration("add original author/url migration info to issues, comments, and repo ", addOriginalMigrationInfo),
NewMigration("add original author/url migration info to issues, comments, and repo ", v1_10.AddOriginalMigrationInfo),
// v90 -> v91
NewMigration("change length of some repository columns", changeSomeColumnsLengthOfRepo),
NewMigration("change length of some repository columns", v1_10.ChangeSomeColumnsLengthOfRepo),
// v91 -> v92
NewMigration("add index on owner_id of repository and type, review_id of comment", addIndexOnRepositoryAndComment),
NewMigration("add index on owner_id of repository and type, review_id of comment", v1_10.AddIndexOnRepositoryAndComment),
// v92 -> v93
NewMigration("remove orphaned repository index statuses", removeLingeringIndexStatus),
NewMigration("remove orphaned repository index statuses", v1_10.RemoveLingeringIndexStatus),
// v93 -> v94
NewMigration("add email notification enabled preference to user", addEmailNotificationEnabledToUser),
NewMigration("add email notification enabled preference to user", v1_10.AddEmailNotificationEnabledToUser),
// v94 -> v95
NewMigration("add enable_status_check, status_check_contexts to protected_branch", addStatusCheckColumnsForProtectedBranches),
NewMigration("add enable_status_check, status_check_contexts to protected_branch", v1_10.AddStatusCheckColumnsForProtectedBranches),
// v95 -> v96
NewMigration("add table columns for cross referencing issues", addCrossReferenceColumns),
NewMigration("add table columns for cross referencing issues", v1_10.AddCrossReferenceColumns),
// v96 -> v97
NewMigration("delete orphaned attachments", deleteOrphanedAttachments),
NewMigration("delete orphaned attachments", v1_10.DeleteOrphanedAttachments),
// v97 -> v98
NewMigration("add repo_admin_change_team_access to user", addRepoAdminChangeTeamAccessColumnForUser),
NewMigration("add repo_admin_change_team_access to user", v1_10.AddRepoAdminChangeTeamAccessColumnForUser),
// v98 -> v99
NewMigration("add original author name and id on migrated release", addOriginalAuthorOnMigratedReleases),
NewMigration("add original author name and id on migrated release", v1_10.AddOriginalAuthorOnMigratedReleases),
// v99 -> v100
NewMigration("add task table and status column for repository table", addTaskTable),
NewMigration("add task table and status column for repository table", v1_10.AddTaskTable),
// v100 -> v101
NewMigration("update migration repositories' service type", updateMigrationServiceTypes),
NewMigration("update migration repositories' service type", v1_10.UpdateMigrationServiceTypes),
// v101 -> v102
NewMigration("change length of some external login users columns", changeSomeColumnsLengthOfExternalLoginUser),
NewMigration("change length of some external login users columns", v1_10.ChangeSomeColumnsLengthOfExternalLoginUser),
// Gitea 1.10.0 ends at v102
// v102 -> v103
NewMigration("update migration repositories' service type", dropColumnHeadUserNameOnPullRequest),
NewMigration("update migration repositories' service type", v1_11.DropColumnHeadUserNameOnPullRequest),
// v103 -> v104
NewMigration("Add WhitelistDeployKeys to protected branch", addWhitelistDeployKeysToBranches),
NewMigration("Add WhitelistDeployKeys to protected branch", v1_11.AddWhitelistDeployKeysToBranches),
// v104 -> v105
NewMigration("remove unnecessary columns from label", removeLabelUneededCols),
NewMigration("remove unnecessary columns from label", v1_11.RemoveLabelUneededCols),
// v105 -> v106
NewMigration("add includes_all_repositories to teams", addTeamIncludesAllRepositories),
NewMigration("add includes_all_repositories to teams", v1_11.AddTeamIncludesAllRepositories),
// v106 -> v107
NewMigration("add column `mode` to table watch", addModeColumnToWatch),
NewMigration("add column `mode` to table watch", v1_11.AddModeColumnToWatch),
// v107 -> v108
NewMigration("Add template options to repository", addTemplateToRepo),
NewMigration("Add template options to repository", v1_11.AddTemplateToRepo),
// v108 -> v109
NewMigration("Add comment_id on table notification", addCommentIDOnNotification),
NewMigration("Add comment_id on table notification", v1_11.AddCommentIDOnNotification),
// v109 -> v110
NewMigration("add can_create_org_repo to team", addCanCreateOrgRepoColumnForTeam),
NewMigration("add can_create_org_repo to team", v1_11.AddCanCreateOrgRepoColumnForTeam),
// v110 -> v111
NewMigration("change review content type to text", changeReviewContentToText),
NewMigration("change review content type to text", v1_11.ChangeReviewContentToText),
// v111 -> v112
NewMigration("update branch protection for can push and whitelist enable", addBranchProtectionCanPushAndEnableWhitelist),
NewMigration("update branch protection for can push and whitelist enable", v1_11.AddBranchProtectionCanPushAndEnableWhitelist),
// v112 -> v113
NewMigration("remove release attachments which repository deleted", removeAttachmentMissedRepo),
NewMigration("remove release attachments which repository deleted", v1_11.RemoveAttachmentMissedRepo),
// v113 -> v114
NewMigration("new feature: change target branch of pull requests", featureChangeTargetBranch),
NewMigration("new feature: change target branch of pull requests", v1_11.FeatureChangeTargetBranch),
// v114 -> v115
NewMigration("Remove authentication credentials from stored URL", sanitizeOriginalURL),
NewMigration("Remove authentication credentials from stored URL", v1_11.SanitizeOriginalURL),
// v115 -> v116
NewMigration("add user_id prefix to existing user avatar name", renameExistingUserAvatarName),
NewMigration("add user_id prefix to existing user avatar name", v1_11.RenameExistingUserAvatarName),
// v116 -> v117
NewMigration("Extend TrackedTimes", extendTrackedTimes),
NewMigration("Extend TrackedTimes", v1_11.ExtendTrackedTimes),
// Gitea 1.11.0 ends at v117
// v117 -> v118
NewMigration("Add block on rejected reviews branch protection", addBlockOnRejectedReviews),
NewMigration("Add block on rejected reviews branch protection", v1_12.AddBlockOnRejectedReviews),
// v118 -> v119
NewMigration("Add commit id and stale to reviews", addReviewCommitAndStale),
NewMigration("Add commit id and stale to reviews", v1_12.AddReviewCommitAndStale),
// v119 -> v120
NewMigration("Fix migrated repositories' git service type", fixMigratedRepositoryServiceType),
NewMigration("Fix migrated repositories' git service type", v1_12.FixMigratedRepositoryServiceType),
// v120 -> v121
NewMigration("Add owner_name on table repository", addOwnerNameOnRepository),
NewMigration("Add owner_name on table repository", v1_12.AddOwnerNameOnRepository),
// v121 -> v122
NewMigration("add is_restricted column for users table", addIsRestricted),
NewMigration("add is_restricted column for users table", v1_12.AddIsRestricted),
// v122 -> v123
NewMigration("Add Require Signed Commits to ProtectedBranch", addRequireSignedCommits),
NewMigration("Add Require Signed Commits to ProtectedBranch", v1_12.AddRequireSignedCommits),
// v123 -> v124
NewMigration("Add original information for reactions", addReactionOriginals),
NewMigration("Add original information for reactions", v1_12.AddReactionOriginals),
// v124 -> v125
NewMigration("Add columns to user and repository", addUserRepoMissingColumns),
NewMigration("Add columns to user and repository", v1_12.AddUserRepoMissingColumns),
// v125 -> v126
NewMigration("Add some columns on review for migration", addReviewMigrateInfo),
NewMigration("Add some columns on review for migration", v1_12.AddReviewMigrateInfo),
// v126 -> v127
NewMigration("Fix topic repository count", fixTopicRepositoryCount),
NewMigration("Fix topic repository count", v1_12.FixTopicRepositoryCount),
// v127 -> v128
NewMigration("add repository code language statistics", addLanguageStats),
NewMigration("add repository code language statistics", v1_12.AddLanguageStats),
// v128 -> v129
NewMigration("fix merge base for pull requests", fixMergeBase),
NewMigration("fix merge base for pull requests", v1_12.FixMergeBase),
// v129 -> v130
NewMigration("remove dependencies from deleted repositories", purgeUnusedDependencies),
NewMigration("remove dependencies from deleted repositories", v1_12.PurgeUnusedDependencies),
// v130 -> v131
NewMigration("Expand webhooks for more granularity", expandWebhooks),
NewMigration("Expand webhooks for more granularity", v1_12.ExpandWebhooks),
// v131 -> v132
NewMigration("Add IsSystemWebhook column to webhooks table", addSystemWebhookColumn),
NewMigration("Add IsSystemWebhook column to webhooks table", v1_12.AddSystemWebhookColumn),
// v132 -> v133
NewMigration("Add Branch Protection Protected Files Column", addBranchProtectionProtectedFilesColumn),
NewMigration("Add Branch Protection Protected Files Column", v1_12.AddBranchProtectionProtectedFilesColumn),
// v133 -> v134
NewMigration("Add EmailHash Table", addEmailHashTable),
NewMigration("Add EmailHash Table", v1_12.AddEmailHashTable),
// v134 -> v135
NewMigration("Refix merge base for merged pull requests", refixMergeBase),
NewMigration("Refix merge base for merged pull requests", v1_12.RefixMergeBase),
// v135 -> v136
NewMigration("Add OrgID column to Labels table", addOrgIDLabelColumn),
NewMigration("Add OrgID column to Labels table", v1_12.AddOrgIDLabelColumn),
// v136 -> v137
NewMigration("Add CommitsAhead and CommitsBehind Column to PullRequest Table", addCommitDivergenceToPulls),
NewMigration("Add CommitsAhead and CommitsBehind Column to PullRequest Table", v1_12.AddCommitDivergenceToPulls),
// v137 -> v138
NewMigration("Add Branch Protection Block Outdated Branch", addBlockOnOutdatedBranch),
NewMigration("Add Branch Protection Block Outdated Branch", v1_12.AddBlockOnOutdatedBranch),
// v138 -> v139
NewMigration("Add ResolveDoerID to Comment table", addResolveDoerIDCommentColumn),
NewMigration("Add ResolveDoerID to Comment table", v1_12.AddResolveDoerIDCommentColumn),
// v139 -> v140
NewMigration("prepend refs/heads/ to issue refs", prependRefsHeadsToIssueRefs),
NewMigration("prepend refs/heads/ to issue refs", v1_12.PrependRefsHeadsToIssueRefs),
// Gitea 1.12.0 ends at v140
// v140 -> v141
NewMigration("Save detected language file size to database instead of percent", fixLanguageStatsToSaveSize),
NewMigration("Save detected language file size to database instead of percent", v1_13.FixLanguageStatsToSaveSize),
// v141 -> v142
NewMigration("Add KeepActivityPrivate to User table", addKeepActivityPrivateUserColumn),
NewMigration("Add KeepActivityPrivate to User table", v1_13.AddKeepActivityPrivateUserColumn),
// v142 -> v143
NewMigration("Ensure Repository.IsArchived is not null", setIsArchivedToFalse),
NewMigration("Ensure Repository.IsArchived is not null", v1_13.SetIsArchivedToFalse),
// v143 -> v144
NewMigration("recalculate Stars number for all user", recalculateStars),
NewMigration("recalculate Stars number for all user", v1_13.RecalculateStars),
// v144 -> v145
NewMigration("update Matrix Webhook http method to 'PUT'", updateMatrixWebhookHTTPMethod),
NewMigration("update Matrix Webhook http method to 'PUT'", v1_13.UpdateMatrixWebhookHTTPMethod),
// v145 -> v146
NewMigration("Increase Language field to 50 in LanguageStats", increaseLanguageField),
NewMigration("Increase Language field to 50 in LanguageStats", v1_13.IncreaseLanguageField),
// v146 -> v147
NewMigration("Add projects info to repository table", addProjectsInfo),
NewMigration("Add projects info to repository table", v1_13.AddProjectsInfo),
// v147 -> v148
NewMigration("create review for 0 review id code comments", createReviewsForCodeComments),
NewMigration("create review for 0 review id code comments", v1_13.CreateReviewsForCodeComments),
// v148 -> v149
NewMigration("remove issue dependency comments who refer to non existing issues", purgeInvalidDependenciesComments),
NewMigration("remove issue dependency comments who refer to non existing issues", v1_13.PurgeInvalidDependenciesComments),
// v149 -> v150
NewMigration("Add Created and Updated to Milestone table", addCreatedAndUpdatedToMilestones),
NewMigration("Add Created and Updated to Milestone table", v1_13.AddCreatedAndUpdatedToMilestones),
// v150 -> v151
NewMigration("add primary key to repo_topic", addPrimaryKeyToRepoTopic),
NewMigration("add primary key to repo_topic", v1_13.AddPrimaryKeyToRepoTopic),
// v151 -> v152
NewMigration("set default password algorithm to Argon2", setDefaultPasswordToArgon2),
NewMigration("set default password algorithm to Argon2", v1_13.SetDefaultPasswordToArgon2),
// v152 -> v153
NewMigration("add TrustModel field to Repository", addTrustModelToRepository),
NewMigration("add TrustModel field to Repository", v1_13.AddTrustModelToRepository),
// v153 > v154
NewMigration("add Team review request support", addTeamReviewRequestSupport),
NewMigration("add Team review request support", v1_13.AddTeamReviewRequestSupport),
// v154 > v155
NewMigration("add timestamps to Star, Label, Follow, Watch and Collaboration", addTimeStamps),
NewMigration("add timestamps to Star, Label, Follow, Watch and Collaboration", v1_13.AddTimeStamps),
// Gitea 1.13.0 ends at v155
// v155 -> v156
NewMigration("add changed_protected_files column for pull_request table", addChangedProtectedFilesPullRequestColumn),
NewMigration("add changed_protected_files column for pull_request table", v1_14.AddChangedProtectedFilesPullRequestColumn),
// v156 -> v157
NewMigration("fix publisher ID for tag releases", fixPublisherIDforTagReleases),
NewMigration("fix publisher ID for tag releases", v1_14.FixPublisherIDforTagReleases),
// v157 -> v158
NewMigration("ensure repo topics are up-to-date", fixRepoTopics),
NewMigration("ensure repo topics are up-to-date", v1_14.FixRepoTopics),
// v158 -> v159
NewMigration("code comment replies should have the commitID of the review they are replying to", updateCodeCommentReplies),
NewMigration("code comment replies should have the commitID of the review they are replying to", v1_14.UpdateCodeCommentReplies),
// v159 -> v160
NewMigration("update reactions constraint", updateReactionConstraint),
NewMigration("update reactions constraint", v1_14.UpdateReactionConstraint),
// v160 -> v161
NewMigration("Add block on official review requests branch protection", addBlockOnOfficialReviewRequests),
NewMigration("Add block on official review requests branch protection", v1_14.AddBlockOnOfficialReviewRequests),
// v161 -> v162
NewMigration("Convert task type from int to string", convertTaskTypeToString),
NewMigration("Convert task type from int to string", v1_14.ConvertTaskTypeToString),
// v162 -> v163
NewMigration("Convert webhook task type from int to string", convertWebhookTaskTypeToString),
NewMigration("Convert webhook task type from int to string", v1_14.ConvertWebhookTaskTypeToString),
// v163 -> v164
NewMigration("Convert topic name from 25 to 50", convertTopicNameFrom25To50),
NewMigration("Convert topic name from 25 to 50", v1_14.ConvertTopicNameFrom25To50),
// v164 -> v165
NewMigration("Add scope and nonce columns to oauth2_grant table", addScopeAndNonceColumnsToOAuth2Grant),
NewMigration("Add scope and nonce columns to oauth2_grant table", v1_14.AddScopeAndNonceColumnsToOAuth2Grant),
// v165 -> v166
NewMigration("Convert hook task type from char(16) to varchar(16) and trim the column", convertHookTaskTypeToVarcharAndTrim),
NewMigration("Convert hook task type from char(16) to varchar(16) and trim the column", v1_14.ConvertHookTaskTypeToVarcharAndTrim),
// v166 -> v167
NewMigration("Where Password is Valid with Empty String delete it", recalculateUserEmptyPWD),
NewMigration("Where Password is Valid with Empty String delete it", v1_14.RecalculateUserEmptyPWD),
// v167 -> v168
NewMigration("Add user redirect", addUserRedirect),
NewMigration("Add user redirect", v1_14.AddUserRedirect),
// v168 -> v169
NewMigration("Recreate user table to fix default values", recreateUserTableToFixDefaultValues),
NewMigration("Recreate user table to fix default values", v1_14.RecreateUserTableToFixDefaultValues),
// v169 -> v170
NewMigration("Update DeleteBranch comments to set the old_ref to the commit_sha", commentTypeDeleteBranchUseOldRef),
NewMigration("Update DeleteBranch comments to set the old_ref to the commit_sha", v1_14.CommentTypeDeleteBranchUseOldRef),
// v170 -> v171
NewMigration("Add Dismissed to Review table", addDismissedReviewColumn),
NewMigration("Add Dismissed to Review table", v1_14.AddDismissedReviewColumn),
// v171 -> v172
NewMigration("Add Sorting to ProjectBoard table", addSortingColToProjectBoard),
NewMigration("Add Sorting to ProjectBoard table", v1_14.AddSortingColToProjectBoard),
// v172 -> v173
NewMigration("Add sessions table for go-chi/session", addSessionTable),
NewMigration("Add sessions table for go-chi/session", v1_14.AddSessionTable),
// v173 -> v174
NewMigration("Add time_id column to Comment", addTimeIDCommentColumn),
NewMigration("Add time_id column to Comment", v1_14.AddTimeIDCommentColumn),
// v174 -> v175
NewMigration("Create repo transfer table", addRepoTransfer),
NewMigration("Create repo transfer table", v1_14.AddRepoTransfer),
// v175 -> v176
NewMigration("Fix Postgres ID Sequences broken by recreate-table", fixPostgresIDSequences),
NewMigration("Fix Postgres ID Sequences broken by recreate-table", v1_14.FixPostgresIDSequences),
// v176 -> v177
NewMigration("Remove invalid labels from comments", removeInvalidLabels),
NewMigration("Remove invalid labels from comments", v1_14.RemoveInvalidLabels),
// v177 -> v178
NewMigration("Delete orphaned IssueLabels", deleteOrphanedIssueLabels),
NewMigration("Delete orphaned IssueLabels", v1_14.DeleteOrphanedIssueLabels),
// Gitea 1.14.0 ends at v178
// v178 -> v179
NewMigration("Add LFS columns to Mirror", addLFSMirrorColumns),
NewMigration("Add LFS columns to Mirror", v1_15.AddLFSMirrorColumns),
// v179 -> v180
NewMigration("Convert avatar url to text", convertAvatarURLToText),
NewMigration("Convert avatar url to text", v1_15.ConvertAvatarURLToText),
// v180 -> v181
NewMigration("Delete credentials from past migrations", deleteMigrationCredentials),
NewMigration("Delete credentials from past migrations", v1_15.DeleteMigrationCredentials),
// v181 -> v182
NewMigration("Always save primary email on email address table", addPrimaryEmail2EmailAddress),
NewMigration("Always save primary email on email address table", v1_15.AddPrimaryEmail2EmailAddress),
// v182 -> v183
NewMigration("Add issue resource index table", addIssueResourceIndexTable),
NewMigration("Add issue resource index table", v1_15.AddIssueResourceIndexTable),
// v183 -> v184
NewMigration("Create PushMirror table", createPushMirrorTable),
NewMigration("Create PushMirror table", v1_15.CreatePushMirrorTable),
// v184 -> v185
NewMigration("Rename Task errors to message", renameTaskErrorsToMessage),
NewMigration("Rename Task errors to message", v1_15.RenameTaskErrorsToMessage),
// v185 -> v186
NewMigration("Add new table repo_archiver", addRepoArchiver),
NewMigration("Add new table repo_archiver", v1_15.AddRepoArchiver),
// v186 -> v187
NewMigration("Create protected tag table", createProtectedTagTable),
NewMigration("Create protected tag table", v1_15.CreateProtectedTagTable),
// v187 -> v188
NewMigration("Drop unneeded webhook related columns", dropWebhookColumns),
NewMigration("Drop unneeded webhook related columns", v1_15.DropWebhookColumns),
// v188 -> v189
NewMigration("Add key is verified to gpg key", addKeyIsVerified),
NewMigration("Add key is verified to gpg key", v1_15.AddKeyIsVerified),
// Gitea 1.15.0 ends at v189
// v189 -> v190
NewMigration("Unwrap ldap.Sources", unwrapLDAPSourceCfg),
NewMigration("Unwrap ldap.Sources", v1_16.UnwrapLDAPSourceCfg),
// v190 -> v191
NewMigration("Add agit flow pull request support", addAgitFlowPullRequest),
NewMigration("Add agit flow pull request support", v1_16.AddAgitFlowPullRequest),
// v191 -> v192
NewMigration("Alter issue/comment table TEXT fields to LONGTEXT", alterIssueAndCommentTextFieldsToLongText),
NewMigration("Alter issue/comment table TEXT fields to LONGTEXT", v1_16.AlterIssueAndCommentTextFieldsToLongText),
// v192 -> v193
NewMigration("RecreateIssueResourceIndexTable to have a primary key instead of an unique index", recreateIssueResourceIndexTable),
NewMigration("RecreateIssueResourceIndexTable to have a primary key instead of an unique index", v1_16.RecreateIssueResourceIndexTable),
// v193 -> v194
NewMigration("Add repo id column for attachment table", addRepoIDForAttachment),
NewMigration("Add repo id column for attachment table", v1_16.AddRepoIDForAttachment),
// v194 -> v195
NewMigration("Add Branch Protection Unprotected Files Column", addBranchProtectionUnprotectedFilesColumn),
NewMigration("Add Branch Protection Unprotected Files Column", v1_16.AddBranchProtectionUnprotectedFilesColumn),
// v195 -> v196
NewMigration("Add table commit_status_index", addTableCommitStatusIndex),
NewMigration("Add table commit_status_index", v1_16.AddTableCommitStatusIndex),
// v196 -> v197
NewMigration("Add Color to ProjectBoard table", addColorColToProjectBoard),
NewMigration("Add Color to ProjectBoard table", v1_16.AddColorColToProjectBoard),
// v197 -> v198
NewMigration("Add renamed_branch table", addRenamedBranchTable),
NewMigration("Add renamed_branch table", v1_16.AddRenamedBranchTable),
// v198 -> v199
NewMigration("Add issue content history table", addTableIssueContentHistory),
NewMigration("Add issue content history table", v1_16.AddTableIssueContentHistory),
// v199 -> v200
NewMigration("No-op (remote version is using AppState now)", noopMigration),
// v200 -> v201
NewMigration("Add table app_state", addTableAppState),
NewMigration("Add table app_state", v1_16.AddTableAppState),
// v201 -> v202
NewMigration("Drop table remote_version (if exists)", dropTableRemoteVersion),
NewMigration("Drop table remote_version (if exists)", v1_16.DropTableRemoteVersion),
// v202 -> v203
NewMigration("Create key/value table for user settings", createUserSettingsTable),
NewMigration("Create key/value table for user settings", v1_16.CreateUserSettingsTable),
// v203 -> v204
NewMigration("Add Sorting to ProjectIssue table", addProjectIssueSorting),
NewMigration("Add Sorting to ProjectIssue table", v1_16.AddProjectIssueSorting),
// v204 -> v205
NewMigration("Add key is verified to ssh key", addSSHKeyIsVerified),
NewMigration("Add key is verified to ssh key", v1_16.AddSSHKeyIsVerified),
// v205 -> v206
NewMigration("Migrate to higher varchar on user struct", migrateUserPasswordSalt),
NewMigration("Migrate to higher varchar on user struct", v1_16.MigrateUserPasswordSalt),
// v206 -> v207
NewMigration("Add authorize column to team_unit table", addAuthorizeColForTeamUnit),
NewMigration("Add authorize column to team_unit table", v1_16.AddAuthorizeColForTeamUnit),
// v207 -> v208
NewMigration("Add webauthn table and migrate u2f data to webauthn - NO-OPED", addWebAuthnCred),
NewMigration("Add webauthn table and migrate u2f data to webauthn - NO-OPED", v1_16.AddWebAuthnCred),
// v208 -> v209
NewMigration("Use base32.HexEncoding instead of base64 encoding for cred ID as it is case insensitive - NO-OPED", useBase32HexForCredIDInWebAuthnCredential),
NewMigration("Use base32.HexEncoding instead of base64 encoding for cred ID as it is case insensitive - NO-OPED", v1_16.UseBase32HexForCredIDInWebAuthnCredential),
// v209 -> v210
NewMigration("Increase WebAuthentication CredentialID size to 410 - NO-OPED", increaseCredentialIDTo410),
NewMigration("Increase WebAuthentication CredentialID size to 410 - NO-OPED", v1_16.IncreaseCredentialIDTo410),
// v210 -> v211
NewMigration("v208 was completely broken - remigrate", remigrateU2FCredentials),
NewMigration("v208 was completely broken - remigrate", v1_16.RemigrateU2FCredentials),
// Gitea 1.16.2 ends at v211
// v211 -> v212
NewMigration("Create ForeignReference table", createForeignReferenceTable),
NewMigration("Create ForeignReference table", v1_17.CreateForeignReferenceTable),
// v212 -> v213
NewMigration("Add package tables", addPackageTables),
NewMigration("Add package tables", v1_17.AddPackageTables),
// v213 -> v214
NewMigration("Add allow edits from maintainers to PullRequest table", addAllowMaintainerEdit),
NewMigration("Add allow edits from maintainers to PullRequest table", v1_17.AddAllowMaintainerEdit),
// v214 -> v215
NewMigration("Add auto merge table", addAutoMergeTable),
NewMigration("Add auto merge table", v1_17.AddAutoMergeTable),
// v215 -> v216
NewMigration("allow to view files in PRs", addReviewViewedFiles),
NewMigration("allow to view files in PRs", v1_17.AddReviewViewedFiles),
// v216 -> v217
NewMigration("No-op (Improve Action table indices v1)", noopMigration),
// v217 -> v218
NewMigration("Alter hook_task table TEXT fields to LONGTEXT", alterHookTaskTextFieldsToLongText),
NewMigration("Alter hook_task table TEXT fields to LONGTEXT", v1_17.AlterHookTaskTextFieldsToLongText),
// v218 -> v219
NewMigration("Improve Action table indices v2", improveActionTableIndices),
NewMigration("Improve Action table indices v2", v1_17.ImproveActionTableIndices),
// v219 -> v220
NewMigration("Add sync_on_commit column to push_mirror table", addSyncOnCommitColForPushMirror),
NewMigration("Add sync_on_commit column to push_mirror table", v1_17.AddSyncOnCommitColForPushMirror),
// v220 -> v221
NewMigration("Add container repository property", addContainerRepositoryProperty),
NewMigration("Add container repository property", v1_17.AddContainerRepositoryProperty),
// v221 -> v222
NewMigration("Store WebAuthentication CredentialID as bytes and increase size to at least 1024", storeWebauthnCredentialIDAsBytes),
NewMigration("Store WebAuthentication CredentialID as bytes and increase size to at least 1024", v1_17.StoreWebauthnCredentialIDAsBytes),
// v222 -> v223
NewMigration("Drop old CredentialID column", dropOldCredentialIDColumn),
NewMigration("Drop old CredentialID column", v1_17.DropOldCredentialIDColumn),
// v223 -> v224
NewMigration("Rename CredentialIDBytes column to CredentialID", renameCredentialIDBytes),
NewMigration("Rename CredentialIDBytes column to CredentialID", v1_17.RenameCredentialIDBytes),
// Gitea 1.17.0 ends at v224
// v224 -> v225
NewMigration("Add badges to users", createUserBadgesTable),
NewMigration("Add badges to users", v1_18.CreateUserBadgesTable),
// v225 -> v226
NewMigration("Alter gpg_key/public_key content TEXT fields to MEDIUMTEXT", alterPublicGPGKeyContentFieldsToMediumText),
NewMigration("Alter gpg_key/public_key content TEXT fields to MEDIUMTEXT", v1_18.AlterPublicGPGKeyContentFieldsToMediumText),
// v226 -> v227
NewMigration("Conan and generic packages do not need to be semantically versioned", fixPackageSemverField),
NewMigration("Conan and generic packages do not need to be semantically versioned", v1_18.FixPackageSemverField),
// v227 -> v228
NewMigration("Create key/value table for system settings", createSystemSettingsTable),
NewMigration("Create key/value table for system settings", v1_18.CreateSystemSettingsTable),
// v228 -> v229
NewMigration("Add TeamInvite table", addTeamInviteTable),
NewMigration("Add TeamInvite table", v1_18.AddTeamInviteTable),
// v229 -> v230
NewMigration("Update counts of all open milestones", updateOpenMilestoneCounts),
NewMigration("Update counts of all open milestones", v1_18.UpdateOpenMilestoneCounts),
// v230 -> v231
NewMigration("Add ConfidentialClient column (default true) to OAuth2Application table", addConfidentialClientColumnToOAuth2ApplicationTable),
NewMigration("Add ConfidentialClient column (default true) to OAuth2Application table", v1_18.AddConfidentialClientColumnToOAuth2ApplicationTable),
// v231 -> v232
NewMigration("Add index for hook_task", addIndexForHookTask),
NewMigration("Add index for hook_task", v1_19.AddIndexForHookTask),
}
// GetCurrentDBVersion returns the current db version
@ -530,499 +538,3 @@ Please try upgrading to a lower version first (suggested v1.6.4), then upgrade t
}
return nil
}
// RecreateTables will recreate the tables for the provided beans using the newly provided bean definition and move all data to that new table
// WARNING: YOU MUST PROVIDE THE FULL BEAN DEFINITION
func RecreateTables(beans ...interface{}) func(*xorm.Engine) error {
return func(x *xorm.Engine) error {
sess := x.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
return err
}
sess = sess.StoreEngine("InnoDB")
for _, bean := range beans {
log.Info("Recreating Table: %s for Bean: %s", x.TableName(bean), reflect.Indirect(reflect.ValueOf(bean)).Type().Name())
if err := recreateTable(sess, bean); err != nil {
return err
}
}
return sess.Commit()
}
}
// recreateTable will recreate the table using the newly provided bean definition and move all data to that new table
// WARNING: YOU MUST PROVIDE THE FULL BEAN DEFINITION
// WARNING: YOU MUST COMMIT THE SESSION AT THE END
func recreateTable(sess *xorm.Session, bean interface{}) error {
// TODO: This will not work if there are foreign keys
tableName := sess.Engine().TableName(bean)
tempTableName := fmt.Sprintf("tmp_recreate__%s", tableName)
// We need to move the old table away and create a new one with the correct columns
// We will need to do this in stages to prevent data loss
//
// First create the temporary table
if err := sess.Table(tempTableName).CreateTable(bean); err != nil {
log.Error("Unable to create table %s. Error: %v", tempTableName, err)
return err
}
if err := sess.Table(tempTableName).CreateUniques(bean); err != nil {
log.Error("Unable to create uniques for table %s. Error: %v", tempTableName, err)
return err
}
if err := sess.Table(tempTableName).CreateIndexes(bean); err != nil {
log.Error("Unable to create indexes for table %s. Error: %v", tempTableName, err)
return err
}
// Work out the column names from the bean - these are the columns to select from the old table and install into the new table
table, err := sess.Engine().TableInfo(bean)
if err != nil {
log.Error("Unable to get table info. Error: %v", err)
return err
}
newTableColumns := table.Columns()
if len(newTableColumns) == 0 {
return fmt.Errorf("no columns in new table")
}
hasID := false
for _, column := range newTableColumns {
hasID = hasID || (column.IsPrimaryKey && column.IsAutoIncrement)
}
if hasID && setting.Database.UseMSSQL {
if _, err := sess.Exec(fmt.Sprintf("SET IDENTITY_INSERT `%s` ON", tempTableName)); err != nil {
log.Error("Unable to set identity insert for table %s. Error: %v", tempTableName, err)
return err
}
}
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
}
if hasID && setting.Database.UseMSSQL {
if _, err := sess.Exec(fmt.Sprintf("SET IDENTITY_INSERT `%s` OFF", tempTableName)); err != nil {
log.Error("Unable to switch off identity insert for table %s. Error: %v", tempTableName, err)
return err
}
}
switch {
case setting.Database.UseSQLite3:
// 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
}
if err := sess.Table(tempTableName).DropIndexes(bean); 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
}
if err := sess.Table(tableName).CreateIndexes(bean); err != nil {
log.Error("Unable to recreate indexes on table %s. Error: %v", tableName, err)
return err
}
if err := sess.Table(tableName).CreateUniques(bean); err != nil {
log.Error("Unable to recreate uniques on table %s. Error: %v", tableName, err)
return err
}
case setting.Database.UseMySQL:
// MySQL 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
}
if err := sess.Table(tempTableName).DropIndexes(bean); err != nil {
log.Error("Unable to drop indexes on temporary table %s. Error: %v", tempTableName, err)
return err
}
// SQLite and MySQL will move all the constraints from the temporary table to the new table
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
}
if err := sess.Table(tableName).CreateIndexes(bean); err != nil {
log.Error("Unable to recreate indexes on table %s. Error: %v", tableName, err)
return err
}
if err := sess.Table(tableName).CreateUniques(bean); err != nil {
log.Error("Unable to recreate uniques on table %s. Error: %v", tableName, err)
return err
}
case setting.Database.UsePostgreSQL:
var originalSequences []string
type sequenceData struct {
LastValue int `xorm:"'last_value'"`
IsCalled bool `xorm:"'is_called'"`
}
sequenceMap := map[string]sequenceData{}
schema := sess.Engine().Dialect().URI().Schema
sess.Engine().SetSchema("")
if err := sess.Table("information_schema.sequences").Cols("sequence_name").Where("sequence_name LIKE ? || '_%' AND sequence_catalog = ?", tableName, setting.Database.Name).Find(&originalSequences); err != nil {
log.Error("Unable to rename %s to %s. Error: %v", tempTableName, tableName, err)
return err
}
sess.Engine().SetSchema(schema)
for _, sequence := range originalSequences {
sequenceData := sequenceData{}
if _, err := sess.Table(sequence).Cols("last_value", "is_called").Get(&sequenceData); err != nil {
log.Error("Unable to get last_value and is_called from %s. Error: %v", sequence, err)
return err
}
sequenceMap[sequence] = sequenceData
}
// CASCADE causes postgres to drop all the constraints on the old table
if _, err := sess.Exec(fmt.Sprintf("DROP TABLE `%s` CASCADE", tableName)); err != nil {
log.Error("Unable to drop old table %s. Error: %v", tableName, err)
return err
}
// CASCADE causes postgres to move all the constraints from the temporary table to the new table
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
}
var indices []string
sess.Engine().SetSchema("")
if err := sess.Table("pg_indexes").Cols("indexname").Where("tablename = ? ", tableName).Find(&indices); err != nil {
log.Error("Unable to rename %s to %s. Error: %v", tempTableName, tableName, err)
return err
}
sess.Engine().SetSchema(schema)
for _, index := range indices {
newIndexName := strings.Replace(index, "tmp_recreate__", "", 1)
if _, err := sess.Exec(fmt.Sprintf("ALTER INDEX `%s` RENAME TO `%s`", index, newIndexName)); err != nil {
log.Error("Unable to rename %s to %s. Error: %v", index, newIndexName, err)
return err
}
}
var sequences []string
sess.Engine().SetSchema("")
if err := sess.Table("information_schema.sequences").Cols("sequence_name").Where("sequence_name LIKE 'tmp_recreate__' || ? || '_%' AND sequence_catalog = ?", tableName, setting.Database.Name).Find(&sequences); err != nil {
log.Error("Unable to rename %s to %s. Error: %v", tempTableName, tableName, err)
return err
}
sess.Engine().SetSchema(schema)
for _, sequence := range sequences {
newSequenceName := strings.Replace(sequence, "tmp_recreate__", "", 1)
if _, err := sess.Exec(fmt.Sprintf("ALTER SEQUENCE `%s` RENAME TO `%s`", sequence, newSequenceName)); err != nil {
log.Error("Unable to rename %s sequence to %s. Error: %v", sequence, newSequenceName, err)
return err
}
val, ok := sequenceMap[newSequenceName]
if newSequenceName == tableName+"_id_seq" {
if ok && val.LastValue != 0 {
if _, err := sess.Exec(fmt.Sprintf("SELECT setval('%s', %d, %t)", newSequenceName, val.LastValue, val.IsCalled)); err != nil {
log.Error("Unable to reset %s to %d. Error: %v", newSequenceName, val, err)
return err
}
} else {
// We're going to try to guess this
if _, err := sess.Exec(fmt.Sprintf("SELECT setval('%s', COALESCE((SELECT MAX(id)+1 FROM `%s`), 1), false)", newSequenceName, tableName)); err != nil {
log.Error("Unable to reset %s. Error: %v", newSequenceName, err)
return err
}
}
} else if ok {
if _, err := sess.Exec(fmt.Sprintf("SELECT setval('%s', %d, %t)", newSequenceName, val.LastValue, val.IsCalled)); err != nil {
log.Error("Unable to reset %s to %d. Error: %v", newSequenceName, val, err)
return err
}
}
}
case setting.Database.UseMSSQL:
// MSSQL 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
}
// MSSQL sp_rename will move all the constraints from the temporary table to the new table
if _, err := sess.Exec(fmt.Sprintf("sp_rename `%s`,`%s`", tempTableName, tableName)); err != nil {
log.Error("Unable to rename %s to %s. Error: %v", tempTableName, tableName, err)
return err
}
default:
log.Fatal("Unrecognized DB")
}
return nil
}
// WARNING: YOU MUST COMMIT THE SESSION AT THE END
func dropTableColumns(sess *xorm.Session, tableName string, columnNames ...string) (err error) {
if tableName == "" || len(columnNames) == 0 {
return nil
}
// TODO: This will not work if there are foreign keys
switch {
case setting.Database.UseSQLite3:
// First drop the indexes on the columns
res, errIndex := sess.Query(fmt.Sprintf("PRAGMA index_list(`%s`)", tableName))
if errIndex != nil {
return errIndex
}
for _, row := range res {
indexName := row["name"]
indexRes, err := sess.Query(fmt.Sprintf("PRAGMA index_info(`%s`)", indexName))
if err != nil {
return err
}
if len(indexRes) != 1 {
continue
}
indexColumn := string(indexRes[0]["name"])
for _, name := range columnNames {
if name == indexColumn {
_, err := sess.Exec(fmt.Sprintf("DROP INDEX `%s`", indexName))
if err != nil {
return err
}
}
}
}
// Here we need to get the columns from the original table
sql := fmt.Sprintf("SELECT sql FROM sqlite_master WHERE tbl_name='%s' and type='table'", tableName)
res, err := sess.Query(sql)
if err != nil {
return err
}
tableSQL := string(res[0]["sql"])
// Get the string offset for column definitions: `CREATE TABLE ( column-definitions... )`
columnDefinitionsIndex := strings.Index(tableSQL, "(")
if columnDefinitionsIndex < 0 {
return errors.New("couldn't find column definitions")
}
// Separate out the column definitions
tableSQL = tableSQL[columnDefinitionsIndex:]
// Remove the required columnNames
for _, name := range columnNames {
tableSQL = regexp.MustCompile(regexp.QuoteMeta("`"+name+"`")+"[^`,)]*?[,)]").ReplaceAllString(tableSQL, "")
}
// Ensure the query is ended properly
tableSQL = strings.TrimSpace(tableSQL)
if tableSQL[len(tableSQL)-1] != ')' {
if tableSQL[len(tableSQL)-1] == ',' {
tableSQL = tableSQL[:len(tableSQL)-1]
}
tableSQL += ")"
}
// Find all the columns in the table
columns := regexp.MustCompile("`([^`]*)`").FindAllString(tableSQL, -1)
tableSQL = fmt.Sprintf("CREATE TABLE `new_%s_new` ", tableName) + tableSQL
if _, err := sess.Exec(tableSQL); err != nil {
return err
}
// Now restore the data
columnsSeparated := strings.Join(columns, ",")
insertSQL := fmt.Sprintf("INSERT INTO `new_%s_new` (%s) SELECT %s FROM %s", tableName, columnsSeparated, columnsSeparated, tableName)
if _, err := sess.Exec(insertSQL); err != nil {
return err
}
// Now drop the old table
if _, err := sess.Exec(fmt.Sprintf("DROP TABLE `%s`", tableName)); err != nil {
return err
}
// Rename the table
if _, err := sess.Exec(fmt.Sprintf("ALTER TABLE `new_%s_new` RENAME TO `%s`", tableName, tableName)); err != nil {
return err
}
case setting.Database.UsePostgreSQL:
cols := ""
for _, col := range columnNames {
if cols != "" {
cols += ", "
}
cols += "DROP COLUMN `" + col + "` CASCADE"
}
if _, err := sess.Exec(fmt.Sprintf("ALTER TABLE `%s` %s", tableName, cols)); err != nil {
return fmt.Errorf("Drop table `%s` columns %v: %w", tableName, columnNames, err)
}
case setting.Database.UseMySQL:
// Drop indexes on columns first
sql := fmt.Sprintf("SHOW INDEX FROM %s WHERE column_name IN ('%s')", tableName, strings.Join(columnNames, "','"))
res, err := sess.Query(sql)
if err != nil {
return err
}
for _, index := range res {
indexName := index["column_name"]
if len(indexName) > 0 {
_, err := sess.Exec(fmt.Sprintf("DROP INDEX `%s` ON `%s`", indexName, tableName))
if err != nil {
return err
}
}
}
// Now drop the columns
cols := ""
for _, col := range columnNames {
if cols != "" {
cols += ", "
}
cols += "DROP COLUMN `" + col + "`"
}
if _, err := sess.Exec(fmt.Sprintf("ALTER TABLE `%s` %s", tableName, cols)); err != nil {
return fmt.Errorf("Drop table `%s` columns %v: %w", tableName, columnNames, err)
}
case setting.Database.UseMSSQL:
cols := ""
for _, col := range columnNames {
if cols != "" {
cols += ", "
}
cols += "`" + strings.ToLower(col) + "`"
}
sql := fmt.Sprintf("SELECT Name FROM sys.default_constraints WHERE parent_object_id = OBJECT_ID('%[1]s') AND parent_column_id IN (SELECT column_id FROM sys.columns WHERE LOWER(name) IN (%[2]s) AND object_id = OBJECT_ID('%[1]s'))",
tableName, strings.ReplaceAll(cols, "`", "'"))
constraints := make([]string, 0)
if err := sess.SQL(sql).Find(&constraints); err != nil {
return fmt.Errorf("Find constraints: %w", err)
}
for _, constraint := range constraints {
if _, err := sess.Exec(fmt.Sprintf("ALTER TABLE `%s` DROP CONSTRAINT `%s`", tableName, constraint)); err != nil {
return fmt.Errorf("Drop table `%s` default constraint `%s`: %w", tableName, constraint, err)
}
}
sql = fmt.Sprintf("SELECT DISTINCT Name FROM sys.indexes INNER JOIN sys.index_columns ON indexes.index_id = index_columns.index_id AND indexes.object_id = index_columns.object_id WHERE indexes.object_id = OBJECT_ID('%[1]s') AND index_columns.column_id IN (SELECT column_id FROM sys.columns WHERE LOWER(name) IN (%[2]s) AND object_id = OBJECT_ID('%[1]s'))",
tableName, strings.ReplaceAll(cols, "`", "'"))
constraints = make([]string, 0)
if err := sess.SQL(sql).Find(&constraints); err != nil {
return fmt.Errorf("Find constraints: %w", err)
}
for _, constraint := range constraints {
if _, err := sess.Exec(fmt.Sprintf("DROP INDEX `%[2]s` ON `%[1]s`", tableName, constraint)); err != nil {
return fmt.Errorf("Drop index `%s` on `%s`: %w", constraint, tableName, err)
}
}
if _, err := sess.Exec(fmt.Sprintf("ALTER TABLE `%s` DROP COLUMN %s", tableName, cols)); err != nil {
return fmt.Errorf("Drop table `%s` columns %v: %w", tableName, columnNames, err)
}
default:
log.Fatal("Unrecognized DB")
}
return nil
}
// modifyColumn will modify column's type or other property. SQLITE is not supported
func modifyColumn(x *xorm.Engine, tableName string, col *schemas.Column) error {
var indexes map[string]*schemas.Index
var err error
// MSSQL have to remove index at first, otherwise alter column will fail
// ref. https://sqlzealots.com/2018/05/09/error-message-the-index-is-dependent-on-column-alter-table-alter-column-failed-because-one-or-more-objects-access-this-column/
if x.Dialect().URI().DBType == schemas.MSSQL {
indexes, err = x.Dialect().GetIndexes(x.DB(), context.Background(), tableName)
if err != nil {
return err
}
for _, index := range indexes {
_, err = x.Exec(x.Dialect().DropIndexSQL(tableName, index))
if err != nil {
return err
}
}
}
defer func() {
for _, index := range indexes {
_, err = x.Exec(x.Dialect().CreateIndexSQL(tableName, index))
if err != nil {
log.Error("Create index %s on table %s failed: %v", index.Name, tableName, err)
}
}
}()
alterSQL := x.Dialect().ModifyColumnSQL(tableName, col)
if _, err := x.Exec(alterSQL); err != nil {
return err
}
return nil
}

View File

@ -1,365 +0,0 @@
// 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 (
"context"
"database/sql"
"fmt"
"os"
"path"
"path/filepath"
"runtime"
"testing"
"time"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"github.com/stretchr/testify/assert"
"xorm.io/xorm"
"xorm.io/xorm/names"
)
func TestMain(m *testing.M) {
giteaRoot := base.SetupGiteaRoot()
if giteaRoot == "" {
fmt.Println("Environment variable $GITEA_ROOT not set")
os.Exit(1)
}
giteaBinary := "gitea"
if runtime.GOOS == "windows" {
giteaBinary += ".exe"
}
setting.AppPath = path.Join(giteaRoot, giteaBinary)
if _, err := os.Stat(setting.AppPath); err != nil {
fmt.Printf("Could not find gitea binary at %s\n", setting.AppPath)
os.Exit(1)
}
giteaConf := os.Getenv("GITEA_CONF")
if giteaConf == "" {
giteaConf = path.Join(filepath.Dir(setting.AppPath), "tests/sqlite.ini")
fmt.Printf("Environment variable $GITEA_CONF not set - defaulting to %s\n", giteaConf)
}
if !path.IsAbs(giteaConf) {
setting.CustomConf = path.Join(giteaRoot, giteaConf)
} else {
setting.CustomConf = giteaConf
}
tmpDataPath, err := os.MkdirTemp("", "data")
if err != nil {
fmt.Printf("Unable to create temporary data path %v\n", err)
os.Exit(1)
}
setting.AppDataPath = tmpDataPath
setting.SetCustomPathAndConf("", "", "")
setting.LoadForTest()
if err = git.InitFull(context.Background()); err != nil {
fmt.Printf("Unable to InitFull: %v\n", err)
os.Exit(1)
}
setting.InitDBConfig()
setting.NewLogServices(true)
exitStatus := m.Run()
if err := removeAllWithRetry(setting.RepoRootPath); err != nil {
fmt.Fprintf(os.Stderr, "os.RemoveAll: %v\n", err)
}
if err := removeAllWithRetry(tmpDataPath); err != nil {
fmt.Fprintf(os.Stderr, "os.RemoveAll: %v\n", err)
}
os.Exit(exitStatus)
}
func removeAllWithRetry(dir string) error {
var err error
for i := 0; i < 20; i++ {
err = os.RemoveAll(dir)
if err == nil {
break
}
time.Sleep(100 * time.Millisecond)
}
return err
}
func newXORMEngine() (*xorm.Engine, error) {
if err := db.InitEngine(context.Background()); err != nil {
return nil, err
}
x := unittest.GetXORMEngine()
return x, nil
}
func deleteDB() error {
switch {
case setting.Database.UseSQLite3:
if err := util.Remove(setting.Database.Path); err != nil {
return err
}
return os.MkdirAll(path.Dir(setting.Database.Path), os.ModePerm)
case setting.Database.UseMySQL:
db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s)/",
setting.Database.User, setting.Database.Passwd, setting.Database.Host))
if err != nil {
return err
}
defer db.Close()
if _, err = db.Exec(fmt.Sprintf("DROP DATABASE IF EXISTS %s", setting.Database.Name)); err != nil {
return err
}
if _, err = db.Exec(fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s", setting.Database.Name)); err != nil {
return err
}
return nil
case setting.Database.UsePostgreSQL:
db, err := sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@%s/?sslmode=%s",
setting.Database.User, setting.Database.Passwd, setting.Database.Host, setting.Database.SSLMode))
if err != nil {
return err
}
defer db.Close()
if _, err = db.Exec(fmt.Sprintf("DROP DATABASE IF EXISTS %s", setting.Database.Name)); err != nil {
return err
}
if _, err = db.Exec(fmt.Sprintf("CREATE DATABASE %s", setting.Database.Name)); err != nil {
return err
}
db.Close()
// Check if we need to setup a specific schema
if len(setting.Database.Schema) != 0 {
db, err = sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@%s/%s?sslmode=%s",
setting.Database.User, setting.Database.Passwd, setting.Database.Host, setting.Database.Name, setting.Database.SSLMode))
if err != nil {
return err
}
defer db.Close()
schrows, err := db.Query(fmt.Sprintf("SELECT 1 FROM information_schema.schemata WHERE schema_name = '%s'", setting.Database.Schema))
if err != nil {
return err
}
defer schrows.Close()
if !schrows.Next() {
// Create and setup a DB schema
_, err = db.Exec(fmt.Sprintf("CREATE SCHEMA %s", setting.Database.Schema))
if err != nil {
return err
}
}
// Make the user's default search path the created schema; this will affect new connections
_, err = db.Exec(fmt.Sprintf(`ALTER USER "%s" SET search_path = %s`, setting.Database.User, setting.Database.Schema))
if err != nil {
return err
}
return nil
}
case setting.Database.UseMSSQL:
host, port := setting.ParseMSSQLHostPort(setting.Database.Host)
db, err := sql.Open("mssql", fmt.Sprintf("server=%s; port=%s; database=%s; user id=%s; password=%s;",
host, port, "master", setting.Database.User, setting.Database.Passwd))
if err != nil {
return err
}
defer db.Close()
if _, err = db.Exec(fmt.Sprintf("DROP DATABASE IF EXISTS [%s]", setting.Database.Name)); err != nil {
return err
}
if _, err = db.Exec(fmt.Sprintf("CREATE DATABASE [%s]", setting.Database.Name)); err != nil {
return err
}
}
return nil
}
// prepareTestEnv prepares the test environment and reset the database. The skip parameter should usually be 0.
// Provide models to be sync'd with the database - in particular any models you expect fixtures to be loaded from.
//
// fixtures in `models/migrations/fixtures/<TestName>` will be loaded automatically
func prepareTestEnv(t *testing.T, skip int, syncModels ...interface{}) (*xorm.Engine, func()) {
t.Helper()
ourSkip := 2
ourSkip += skip
deferFn := PrintCurrentTest(t, ourSkip)
assert.NoError(t, os.RemoveAll(setting.RepoRootPath))
assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "tests/gitea-repositories-meta"), setting.RepoRootPath))
ownerDirs, err := os.ReadDir(setting.RepoRootPath)
if err != nil {
assert.NoError(t, err, "unable to read the new repo root: %v\n", err)
}
for _, ownerDir := range ownerDirs {
if !ownerDir.Type().IsDir() {
continue
}
repoDirs, err := os.ReadDir(filepath.Join(setting.RepoRootPath, ownerDir.Name()))
if err != nil {
assert.NoError(t, err, "unable to read the new repo root: %v\n", err)
}
for _, repoDir := range repoDirs {
_ = os.MkdirAll(filepath.Join(setting.RepoRootPath, ownerDir.Name(), repoDir.Name(), "objects", "pack"), 0o755)
_ = os.MkdirAll(filepath.Join(setting.RepoRootPath, ownerDir.Name(), repoDir.Name(), "objects", "info"), 0o755)
_ = os.MkdirAll(filepath.Join(setting.RepoRootPath, ownerDir.Name(), repoDir.Name(), "refs", "heads"), 0o755)
_ = os.MkdirAll(filepath.Join(setting.RepoRootPath, ownerDir.Name(), repoDir.Name(), "refs", "tag"), 0o755)
}
}
if err := deleteDB(); err != nil {
t.Errorf("unable to reset database: %v", err)
return nil, deferFn
}
x, err := newXORMEngine()
assert.NoError(t, err)
if x != nil {
oldDefer := deferFn
deferFn = func() {
oldDefer()
if err := x.Close(); err != nil {
t.Errorf("error during close: %v", err)
}
if err := deleteDB(); err != nil {
t.Errorf("unable to reset database: %v", err)
}
}
}
if err != nil {
return x, deferFn
}
if len(syncModels) > 0 {
if err := x.Sync2(syncModels...); err != nil {
t.Errorf("error during sync: %v", err)
return x, deferFn
}
}
fixturesDir := filepath.Join(filepath.Dir(setting.AppPath), "models", "migrations", "fixtures", t.Name())
if _, err := os.Stat(fixturesDir); err == nil {
t.Logf("initializing fixtures from: %s", fixturesDir)
if err := unittest.InitFixtures(
unittest.FixturesOptions{
Dir: fixturesDir,
}, x); err != nil {
t.Errorf("error whilst initializing fixtures from %s: %v", fixturesDir, err)
return x, deferFn
}
if err := unittest.LoadFixtures(x); err != nil {
t.Errorf("error whilst loading fixtures from %s: %v", fixturesDir, err)
return x, deferFn
}
} else if !os.IsNotExist(err) {
t.Errorf("unexpected error whilst checking for existence of fixtures: %v", err)
} else {
t.Logf("no fixtures found in: %s", fixturesDir)
}
return x, deferFn
}
func Test_dropTableColumns(t *testing.T) {
x, deferable := prepareTestEnv(t, 0)
if x == nil || t.Failed() {
defer deferable()
return
}
defer deferable()
type DropTest struct {
ID int64 `xorm:"pk autoincr"`
FirstColumn string
ToDropColumn string `xorm:"unique"`
AnotherColumn int64
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
}
columns := []string{
"first_column",
"to_drop_column",
"another_column",
"created_unix",
"updated_unix",
}
for i := range columns {
x.SetMapper(names.GonicMapper{})
if err := x.Sync2(new(DropTest)); err != nil {
t.Errorf("unable to create DropTest table: %v", err)
return
}
sess := x.NewSession()
if err := sess.Begin(); err != nil {
sess.Close()
t.Errorf("unable to begin transaction: %v", err)
return
}
if err := dropTableColumns(sess, "drop_test", columns[i:]...); err != nil {
sess.Close()
t.Errorf("Unable to drop columns[%d:]: %s from drop_test: %v", i, columns[i:], err)
return
}
if err := sess.Commit(); err != nil {
sess.Close()
t.Errorf("unable to commit transaction: %v", err)
return
}
sess.Close()
if err := x.DropTables(new(DropTest)); err != nil {
t.Errorf("unable to drop table: %v", err)
return
}
for j := range columns[i+1:] {
x.SetMapper(names.GonicMapper{})
if err := x.Sync2(new(DropTest)); err != nil {
t.Errorf("unable to create DropTest table: %v", err)
return
}
dropcols := append([]string{columns[i]}, columns[j+i+1:]...)
sess := x.NewSession()
if err := sess.Begin(); err != nil {
sess.Close()
t.Errorf("unable to begin transaction: %v", err)
return
}
if err := dropTableColumns(sess, "drop_test", dropcols...); err != nil {
sess.Close()
t.Errorf("Unable to drop columns: %s from drop_test: %v", dropcols, err)
return
}
if err := sess.Commit(); err != nil {
sess.Close()
t.Errorf("unable to commit transaction: %v", err)
return
}
sess.Close()
if err := x.DropTables(new(DropTest)); err != nil {
t.Errorf("unable to drop table: %v", err)
return
}
}
}
}

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_10 //nolint
import (
"net/url"
@ -12,7 +12,7 @@ import (
"xorm.io/xorm"
)
func updateMigrationServiceTypes(x *xorm.Engine) error {
func UpdateMigrationServiceTypes(x *xorm.Engine) error {
type Repository struct {
ID int64
OriginalServiceType int `xorm:"index default(0)"`

View File

@ -2,13 +2,13 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_10 //nolint
import (
"xorm.io/xorm"
)
func changeSomeColumnsLengthOfExternalLoginUser(x *xorm.Engine) error {
func ChangeSomeColumnsLengthOfExternalLoginUser(x *xorm.Engine) error {
type ExternalLoginUser struct {
AccessToken string `xorm:"TEXT"`
AccessTokenSecret string `xorm:"TEXT"`

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_10 //nolint
import (
"crypto/sha1"
@ -15,7 +15,7 @@ func hashContext(context string) string {
return fmt.Sprintf("%x", sha1.Sum([]byte(context)))
}
func addCommitStatusContext(x *xorm.Engine) error {
func AddCommitStatusContext(x *xorm.Engine) error {
type CommitStatus struct {
ID int64 `xorm:"pk autoincr"`
ContextHash string `xorm:"char(40) index"`

View File

@ -2,11 +2,11 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_10 //nolint
import "xorm.io/xorm"
func addOriginalMigrationInfo(x *xorm.Engine) error {
func AddOriginalMigrationInfo(x *xorm.Engine) error {
// Issue see models/issue.go
type Issue struct {
OriginalAuthor string

View File

@ -2,11 +2,11 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_10 //nolint
import "xorm.io/xorm"
func changeSomeColumnsLengthOfRepo(x *xorm.Engine) error {
func ChangeSomeColumnsLengthOfRepo(x *xorm.Engine) error {
type Repository struct {
ID int64 `xorm:"pk autoincr"`
Description string `xorm:"TEXT"`

View File

@ -2,11 +2,11 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_10 //nolint
import "xorm.io/xorm"
func addIndexOnRepositoryAndComment(x *xorm.Engine) error {
func AddIndexOnRepositoryAndComment(x *xorm.Engine) error {
type Repository struct {
ID int64 `xorm:"pk autoincr"`
OwnerID int64 `xorm:"index"`

View File

@ -2,14 +2,14 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_10 //nolint
import (
"xorm.io/builder"
"xorm.io/xorm"
)
func removeLingeringIndexStatus(x *xorm.Engine) error {
func RemoveLingeringIndexStatus(x *xorm.Engine) error {
_, err := x.Exec(builder.Delete(builder.NotIn("`repo_id`", builder.Select("`id`").From("`repository`"))).From("`repo_indexer_status`"))
return err
}

View File

@ -2,11 +2,11 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_10 //nolint
import "xorm.io/xorm"
func addEmailNotificationEnabledToUser(x *xorm.Engine) error {
func AddEmailNotificationEnabledToUser(x *xorm.Engine) error {
// User see models/user.go
type User struct {
EmailNotificationsPreference string `xorm:"VARCHAR(20) NOT NULL DEFAULT 'enabled'"`

View File

@ -2,11 +2,11 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_10 //nolint
import "xorm.io/xorm"
func addStatusCheckColumnsForProtectedBranches(x *xorm.Engine) error {
func AddStatusCheckColumnsForProtectedBranches(x *xorm.Engine) error {
type ProtectedBranch struct {
EnableStatusCheck bool `xorm:"NOT NULL DEFAULT false"`
StatusCheckContexts []string `xorm:"JSON TEXT"`

View File

@ -2,11 +2,11 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_10 //nolint
import "xorm.io/xorm"
func addCrossReferenceColumns(x *xorm.Engine) error {
func AddCrossReferenceColumns(x *xorm.Engine) error {
// Comment see models/comment.go
type Comment struct {
RefRepoID int64 `xorm:"index"`

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_10 //nolint
import (
"path/filepath"
@ -13,7 +13,7 @@ import (
"xorm.io/xorm"
)
func deleteOrphanedAttachments(x *xorm.Engine) error {
func DeleteOrphanedAttachments(x *xorm.Engine) error {
type Attachment struct {
ID int64 `xorm:"pk autoincr"`
UUID string `xorm:"uuid UNIQUE"`

View File

@ -2,11 +2,11 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_10 //nolint
import "xorm.io/xorm"
func addRepoAdminChangeTeamAccessColumnForUser(x *xorm.Engine) error {
func AddRepoAdminChangeTeamAccessColumnForUser(x *xorm.Engine) error {
type User struct {
RepoAdminChangeTeamAccess bool `xorm:"NOT NULL DEFAULT false"`
}

View File

@ -2,11 +2,11 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_10 //nolint
import "xorm.io/xorm"
func addOriginalAuthorOnMigratedReleases(x *xorm.Engine) error {
func AddOriginalAuthorOnMigratedReleases(x *xorm.Engine) error {
type Release struct {
ID int64
OriginalAuthor string

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_10 //nolint
import (
"code.gitea.io/gitea/modules/timeutil"
@ -10,7 +10,7 @@ import (
"xorm.io/xorm"
)
func addTaskTable(x *xorm.Engine) error {
func AddTaskTable(x *xorm.Engine) error {
// TaskType defines task type
type TaskType int

View File

@ -2,19 +2,21 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_11 //nolint
import (
"code.gitea.io/gitea/models/migrations/base"
"xorm.io/xorm"
)
func dropColumnHeadUserNameOnPullRequest(x *xorm.Engine) error {
func DropColumnHeadUserNameOnPullRequest(x *xorm.Engine) error {
sess := x.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
return err
}
if err := dropTableColumns(sess, "pull_request", "head_user_name"); err != nil {
if err := base.DropTableColumns(sess, "pull_request", "head_user_name"); err != nil {
return err
}
return sess.Commit()

View File

@ -2,13 +2,13 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_11 //nolint
import (
"xorm.io/xorm"
)
func addWhitelistDeployKeysToBranches(x *xorm.Engine) error {
func AddWhitelistDeployKeysToBranches(x *xorm.Engine) error {
type ProtectedBranch struct {
ID int64
WhitelistDeployKeys bool `xorm:"NOT NULL DEFAULT false"`

View File

@ -2,13 +2,15 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_11 //nolint
import (
"code.gitea.io/gitea/models/migrations/base"
"xorm.io/xorm"
)
func removeLabelUneededCols(x *xorm.Engine) error {
func RemoveLabelUneededCols(x *xorm.Engine) error {
// Make sure the columns exist before dropping them
type Label struct {
QueryString string
@ -23,10 +25,10 @@ func removeLabelUneededCols(x *xorm.Engine) error {
if err := sess.Begin(); err != nil {
return err
}
if err := dropTableColumns(sess, "label", "query_string"); err != nil {
if err := base.DropTableColumns(sess, "label", "query_string"); err != nil {
return err
}
if err := dropTableColumns(sess, "label", "is_selected"); err != nil {
if err := base.DropTableColumns(sess, "label", "is_selected"); err != nil {
return err
}
return sess.Commit()

View File

@ -2,13 +2,13 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_11 //nolint
import (
"xorm.io/xorm"
)
func addTeamIncludesAllRepositories(x *xorm.Engine) error {
func AddTeamIncludesAllRepositories(x *xorm.Engine) error {
type Team struct {
ID int64 `xorm:"pk autoincr"`
IncludesAllRepositories bool `xorm:"NOT NULL DEFAULT false"`

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_11 //nolint
import (
"xorm.io/xorm"
@ -17,7 +17,7 @@ type Watch struct {
Mode RepoWatchMode `xorm:"SMALLINT NOT NULL DEFAULT 1"`
}
func addModeColumnToWatch(x *xorm.Engine) (err error) {
func AddModeColumnToWatch(x *xorm.Engine) (err error) {
if err = x.Sync2(new(Watch)); err != nil {
return
}

View File

@ -2,13 +2,13 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_11 //nolint
import (
"xorm.io/xorm"
)
func addTemplateToRepo(x *xorm.Engine) error {
func AddTemplateToRepo(x *xorm.Engine) error {
type Repository struct {
IsTemplate bool `xorm:"INDEX NOT NULL DEFAULT false"`
TemplateID int64 `xorm:"INDEX"`

View File

@ -2,13 +2,13 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_11 //nolint
import (
"xorm.io/xorm"
)
func addCommentIDOnNotification(x *xorm.Engine) error {
func AddCommentIDOnNotification(x *xorm.Engine) error {
type Notification struct {
ID int64 `xorm:"pk autoincr"`
CommentID int64

View File

@ -2,13 +2,13 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_11 //nolint
import (
"xorm.io/xorm"
)
func addCanCreateOrgRepoColumnForTeam(x *xorm.Engine) error {
func AddCanCreateOrgRepoColumnForTeam(x *xorm.Engine) error {
type Team struct {
CanCreateOrgRepo bool `xorm:"NOT NULL DEFAULT false"`
}

View File

@ -2,14 +2,14 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_11 //nolint
import (
"xorm.io/xorm"
"xorm.io/xorm/schemas"
)
func changeReviewContentToText(x *xorm.Engine) error {
func ChangeReviewContentToText(x *xorm.Engine) error {
switch x.Dialect().URI().DBType {
case schemas.MYSQL:
_, err := x.Exec("ALTER TABLE review MODIFY COLUMN content TEXT")

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_11 //nolint
import (
"fmt"
@ -10,7 +10,7 @@ import (
"xorm.io/xorm"
)
func addBranchProtectionCanPushAndEnableWhitelist(x *xorm.Engine) error {
func AddBranchProtectionCanPushAndEnableWhitelist(x *xorm.Engine) error {
type ProtectedBranch struct {
CanPush bool `xorm:"NOT NULL DEFAULT false"`
EnableApprovalsWhitelist bool `xorm:"NOT NULL DEFAULT false"`

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_11 //nolint
import (
"fmt"
@ -15,7 +15,7 @@ import (
"xorm.io/xorm"
)
func removeAttachmentMissedRepo(x *xorm.Engine) error {
func RemoveAttachmentMissedRepo(x *xorm.Engine) error {
type Attachment struct {
UUID string `xorm:"uuid"`
}

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_11 //nolint
import (
"fmt"
@ -10,7 +10,7 @@ import (
"xorm.io/xorm"
)
func featureChangeTargetBranch(x *xorm.Engine) error {
func FeatureChangeTargetBranch(x *xorm.Engine) error {
type Comment struct {
OldRef string
NewRef string

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_11 //nolint
import (
"net/url"
@ -10,7 +10,7 @@ import (
"xorm.io/xorm"
)
func sanitizeOriginalURL(x *xorm.Engine) error {
func SanitizeOriginalURL(x *xorm.Engine) error {
type Repository struct {
ID int64
OriginalURL string `xorm:"VARCHAR(2048)"`

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_11 //nolint
import (
"crypto/md5"
@ -21,7 +21,7 @@ import (
"xorm.io/xorm"
)
func renameExistingUserAvatarName(x *xorm.Engine) error {
func RenameExistingUserAvatarName(x *xorm.Engine) error {
sess := x.NewSession()
defer sess.Close()

View File

@ -2,13 +2,13 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_11 //nolint
import (
"xorm.io/xorm"
)
func extendTrackedTimes(x *xorm.Engine) error {
func ExtendTrackedTimes(x *xorm.Engine) error {
type TrackedTime struct {
Time int64 `xorm:"NOT NULL"`
Deleted bool `xorm:"NOT NULL DEFAULT false"`

View File

@ -2,13 +2,13 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_12 //nolint
import (
"xorm.io/xorm"
)
func addBlockOnRejectedReviews(x *xorm.Engine) error {
func AddBlockOnRejectedReviews(x *xorm.Engine) error {
type ProtectedBranch struct {
BlockOnRejectedReviews bool `xorm:"NOT NULL DEFAULT false"`
}

View File

@ -2,13 +2,13 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_12 //nolint
import (
"xorm.io/xorm"
)
func addReviewCommitAndStale(x *xorm.Engine) error {
func AddReviewCommitAndStale(x *xorm.Engine) error {
type Review struct {
CommitID string `xorm:"VARCHAR(40)"`
Stale bool `xorm:"NOT NULL DEFAULT false"`

View File

@ -2,13 +2,13 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_12 //nolint
import (
"xorm.io/xorm"
)
func fixMigratedRepositoryServiceType(x *xorm.Engine) error {
func FixMigratedRepositoryServiceType(x *xorm.Engine) error {
// structs.GithubService:
// GithubService = 2
_, err := x.Exec("UPDATE repository SET original_service_type = ? WHERE original_url LIKE 'https://github.com/%'", 2)

View File

@ -2,13 +2,13 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_12 //nolint
import (
"xorm.io/xorm"
)
func addOwnerNameOnRepository(x *xorm.Engine) error {
func AddOwnerNameOnRepository(x *xorm.Engine) error {
type Repository struct {
OwnerName string
}

View File

@ -2,11 +2,11 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_12 //nolint
import "xorm.io/xorm"
func addIsRestricted(x *xorm.Engine) error {
func AddIsRestricted(x *xorm.Engine) error {
// User see models/user.go
type User struct {
ID int64 `xorm:"pk autoincr"`

View File

@ -2,13 +2,13 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_12 //nolint
import (
"xorm.io/xorm"
)
func addRequireSignedCommits(x *xorm.Engine) error {
func AddRequireSignedCommits(x *xorm.Engine) error {
type ProtectedBranch struct {
RequireSignedCommits bool `xorm:"NOT NULL DEFAULT false"`
}

View File

@ -2,13 +2,13 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_12 //nolint
import (
"xorm.io/xorm"
)
func addReactionOriginals(x *xorm.Engine) error {
func AddReactionOriginals(x *xorm.Engine) error {
type Reaction struct {
OriginalAuthorID int64 `xorm:"INDEX NOT NULL DEFAULT(0)"`
OriginalAuthor string

View File

@ -2,13 +2,13 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_12 //nolint
import (
"xorm.io/xorm"
)
func addUserRepoMissingColumns(x *xorm.Engine) error {
func AddUserRepoMissingColumns(x *xorm.Engine) error {
type VisibleType int
type User struct {
PasswdHashAlgo string `xorm:"NOT NULL DEFAULT 'pbkdf2'"`

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_12 //nolint
import (
"fmt"
@ -10,7 +10,7 @@ import (
"xorm.io/xorm"
)
func addReviewMigrateInfo(x *xorm.Engine) error {
func AddReviewMigrateInfo(x *xorm.Engine) error {
type Review struct {
OriginalAuthor string
OriginalAuthorID int64

View File

@ -2,14 +2,14 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_12 //nolint
import (
"xorm.io/builder"
"xorm.io/xorm"
)
func fixTopicRepositoryCount(x *xorm.Engine) error {
func FixTopicRepositoryCount(x *xorm.Engine) error {
_, err := x.Exec(builder.Delete(builder.NotIn("`repo_id`", builder.Select("`id`").From("`repository`"))).From("`repo_topic`"))
if err != nil {
return err

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_12 //nolint
import (
"fmt"
@ -12,7 +12,7 @@ import (
"xorm.io/xorm"
)
func addLanguageStats(x *xorm.Engine) error {
func AddLanguageStats(x *xorm.Engine) error {
// LanguageStat see models/repo_language_stats.go
type LanguageStat struct {
ID int64 `xorm:"pk autoincr"`

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_12 //nolint
import (
"fmt"
@ -18,7 +18,7 @@ import (
"xorm.io/xorm"
)
func fixMergeBase(x *xorm.Engine) error {
func FixMergeBase(x *xorm.Engine) error {
type Repository struct {
ID int64 `xorm:"pk autoincr"`
OwnerID int64 `xorm:"UNIQUE(s) index"`

View File

@ -2,13 +2,13 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_12 //nolint
import (
"xorm.io/xorm"
)
func purgeUnusedDependencies(x *xorm.Engine) error {
func PurgeUnusedDependencies(x *xorm.Engine) error {
if _, err := x.Exec("DELETE FROM issue_dependency WHERE issue_id NOT IN (SELECT id FROM issue)"); err != nil {
return err
}

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_12 //nolint
import (
"code.gitea.io/gitea/modules/json"
@ -11,7 +11,7 @@ import (
"xorm.io/xorm"
)
func expandWebhooks(x *xorm.Engine) error {
func ExpandWebhooks(x *xorm.Engine) error {
type HookEvents struct {
Create bool `json:"create"`
Delete bool `json:"delete"`

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_12 //nolint
import (
"fmt"
@ -10,7 +10,7 @@ import (
"xorm.io/xorm"
)
func addSystemWebhookColumn(x *xorm.Engine) error {
func AddSystemWebhookColumn(x *xorm.Engine) error {
type Webhook struct {
IsSystemWebhook bool `xorm:"NOT NULL DEFAULT false"`
}

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_12 //nolint
import (
"fmt"
@ -10,7 +10,7 @@ import (
"xorm.io/xorm"
)
func addBranchProtectionProtectedFilesColumn(x *xorm.Engine) error {
func AddBranchProtectionProtectedFilesColumn(x *xorm.Engine) error {
type ProtectedBranch struct {
ProtectedFilePatterns string `xorm:"TEXT"`
}

View File

@ -2,11 +2,11 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_12 //nolint
import "xorm.io/xorm"
func addEmailHashTable(x *xorm.Engine) error {
func AddEmailHashTable(x *xorm.Engine) error {
// EmailHash represents a pre-generated hash map
type EmailHash struct {
Hash string `xorm:"pk varchar(32)"`

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_12 //nolint
import (
"fmt"
@ -18,7 +18,7 @@ import (
"xorm.io/xorm"
)
func refixMergeBase(x *xorm.Engine) error {
func RefixMergeBase(x *xorm.Engine) error {
type Repository struct {
ID int64 `xorm:"pk autoincr"`
OwnerID int64 `xorm:"UNIQUE(s) index"`

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_12 //nolint
import (
"fmt"
@ -10,7 +10,7 @@ import (
"xorm.io/xorm"
)
func addOrgIDLabelColumn(x *xorm.Engine) error {
func AddOrgIDLabelColumn(x *xorm.Engine) error {
type Label struct {
OrgID int64 `xorm:"INDEX"`
}

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_12 //nolint
import (
"fmt"
@ -19,7 +19,7 @@ import (
"xorm.io/xorm"
)
func addCommitDivergenceToPulls(x *xorm.Engine) error {
func AddCommitDivergenceToPulls(x *xorm.Engine) error {
type Repository struct {
ID int64 `xorm:"pk autoincr"`
OwnerID int64 `xorm:"UNIQUE(s) index"`

View File

@ -2,13 +2,13 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_12 //nolint
import (
"xorm.io/xorm"
)
func addBlockOnOutdatedBranch(x *xorm.Engine) error {
func AddBlockOnOutdatedBranch(x *xorm.Engine) error {
type ProtectedBranch struct {
BlockOnOutdatedBranch bool `xorm:"NOT NULL DEFAULT false"`
}

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_12 //nolint
import (
"fmt"
@ -10,7 +10,7 @@ import (
"xorm.io/xorm"
)
func addResolveDoerIDCommentColumn(x *xorm.Engine) error {
func AddResolveDoerIDCommentColumn(x *xorm.Engine) error {
type Comment struct {
ResolveDoerID int64
}

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_12 //nolint
import (
"code.gitea.io/gitea/modules/setting"
@ -10,7 +10,7 @@ import (
"xorm.io/xorm"
)
func prependRefsHeadsToIssueRefs(x *xorm.Engine) error {
func PrependRefsHeadsToIssueRefs(x *xorm.Engine) error {
var query string
switch {

View File

@ -2,17 +2,18 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_13 //nolint
import (
"fmt"
"code.gitea.io/gitea/models/migrations/base"
"code.gitea.io/gitea/modules/setting"
"xorm.io/xorm"
)
func fixLanguageStatsToSaveSize(x *xorm.Engine) error {
func FixLanguageStatsToSaveSize(x *xorm.Engine) error {
// LanguageStat see models/repo_language_stats.go
type LanguageStat struct {
Size int64 `xorm:"NOT NULL DEFAULT 0"`
@ -52,5 +53,5 @@ func fixLanguageStatsToSaveSize(x *xorm.Engine) error {
sess := x.NewSession()
defer sess.Close()
return dropTableColumns(sess, "language_stat", "percentage")
return base.DropTableColumns(sess, "language_stat", "percentage")
}

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_13 //nolint
import (
"fmt"
@ -10,7 +10,7 @@ import (
"xorm.io/xorm"
)
func addKeepActivityPrivateUserColumn(x *xorm.Engine) error {
func AddKeepActivityPrivateUserColumn(x *xorm.Engine) error {
type User struct {
KeepActivityPrivate bool `xorm:"NOT NULL DEFAULT false"`
}

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_13 //nolint
import (
"code.gitea.io/gitea/modules/log"
@ -11,7 +11,7 @@ import (
"xorm.io/xorm"
)
func setIsArchivedToFalse(x *xorm.Engine) error {
func SetIsArchivedToFalse(x *xorm.Engine) error {
type Repository struct {
IsArchived bool `xorm:"INDEX"`
}

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_13 //nolint
import (
"code.gitea.io/gitea/modules/log"
@ -10,7 +10,7 @@ import (
"xorm.io/xorm"
)
func recalculateStars(x *xorm.Engine) (err error) {
func RecalculateStars(x *xorm.Engine) (err error) {
// because of issue https://github.com/go-gitea/gitea/issues/11949,
// recalculate Stars number for all users to fully fix it.

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_13 //nolint
import (
"code.gitea.io/gitea/modules/log"
@ -11,7 +11,7 @@ import (
"xorm.io/xorm"
)
func updateMatrixWebhookHTTPMethod(x *xorm.Engine) error {
func UpdateMatrixWebhookHTTPMethod(x *xorm.Engine) error {
matrixHookTaskType := 9 // value comes from the models package
type Webhook struct {
HTTPMethod string

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_13 //nolint
import (
"fmt"
@ -12,7 +12,7 @@ import (
"xorm.io/xorm"
)
func increaseLanguageField(x *xorm.Engine) error {
func IncreaseLanguageField(x *xorm.Engine) error {
type LanguageStat struct {
RepoID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"`
Language string `xorm:"VARCHAR(50) UNIQUE(s) INDEX NOT NULL"`

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_13 //nolint
import (
"code.gitea.io/gitea/modules/timeutil"
@ -10,7 +10,7 @@ import (
"xorm.io/xorm"
)
func addProjectsInfo(x *xorm.Engine) error {
func AddProjectsInfo(x *xorm.Engine) error {
// Create new tables
type (
ProjectType uint8

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_13 //nolint
import (
"code.gitea.io/gitea/modules/timeutil"
@ -10,7 +10,7 @@ import (
"xorm.io/xorm"
)
func createReviewsForCodeComments(x *xorm.Engine) error {
func CreateReviewsForCodeComments(x *xorm.Engine) error {
// Review
type Review struct {
ID int64 `xorm:"pk autoincr"`

View File

@ -2,13 +2,13 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_13 //nolint
import (
"xorm.io/xorm"
)
func purgeInvalidDependenciesComments(x *xorm.Engine) error {
func PurgeInvalidDependenciesComments(x *xorm.Engine) error {
_, err := x.Exec("DELETE FROM comment WHERE dependent_issue_id != 0 AND dependent_issue_id NOT IN (SELECT id FROM issue)")
return err
}

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_13 //nolint
import (
"fmt"
@ -12,7 +12,7 @@ import (
"xorm.io/xorm"
)
func addCreatedAndUpdatedToMilestones(x *xorm.Engine) error {
func AddCreatedAndUpdatedToMilestones(x *xorm.Engine) error {
type Milestone struct {
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`

View File

@ -2,15 +2,16 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_13 //nolint
import (
"code.gitea.io/gitea/models/migrations/base"
"code.gitea.io/gitea/modules/timeutil"
"xorm.io/xorm"
)
func addPrimaryKeyToRepoTopic(x *xorm.Engine) error {
func AddPrimaryKeyToRepoTopic(x *xorm.Engine) error {
// Topic represents a topic of repositories
type Topic struct {
ID int64 `xorm:"pk autoincr"`
@ -32,8 +33,8 @@ func addPrimaryKeyToRepoTopic(x *xorm.Engine) error {
return err
}
recreateTable(sess, &Topic{})
recreateTable(sess, &RepoTopic{})
base.RecreateTable(sess, &Topic{})
base.RecreateTable(sess, &RepoTopic{})
return sess.Commit()
}

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_13 //nolint
import (
"context"
@ -16,7 +16,7 @@ import (
"xorm.io/xorm/schemas"
)
func setDefaultPasswordToArgon2(x *xorm.Engine) error {
func SetDefaultPasswordToArgon2(x *xorm.Engine) error {
switch {
case setting.Database.UseMySQL:
_, err := x.Exec("ALTER TABLE `user` ALTER passwd_hash_algo SET DEFAULT 'argon2';")

View File

@ -2,11 +2,11 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_13 //nolint
import "xorm.io/xorm"
func addTrustModelToRepository(x *xorm.Engine) error {
func AddTrustModelToRepository(x *xorm.Engine) error {
type Repository struct {
TrustModel int
}

View File

@ -2,13 +2,13 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_13 //nolint
import (
"xorm.io/xorm"
)
func addTeamReviewRequestSupport(x *xorm.Engine) error {
func AddTeamReviewRequestSupport(x *xorm.Engine) error {
type Review struct {
ReviewerTeamID int64 `xorm:"NOT NULL DEFAULT 0"`
}

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_13 //nolint
import (
"code.gitea.io/gitea/modules/timeutil"
@ -10,7 +10,7 @@ import (
"xorm.io/xorm"
)
func addTimeStamps(x *xorm.Engine) error {
func AddTimeStamps(x *xorm.Engine) error {
// this will add timestamps where it is useful to have
// Star represents a starred repo by an user.

View 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 v1_14 //nolint
import (
"testing"
"code.gitea.io/gitea/models/migrations/base"
)
func TestMain(m *testing.M) {
base.MainTest(m)
}

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_14 //nolint
import (
"fmt"
@ -10,7 +10,7 @@ import (
"xorm.io/xorm"
)
func addChangedProtectedFilesPullRequestColumn(x *xorm.Engine) error {
func AddChangedProtectedFilesPullRequestColumn(x *xorm.Engine) error {
type PullRequest struct {
ChangedProtectedFiles []string `xorm:"TEXT JSON"`
}

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_14 //nolint
import (
"fmt"
@ -25,7 +25,7 @@ func userPath(userName string) string {
return filepath.Join(setting.RepoRootPath, strings.ToLower(userName))
}
func fixPublisherIDforTagReleases(x *xorm.Engine) error {
func FixPublisherIDforTagReleases(x *xorm.Engine) error {
type Release struct {
ID int64
RepoID int64

View File

@ -2,13 +2,13 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_14 //nolint
import (
"xorm.io/xorm"
)
func fixRepoTopics(x *xorm.Engine) error {
func FixRepoTopics(x *xorm.Engine) error {
type Topic struct {
ID int64 `xorm:"pk autoincr"`
Name string `xorm:"UNIQUE VARCHAR(25)"`

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_14 //nolint
import (
"fmt"
@ -14,7 +14,7 @@ import (
"xorm.io/xorm"
)
func updateCodeCommentReplies(x *xorm.Engine) error {
func UpdateCodeCommentReplies(x *xorm.Engine) error {
type Comment struct {
ID int64 `xorm:"pk autoincr"`
CommitSHA string `xorm:"VARCHAR(40)"`

View File

@ -2,15 +2,16 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_14 //nolint
import (
"code.gitea.io/gitea/models/migrations/base"
"code.gitea.io/gitea/modules/timeutil"
"xorm.io/xorm"
)
func updateReactionConstraint(x *xorm.Engine) error {
func UpdateReactionConstraint(x *xorm.Engine) error {
// Reaction represents a reactions on issues and comments.
type Reaction struct {
ID int64 `xorm:"pk autoincr"`
@ -30,7 +31,7 @@ func updateReactionConstraint(x *xorm.Engine) error {
return err
}
if err := recreateTable(sess, &Reaction{}); err != nil {
if err := base.RecreateTable(sess, &Reaction{}); err != nil {
return err
}

View File

@ -2,13 +2,13 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_14 //nolint
import (
"xorm.io/xorm"
)
func addBlockOnOfficialReviewRequests(x *xorm.Engine) error {
func AddBlockOnOfficialReviewRequests(x *xorm.Engine) error {
type ProtectedBranch struct {
BlockOnOfficialReviewRequests bool `xorm:"NOT NULL DEFAULT false"`
}

View File

@ -2,15 +2,17 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_14 //nolint
import (
"context"
"code.gitea.io/gitea/models/migrations/base"
"xorm.io/xorm"
)
func convertTaskTypeToString(x *xorm.Engine) error {
func ConvertTaskTypeToString(x *xorm.Engine) error {
const (
GOGS int = iota + 1
SLACK
@ -64,7 +66,7 @@ func convertTaskTypeToString(x *xorm.Engine) error {
if err := sess.Begin(); err != nil {
return err
}
if err := dropTableColumns(sess, "hook_task", "type"); err != nil {
if err := base.DropTableColumns(sess, "hook_task", "type"); err != nil {
return err
}

View File

@ -2,13 +2,15 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_14 //nolint
import (
"code.gitea.io/gitea/models/migrations/base"
"xorm.io/xorm"
)
func convertWebhookTaskTypeToString(x *xorm.Engine) error {
func ConvertWebhookTaskTypeToString(x *xorm.Engine) error {
const (
GOGS int = iota + 1
SLACK
@ -53,7 +55,7 @@ func convertWebhookTaskTypeToString(x *xorm.Engine) error {
if err := sess.Begin(); err != nil {
return err
}
if err := dropTableColumns(sess, "webhook", "hook_task_type"); err != nil {
if err := base.DropTableColumns(sess, "webhook", "hook_task_type"); err != nil {
return err
}

View File

@ -2,13 +2,15 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_14 //nolint
import (
"code.gitea.io/gitea/models/migrations/base"
"xorm.io/xorm"
)
func convertTopicNameFrom25To50(x *xorm.Engine) error {
func ConvertTopicNameFrom25To50(x *xorm.Engine) error {
type Topic struct {
ID int64 `xorm:"pk autoincr"`
Name string `xorm:"UNIQUE VARCHAR(50)"`
@ -26,7 +28,7 @@ func convertTopicNameFrom25To50(x *xorm.Engine) error {
if err := sess.Begin(); err != nil {
return err
}
if err := recreateTable(sess, new(Topic)); err != nil {
if err := base.RecreateTable(sess, new(Topic)); err != nil {
return err
}

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_14 //nolint
import (
"fmt"
@ -30,7 +30,7 @@ func (grant *OAuth2Grant) TableName() string {
return "oauth2_grant"
}
func addScopeAndNonceColumnsToOAuth2Grant(x *xorm.Engine) error {
func AddScopeAndNonceColumnsToOAuth2Grant(x *xorm.Engine) error {
if err := x.Sync2(new(OAuth2Grant)); err != nil {
return fmt.Errorf("Sync2: %w", err)
}

View File

@ -2,14 +2,16 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_14 //nolint
import (
"code.gitea.io/gitea/models/migrations/base"
"xorm.io/xorm"
"xorm.io/xorm/schemas"
)
func convertHookTaskTypeToVarcharAndTrim(x *xorm.Engine) error {
func ConvertHookTaskTypeToVarcharAndTrim(x *xorm.Engine) error {
dbType := x.Dialect().URI().DBType
if dbType == schemas.SQLITE { // For SQLITE, varchar or char will always be represented as TEXT
return nil
@ -19,7 +21,7 @@ func convertHookTaskTypeToVarcharAndTrim(x *xorm.Engine) error {
Typ string `xorm:"VARCHAR(16) index"`
}
if err := modifyColumn(x, "hook_task", &schemas.Column{
if err := base.ModifyColumn(x, "hook_task", &schemas.Column{
Name: "typ",
SQLType: schemas.SQLType{
Name: "VARCHAR",
@ -45,7 +47,7 @@ func convertHookTaskTypeToVarcharAndTrim(x *xorm.Engine) error {
Type string `xorm:"VARCHAR(16) index"`
}
if err := modifyColumn(x, "webhook", &schemas.Column{
if err := base.ModifyColumn(x, "webhook", &schemas.Column{
Name: "type",
SQLType: schemas.SQLType{
Name: "VARCHAR",

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_14 //nolint
import (
"crypto/sha256"
@ -16,7 +16,7 @@ import (
"xorm.io/xorm"
)
func recalculateUserEmptyPWD(x *xorm.Engine) (err error) {
func RecalculateUserEmptyPWD(x *xorm.Engine) (err error) {
const (
algoBcrypt = "bcrypt"
algoScrypt = "scrypt"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_14 //nolint
import (
"fmt"
@ -10,7 +10,7 @@ import (
"xorm.io/xorm"
)
func addUserRedirect(x *xorm.Engine) (err error) {
func AddUserRedirect(x *xorm.Engine) (err error) {
type UserRedirect struct {
ID int64 `xorm:"pk autoincr"`
LowerName string `xorm:"UNIQUE(s) INDEX NOT NULL"`

View File

@ -2,10 +2,10 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_14 //nolint
import "xorm.io/xorm"
func recreateUserTableToFixDefaultValues(_ *xorm.Engine) error {
func RecreateUserTableToFixDefaultValues(_ *xorm.Engine) error {
return nil
}

View File

@ -2,13 +2,13 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_14 //nolint
import (
"xorm.io/xorm"
)
func commentTypeDeleteBranchUseOldRef(x *xorm.Engine) error {
func CommentTypeDeleteBranchUseOldRef(x *xorm.Engine) error {
_, err := x.Exec("UPDATE comment SET old_ref = commit_sha, commit_sha = '' WHERE type = 11")
return err
}

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_14 //nolint
import (
"fmt"
@ -10,7 +10,7 @@ import (
"xorm.io/xorm"
)
func addDismissedReviewColumn(x *xorm.Engine) error {
func AddDismissedReviewColumn(x *xorm.Engine) error {
type Review struct {
Dismissed bool `xorm:"NOT NULL DEFAULT false"`
}

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_14 //nolint
import (
"fmt"
@ -10,7 +10,7 @@ import (
"xorm.io/xorm"
)
func addSortingColToProjectBoard(x *xorm.Engine) error {
func AddSortingColToProjectBoard(x *xorm.Engine) error {
type ProjectBoard struct {
Sorting int8 `xorm:"NOT NULL DEFAULT 0"`
}

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_14 //nolint
import (
"code.gitea.io/gitea/modules/timeutil"
@ -10,7 +10,7 @@ import (
"xorm.io/xorm"
)
func addSessionTable(x *xorm.Engine) error {
func AddSessionTable(x *xorm.Engine) error {
type Session struct {
Key string `xorm:"pk CHAR(16)"`
Data []byte `xorm:"BLOB"`

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_14 //nolint
import (
"fmt"
@ -10,7 +10,7 @@ import (
"xorm.io/xorm"
)
func addTimeIDCommentColumn(x *xorm.Engine) error {
func AddTimeIDCommentColumn(x *xorm.Engine) error {
type Comment struct {
TimeID int64
}

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_14 //nolint
import (
"fmt"
@ -10,7 +10,7 @@ import (
"xorm.io/xorm"
)
func addRepoTransfer(x *xorm.Engine) error {
func AddRepoTransfer(x *xorm.Engine) error {
type RepoTransfer struct {
ID int64 `xorm:"pk autoincr"`
DoerID int64

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
package v1_14 //nolint
import (
"fmt"
@ -14,7 +14,7 @@ import (
"xorm.io/xorm"
)
func fixPostgresIDSequences(x *xorm.Engine) error {
func FixPostgresIDSequences(x *xorm.Engine) error {
if !setting.Database.UsePostgreSQL {
return nil
}

Some files were not shown because too many files have changed in this diff Show More