diff --git a/Makefile b/Makefile index 4889958c3b..32ea823e1e 100644 --- a/Makefile +++ b/Makefile @@ -26,17 +26,17 @@ COMMA := , XGO_VERSION := go-1.23.x AIR_PACKAGE ?= github.com/air-verse/air@v1 -EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@2.7.0 +EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v3/cmd/editorconfig-checker@v3.0.3 GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.7.0 GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.62.2 -GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.11 -MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.5.1 +GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.12 +MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.6.0 SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.31.0 XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1 GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1 ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1 -GOPLS_PACKAGE ?= golang.org/x/tools/gopls@v0.15.3 +GOPLS_PACKAGE ?= golang.org/x/tools/gopls@v0.17.0 DOCKER_IMAGE ?= gitea/gitea DOCKER_TAG ?= latest diff --git a/models/auth/source_test.go b/models/auth/source_test.go index 36e76d5e28..84aede0a6b 100644 --- a/models/auth/source_test.go +++ b/models/auth/source_test.go @@ -13,6 +13,8 @@ import ( "code.gitea.io/gitea/modules/json" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "xorm.io/xorm" "xorm.io/xorm/schemas" ) @@ -54,7 +56,8 @@ func TestDumpAuthSource(t *testing.T) { sb := new(strings.Builder) - db.DumpTables([]*schemas.Table{authSourceSchema}, sb) - + // TODO: this test is quite hacky, it should use a low-level "select" (without model processors) but not a database dump + engine := db.GetEngine(db.DefaultContext).(*xorm.Engine) + require.NoError(t, engine.DumpTables([]*schemas.Table{authSourceSchema}, sb)) assert.Contains(t, sb.String(), `"Provider":"ConvertibleSourceName"`) } diff --git a/models/db/collation.go b/models/db/collation.go index a7db9f5442..79ade87380 100644 --- a/models/db/collation.go +++ b/models/db/collation.go @@ -140,7 +140,7 @@ func CheckCollations(x *xorm.Engine) (*CheckCollationsResult, error) { } func CheckCollationsDefaultEngine() (*CheckCollationsResult, error) { - return CheckCollations(x) + return CheckCollations(xormEngine) } func alterDatabaseCollation(x *xorm.Engine, collation string) error { diff --git a/models/db/context.go b/models/db/context.go index 171e26b933..51627712b1 100644 --- a/models/db/context.go +++ b/models/db/context.go @@ -94,7 +94,7 @@ func GetEngine(ctx context.Context) Engine { if e := getExistingEngine(ctx); e != nil { return e } - return x.Context(ctx) + return xormEngine.Context(ctx) } // getExistingEngine gets an existing db Engine/Statement from this context or returns nil @@ -155,7 +155,7 @@ func TxContext(parentCtx context.Context) (*Context, Committer, error) { return newContext(parentCtx, sess), &halfCommitter{committer: sess}, nil } - sess := x.NewSession() + sess := xormEngine.NewSession() if err := sess.Begin(); err != nil { _ = sess.Close() return nil, nil, err @@ -179,7 +179,7 @@ func WithTx(parentCtx context.Context, f func(ctx context.Context) error) error } func txWithNoCheck(parentCtx context.Context, f func(ctx context.Context) error) error { - sess := x.NewSession() + sess := xormEngine.NewSession() defer sess.Close() if err := sess.Begin(); err != nil { return err @@ -322,7 +322,7 @@ func CountByBean(ctx context.Context, bean any) (int64, error) { // TableName returns the table name according a bean object func TableName(bean any) string { - return x.TableName(bean) + return xormEngine.TableName(bean) } // InTransaction returns true if the engine is in a transaction otherwise return false diff --git a/models/db/convert.go b/models/db/convert.go index 8c124471ab..80b0f7b04b 100644 --- a/models/db/convert.go +++ b/models/db/convert.go @@ -16,30 +16,30 @@ import ( // ConvertDatabaseTable converts database and tables from utf8 to utf8mb4 if it's mysql and set ROW_FORMAT=dynamic func ConvertDatabaseTable() error { - if x.Dialect().URI().DBType != schemas.MYSQL { + if xormEngine.Dialect().URI().DBType != schemas.MYSQL { return nil } - r, err := CheckCollations(x) + r, err := CheckCollations(xormEngine) if err != nil { return err } - _, err = x.Exec(fmt.Sprintf("ALTER DATABASE `%s` CHARACTER SET utf8mb4 COLLATE %s", setting.Database.Name, r.ExpectedCollation)) + _, err = xormEngine.Exec(fmt.Sprintf("ALTER DATABASE `%s` CHARACTER SET utf8mb4 COLLATE %s", setting.Database.Name, r.ExpectedCollation)) if err != nil { return err } - tables, err := x.DBMetas() + tables, err := xormEngine.DBMetas() if err != nil { return err } for _, table := range tables { - if _, err := x.Exec(fmt.Sprintf("ALTER TABLE `%s` ROW_FORMAT=dynamic", table.Name)); err != nil { + if _, err := xormEngine.Exec(fmt.Sprintf("ALTER TABLE `%s` ROW_FORMAT=dynamic", table.Name)); err != nil { return err } - if _, err := x.Exec(fmt.Sprintf("ALTER TABLE `%s` CONVERT TO CHARACTER SET utf8mb4 COLLATE %s", table.Name, r.ExpectedCollation)); err != nil { + if _, err := xormEngine.Exec(fmt.Sprintf("ALTER TABLE `%s` CONVERT TO CHARACTER SET utf8mb4 COLLATE %s", table.Name, r.ExpectedCollation)); err != nil { return err } } @@ -49,11 +49,11 @@ func ConvertDatabaseTable() error { // ConvertVarcharToNVarchar converts database and tables from varchar to nvarchar if it's mssql func ConvertVarcharToNVarchar() error { - if x.Dialect().URI().DBType != schemas.MSSQL { + if xormEngine.Dialect().URI().DBType != schemas.MSSQL { return nil } - sess := x.NewSession() + sess := xormEngine.NewSession() defer sess.Close() res, err := sess.QuerySliceString(`SELECT 'ALTER TABLE ' + OBJECT_NAME(SC.object_id) + ' MODIFY SC.name NVARCHAR(' + CONVERT(VARCHAR(5),SC.max_length) + ')' FROM SYS.columns SC diff --git a/models/db/engine.go b/models/db/engine.go index b17188945a..91015f7038 100755 --- a/models/db/engine.go +++ b/models/db/engine.go @@ -8,17 +8,10 @@ import ( "context" "database/sql" "fmt" - "io" "reflect" "strings" - "time" - - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" "xorm.io/xorm" - "xorm.io/xorm/contexts" - "xorm.io/xorm/names" "xorm.io/xorm/schemas" _ "github.com/go-sql-driver/mysql" // Needed for the MySQL driver @@ -27,9 +20,9 @@ import ( ) var ( - x *xorm.Engine - tables []any - initFuncs []func() error + xormEngine *xorm.Engine + registeredModels []any + registeredInitFuncs []func() error ) // Engine represents a xorm engine or session. @@ -70,167 +63,38 @@ type Engine interface { // TableInfo returns table's information via an object func TableInfo(v any) (*schemas.Table, error) { - return x.TableInfo(v) + return xormEngine.TableInfo(v) } -// DumpTables dump tables information -func DumpTables(tables []*schemas.Table, w io.Writer, tp ...schemas.DBType) error { - return x.DumpTables(tables, w, tp...) -} - -// RegisterModel registers model, if initfunc provided, it will be invoked after data model sync +// RegisterModel registers model, if initFuncs provided, it will be invoked after data model sync func RegisterModel(bean any, initFunc ...func() error) { - tables = append(tables, bean) - if len(initFuncs) > 0 && initFunc[0] != nil { - initFuncs = append(initFuncs, initFunc[0]) + registeredModels = append(registeredModels, bean) + if len(registeredInitFuncs) > 0 && initFunc[0] != nil { + registeredInitFuncs = append(registeredInitFuncs, initFunc[0]) } } -func init() { - gonicNames := []string{"SSL", "UID"} - for _, name := range gonicNames { - names.LintGonicMapper[name] = true - } -} - -// newXORMEngine returns a new XORM engine from the configuration -func newXORMEngine() (*xorm.Engine, error) { - connStr, err := setting.DBConnStr() - if err != nil { - return nil, err - } - - var engine *xorm.Engine - - if setting.Database.Type.IsPostgreSQL() && len(setting.Database.Schema) > 0 { - // OK whilst we sort out our schema issues - create a schema aware postgres - registerPostgresSchemaDriver() - engine, err = xorm.NewEngine("postgresschema", connStr) - } else { - engine, err = xorm.NewEngine(setting.Database.Type.String(), connStr) - } - - if err != nil { - return nil, err - } - if setting.Database.Type == "mysql" { - engine.Dialect().SetParams(map[string]string{"rowFormat": "DYNAMIC"}) - } else if setting.Database.Type == "mssql" { - engine.Dialect().SetParams(map[string]string{"DEFAULT_VARCHAR": "nvarchar"}) - } - engine.SetSchema(setting.Database.Schema) - return engine, nil -} - // SyncAllTables sync the schemas of all tables, is required by unit test code func SyncAllTables() error { - _, err := x.StoreEngine("InnoDB").SyncWithOptions(xorm.SyncOptions{ + _, err := xormEngine.StoreEngine("InnoDB").SyncWithOptions(xorm.SyncOptions{ WarnIfDatabaseColumnMissed: true, - }, tables...) + }, registeredModels...) return err } -// InitEngine initializes the xorm.Engine and sets it as db.DefaultContext -func InitEngine(ctx context.Context) error { - xormEngine, err := newXORMEngine() - if err != nil { - if strings.Contains(err.Error(), "SQLite3 support") { - return fmt.Errorf(`sqlite3 requires: -tags sqlite,sqlite_unlock_notify%s%w`, "\n", err) - } - return fmt.Errorf("failed to connect to database: %w", err) - } - - xormEngine.SetMapper(names.GonicMapper{}) - // WARNING: for serv command, MUST remove the output to os.stdout, - // so use log file to instead print to stdout. - xormEngine.SetLogger(NewXORMLogger(setting.Database.LogSQL)) - xormEngine.ShowSQL(setting.Database.LogSQL) - xormEngine.SetMaxOpenConns(setting.Database.MaxOpenConns) - xormEngine.SetMaxIdleConns(setting.Database.MaxIdleConns) - xormEngine.SetConnMaxLifetime(setting.Database.ConnMaxLifetime) - xormEngine.SetDefaultContext(ctx) - - if setting.Database.SlowQueryThreshold > 0 { - xormEngine.AddHook(&SlowQueryHook{ - Threshold: setting.Database.SlowQueryThreshold, - Logger: log.GetLogger("xorm"), - }) - } - - SetDefaultEngine(ctx, xormEngine) - return nil -} - -// SetDefaultEngine sets the default engine for db -func SetDefaultEngine(ctx context.Context, eng *xorm.Engine) { - x = eng - DefaultContext = &Context{Context: ctx, engine: x} -} - -// UnsetDefaultEngine closes and unsets the default engine -// We hope the SetDefaultEngine and UnsetDefaultEngine can be paired, but it's impossible now, -// there are many calls to InitEngine -> SetDefaultEngine directly to overwrite the `x` and DefaultContext without close -// Global database engine related functions are all racy and there is no graceful close right now. -func UnsetDefaultEngine() { - if x != nil { - _ = x.Close() - x = nil - } - DefaultContext = nil -} - -// InitEngineWithMigration initializes a new xorm.Engine and sets it as the db.DefaultContext -// This function must never call .Sync() if the provided migration function fails. -// When called from the "doctor" command, the migration function is a version check -// that prevents the doctor from fixing anything in the database if the migration level -// is different from the expected value. -func InitEngineWithMigration(ctx context.Context, migrateFunc func(*xorm.Engine) error) (err error) { - if err = InitEngine(ctx); err != nil { - return err - } - - if err = x.Ping(); err != nil { - return err - } - - preprocessDatabaseCollation(x) - - // We have to run migrateFunc here in case the user is re-running installation on a previously created DB. - // If we do not then table schemas will be changed and there will be conflicts when the migrations run properly. - // - // Installation should only be being re-run if users want to recover an old database. - // However, we should think carefully about should we support re-install on an installed instance, - // as there may be other problems due to secret reinitialization. - if err = migrateFunc(x); err != nil { - return fmt.Errorf("migrate: %w", err) - } - - if err = SyncAllTables(); err != nil { - return fmt.Errorf("sync database struct error: %w", err) - } - - for _, initFunc := range initFuncs { - if err := initFunc(); err != nil { - return fmt.Errorf("initFunc failed: %w", err) - } - } - - return nil -} - // NamesToBean return a list of beans or an error func NamesToBean(names ...string) ([]any, error) { beans := []any{} if len(names) == 0 { - beans = append(beans, tables...) + beans = append(beans, registeredModels...) return beans, nil } // Need to map provided names to beans... beanMap := make(map[string]any) - for _, bean := range tables { + for _, bean := range registeredModels { beanMap[strings.ToLower(reflect.Indirect(reflect.ValueOf(bean)).Type().Name())] = bean - beanMap[strings.ToLower(x.TableName(bean))] = bean - beanMap[strings.ToLower(x.TableName(bean, true))] = bean + beanMap[strings.ToLower(xormEngine.TableName(bean))] = bean + beanMap[strings.ToLower(xormEngine.TableName(bean, true))] = bean } gotBean := make(map[any]bool) @@ -247,36 +111,9 @@ func NamesToBean(names ...string) ([]any, error) { return beans, nil } -// DumpDatabase dumps all data from database according the special database SQL syntax to file system. -func DumpDatabase(filePath, dbType string) error { - var tbs []*schemas.Table - for _, t := range tables { - t, err := x.TableInfo(t) - if err != nil { - return err - } - tbs = append(tbs, t) - } - - type Version struct { - ID int64 `xorm:"pk autoincr"` - Version int64 - } - t, err := x.TableInfo(&Version{}) - if err != nil { - return err - } - tbs = append(tbs, t) - - if len(dbType) > 0 { - return x.DumpTablesToFile(tbs, filePath, schemas.DBType(dbType)) - } - return x.DumpTablesToFile(tbs, filePath) -} - // MaxBatchInsertSize returns the table's max batch insert size func MaxBatchInsertSize(bean any) int { - t, err := x.TableInfo(bean) + t, err := xormEngine.TableInfo(bean) if err != nil { return 50 } @@ -285,18 +122,18 @@ func MaxBatchInsertSize(bean any) int { // IsTableNotEmpty returns true if table has at least one record func IsTableNotEmpty(beanOrTableName any) (bool, error) { - return x.Table(beanOrTableName).Exist() + return xormEngine.Table(beanOrTableName).Exist() } // DeleteAllRecords will delete all the records of this table func DeleteAllRecords(tableName string) error { - _, err := x.Exec(fmt.Sprintf("DELETE FROM %s", tableName)) + _, err := xormEngine.Exec(fmt.Sprintf("DELETE FROM %s", tableName)) return err } // GetMaxID will return max id of the table func GetMaxID(beanOrTableName any) (maxID int64, err error) { - _, err = x.Select("MAX(id)").Table(beanOrTableName).Get(&maxID) + _, err = xormEngine.Select("MAX(id)").Table(beanOrTableName).Get(&maxID) return maxID, err } @@ -308,24 +145,3 @@ func SetLogSQL(ctx context.Context, on bool) { sess.Engine().ShowSQL(on) } } - -type SlowQueryHook struct { - Threshold time.Duration - Logger log.Logger -} - -var _ contexts.Hook = &SlowQueryHook{} - -func (SlowQueryHook) BeforeProcess(c *contexts.ContextHook) (context.Context, error) { - return c.Ctx, nil -} - -func (h *SlowQueryHook) AfterProcess(c *contexts.ContextHook) error { - if c.ExecuteTime >= h.Threshold { - // 8 is the amount of skips passed to runtime.Caller, so that in the log the correct function - // is being displayed (the function that ultimately wants to execute the query in the code) - // instead of the function of the slow query hook being called. - h.Logger.Log(8, log.WARN, "[Slow SQL Query] %s %v - %v", c.SQL, c.Args, c.ExecuteTime) - } - return nil -} diff --git a/models/db/engine_dump.go b/models/db/engine_dump.go new file mode 100644 index 0000000000..63f2d4e093 --- /dev/null +++ b/models/db/engine_dump.go @@ -0,0 +1,33 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package db + +import "xorm.io/xorm/schemas" + +// DumpDatabase dumps all data from database according the special database SQL syntax to file system. +func DumpDatabase(filePath, dbType string) error { + var tbs []*schemas.Table + for _, t := range registeredModels { + t, err := xormEngine.TableInfo(t) + if err != nil { + return err + } + tbs = append(tbs, t) + } + + type Version struct { + ID int64 `xorm:"pk autoincr"` + Version int64 + } + t, err := xormEngine.TableInfo(&Version{}) + if err != nil { + return err + } + tbs = append(tbs, t) + + if dbType != "" { + return xormEngine.DumpTablesToFile(tbs, filePath, schemas.DBType(dbType)) + } + return xormEngine.DumpTablesToFile(tbs, filePath) +} diff --git a/models/db/engine_hook.go b/models/db/engine_hook.go new file mode 100644 index 0000000000..b4c543c3dd --- /dev/null +++ b/models/db/engine_hook.go @@ -0,0 +1,34 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package db + +import ( + "context" + "time" + + "code.gitea.io/gitea/modules/log" + + "xorm.io/xorm/contexts" +) + +type SlowQueryHook struct { + Threshold time.Duration + Logger log.Logger +} + +var _ contexts.Hook = (*SlowQueryHook)(nil) + +func (*SlowQueryHook) BeforeProcess(c *contexts.ContextHook) (context.Context, error) { + return c.Ctx, nil +} + +func (h *SlowQueryHook) AfterProcess(c *contexts.ContextHook) error { + if c.ExecuteTime >= h.Threshold { + // 8 is the amount of skips passed to runtime.Caller, so that in the log the correct function + // is being displayed (the function that ultimately wants to execute the query in the code) + // instead of the function of the slow query hook being called. + h.Logger.Log(8, log.WARN, "[Slow SQL Query] %s %v - %v", c.SQL, c.Args, c.ExecuteTime) + } + return nil +} diff --git a/models/db/engine_init.go b/models/db/engine_init.go new file mode 100644 index 0000000000..da85018957 --- /dev/null +++ b/models/db/engine_init.go @@ -0,0 +1,140 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package db + +import ( + "context" + "fmt" + "strings" + + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + + "xorm.io/xorm" + "xorm.io/xorm/names" +) + +func init() { + gonicNames := []string{"SSL", "UID"} + for _, name := range gonicNames { + names.LintGonicMapper[name] = true + } +} + +// newXORMEngine returns a new XORM engine from the configuration +func newXORMEngine() (*xorm.Engine, error) { + connStr, err := setting.DBConnStr() + if err != nil { + return nil, err + } + + var engine *xorm.Engine + + if setting.Database.Type.IsPostgreSQL() && len(setting.Database.Schema) > 0 { + // OK whilst we sort out our schema issues - create a schema aware postgres + registerPostgresSchemaDriver() + engine, err = xorm.NewEngine("postgresschema", connStr) + } else { + engine, err = xorm.NewEngine(setting.Database.Type.String(), connStr) + } + + if err != nil { + return nil, err + } + if setting.Database.Type == "mysql" { + engine.Dialect().SetParams(map[string]string{"rowFormat": "DYNAMIC"}) + } else if setting.Database.Type == "mssql" { + engine.Dialect().SetParams(map[string]string{"DEFAULT_VARCHAR": "nvarchar"}) + } + engine.SetSchema(setting.Database.Schema) + return engine, nil +} + +// InitEngine initializes the xorm.Engine and sets it as db.DefaultContext +func InitEngine(ctx context.Context) error { + xe, err := newXORMEngine() + if err != nil { + if strings.Contains(err.Error(), "SQLite3 support") { + return fmt.Errorf(`sqlite3 requires: -tags sqlite,sqlite_unlock_notify%s%w`, "\n", err) + } + return fmt.Errorf("failed to connect to database: %w", err) + } + + xe.SetMapper(names.GonicMapper{}) + // WARNING: for serv command, MUST remove the output to os.stdout, + // so use log file to instead print to stdout. + xe.SetLogger(NewXORMLogger(setting.Database.LogSQL)) + xe.ShowSQL(setting.Database.LogSQL) + xe.SetMaxOpenConns(setting.Database.MaxOpenConns) + xe.SetMaxIdleConns(setting.Database.MaxIdleConns) + xe.SetConnMaxLifetime(setting.Database.ConnMaxLifetime) + xe.SetDefaultContext(ctx) + + if setting.Database.SlowQueryThreshold > 0 { + xe.AddHook(&SlowQueryHook{ + Threshold: setting.Database.SlowQueryThreshold, + Logger: log.GetLogger("xorm"), + }) + } + + SetDefaultEngine(ctx, xe) + return nil +} + +// SetDefaultEngine sets the default engine for db +func SetDefaultEngine(ctx context.Context, eng *xorm.Engine) { + xormEngine = eng + DefaultContext = &Context{Context: ctx, engine: xormEngine} +} + +// UnsetDefaultEngine closes and unsets the default engine +// We hope the SetDefaultEngine and UnsetDefaultEngine can be paired, but it's impossible now, +// there are many calls to InitEngine -> SetDefaultEngine directly to overwrite the `xormEngine` and DefaultContext without close +// Global database engine related functions are all racy and there is no graceful close right now. +func UnsetDefaultEngine() { + if xormEngine != nil { + _ = xormEngine.Close() + xormEngine = nil + } + DefaultContext = nil +} + +// InitEngineWithMigration initializes a new xorm.Engine and sets it as the db.DefaultContext +// This function must never call .Sync() if the provided migration function fails. +// When called from the "doctor" command, the migration function is a version check +// that prevents the doctor from fixing anything in the database if the migration level +// is different from the expected value. +func InitEngineWithMigration(ctx context.Context, migrateFunc func(*xorm.Engine) error) (err error) { + if err = InitEngine(ctx); err != nil { + return err + } + + if err = xormEngine.Ping(); err != nil { + return err + } + + preprocessDatabaseCollation(xormEngine) + + // We have to run migrateFunc here in case the user is re-running installation on a previously created DB. + // If we do not then table schemas will be changed and there will be conflicts when the migrations run properly. + // + // Installation should only be being re-run if users want to recover an old database. + // However, we should think carefully about should we support re-install on an installed instance, + // as there may be other problems due to secret reinitialization. + if err = migrateFunc(xormEngine); err != nil { + return fmt.Errorf("migrate: %w", err) + } + + if err = SyncAllTables(); err != nil { + return fmt.Errorf("sync database struct error: %w", err) + } + + for _, initFunc := range registeredInitFuncs { + if err := initFunc(); err != nil { + return fmt.Errorf("initFunc failed: %w", err) + } + } + + return nil +} diff --git a/models/db/name.go b/models/db/name.go index 51be33a8bc..55c9dffb6a 100644 --- a/models/db/name.go +++ b/models/db/name.go @@ -16,7 +16,7 @@ var ( // ErrNameEmpty name is empty error ErrNameEmpty = util.SilentWrap{Message: "name is empty", Err: util.ErrInvalidArgument} - // AlphaDashDotPattern characters prohibited in a user name (anything except A-Za-z0-9_.-) + // AlphaDashDotPattern characters prohibited in a username (anything except A-Za-z0-9_.-) AlphaDashDotPattern = regexp.MustCompile(`[^\w-\.]`) ) diff --git a/models/db/sequence.go b/models/db/sequence.go index f49ad935de..9adc5113ac 100644 --- a/models/db/sequence.go +++ b/models/db/sequence.go @@ -17,11 +17,11 @@ func CountBadSequences(_ context.Context) (int64, error) { return 0, nil } - sess := x.NewSession() + sess := xormEngine.NewSession() defer sess.Close() var sequences []string - schema := x.Dialect().URI().Schema + schema := xormEngine.Dialect().URI().Schema sess.Engine().SetSchema("") if err := sess.Table("information_schema.sequences").Cols("sequence_name").Where("sequence_name LIKE 'tmp_recreate__%_id_seq%' AND sequence_catalog = ?", setting.Database.Name).Find(&sequences); err != nil { @@ -38,7 +38,7 @@ func FixBadSequences(_ context.Context) error { return nil } - sess := x.NewSession() + sess := xormEngine.NewSession() defer sess.Close() if err := sess.Begin(); err != nil { return err diff --git a/models/error.go b/models/error.go deleted file mode 100644 index 865d5a442f..0000000000 --- a/models/error.go +++ /dev/null @@ -1,510 +0,0 @@ -// Copyright 2015 The Gogs Authors. All rights reserved. -// Copyright 2019 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package models - -import ( - "fmt" - - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/util" -) - -// ErrUserOwnRepos represents a "UserOwnRepos" kind of error. -type ErrUserOwnRepos struct { - UID int64 -} - -// IsErrUserOwnRepos checks if an error is a ErrUserOwnRepos. -func IsErrUserOwnRepos(err error) bool { - _, ok := err.(ErrUserOwnRepos) - return ok -} - -func (err ErrUserOwnRepos) Error() string { - return fmt.Sprintf("user still has ownership of repositories [uid: %d]", err.UID) -} - -// ErrUserHasOrgs represents a "UserHasOrgs" kind of error. -type ErrUserHasOrgs struct { - UID int64 -} - -// IsErrUserHasOrgs checks if an error is a ErrUserHasOrgs. -func IsErrUserHasOrgs(err error) bool { - _, ok := err.(ErrUserHasOrgs) - return ok -} - -func (err ErrUserHasOrgs) Error() string { - return fmt.Sprintf("user still has membership of organizations [uid: %d]", err.UID) -} - -// ErrUserOwnPackages notifies that the user (still) owns the packages. -type ErrUserOwnPackages struct { - UID int64 -} - -// IsErrUserOwnPackages checks if an error is an ErrUserOwnPackages. -func IsErrUserOwnPackages(err error) bool { - _, ok := err.(ErrUserOwnPackages) - return ok -} - -func (err ErrUserOwnPackages) Error() string { - return fmt.Sprintf("user still has ownership of packages [uid: %d]", err.UID) -} - -// ErrDeleteLastAdminUser represents a "DeleteLastAdminUser" kind of error. -type ErrDeleteLastAdminUser struct { - UID int64 -} - -// IsErrDeleteLastAdminUser checks if an error is a ErrDeleteLastAdminUser. -func IsErrDeleteLastAdminUser(err error) bool { - _, ok := err.(ErrDeleteLastAdminUser) - return ok -} - -func (err ErrDeleteLastAdminUser) Error() string { - return fmt.Sprintf("can not delete the last admin user [uid: %d]", err.UID) -} - -// ErrInvalidCloneAddr represents a "InvalidCloneAddr" kind of error. -type ErrInvalidCloneAddr struct { - Host string - IsURLError bool - IsInvalidPath bool - IsProtocolInvalid bool - IsPermissionDenied bool - LocalPath bool -} - -// IsErrInvalidCloneAddr checks if an error is a ErrInvalidCloneAddr. -func IsErrInvalidCloneAddr(err error) bool { - _, ok := err.(*ErrInvalidCloneAddr) - return ok -} - -func (err *ErrInvalidCloneAddr) Error() string { - if err.IsInvalidPath { - return fmt.Sprintf("migration/cloning from '%s' is not allowed: the provided path is invalid", err.Host) - } - if err.IsProtocolInvalid { - return fmt.Sprintf("migration/cloning from '%s' is not allowed: the provided url protocol is not allowed", err.Host) - } - if err.IsPermissionDenied { - return fmt.Sprintf("migration/cloning from '%s' is not allowed.", err.Host) - } - if err.IsURLError { - return fmt.Sprintf("migration/cloning from '%s' is not allowed: the provided url is invalid", err.Host) - } - - return fmt.Sprintf("migration/cloning from '%s' is not allowed", err.Host) -} - -func (err *ErrInvalidCloneAddr) Unwrap() error { - return util.ErrInvalidArgument -} - -// ErrUpdateTaskNotExist represents a "UpdateTaskNotExist" kind of error. -type ErrUpdateTaskNotExist struct { - UUID string -} - -// IsErrUpdateTaskNotExist checks if an error is a ErrUpdateTaskNotExist. -func IsErrUpdateTaskNotExist(err error) bool { - _, ok := err.(ErrUpdateTaskNotExist) - return ok -} - -func (err ErrUpdateTaskNotExist) Error() string { - return fmt.Sprintf("update task does not exist [uuid: %s]", err.UUID) -} - -func (err ErrUpdateTaskNotExist) Unwrap() error { - return util.ErrNotExist -} - -// ErrInvalidTagName represents a "InvalidTagName" kind of error. -type ErrInvalidTagName struct { - TagName string -} - -// IsErrInvalidTagName checks if an error is a ErrInvalidTagName. -func IsErrInvalidTagName(err error) bool { - _, ok := err.(ErrInvalidTagName) - return ok -} - -func (err ErrInvalidTagName) Error() string { - return fmt.Sprintf("release tag name is not valid [tag_name: %s]", err.TagName) -} - -func (err ErrInvalidTagName) Unwrap() error { - return util.ErrInvalidArgument -} - -// ErrProtectedTagName represents a "ProtectedTagName" kind of error. -type ErrProtectedTagName struct { - TagName string -} - -// IsErrProtectedTagName checks if an error is a ErrProtectedTagName. -func IsErrProtectedTagName(err error) bool { - _, ok := err.(ErrProtectedTagName) - return ok -} - -func (err ErrProtectedTagName) Error() string { - return fmt.Sprintf("release tag name is protected [tag_name: %s]", err.TagName) -} - -func (err ErrProtectedTagName) Unwrap() error { - return util.ErrPermissionDenied -} - -// ErrRepoFileAlreadyExists represents a "RepoFileAlreadyExist" kind of error. -type ErrRepoFileAlreadyExists struct { - Path string -} - -// IsErrRepoFileAlreadyExists checks if an error is a ErrRepoFileAlreadyExists. -func IsErrRepoFileAlreadyExists(err error) bool { - _, ok := err.(ErrRepoFileAlreadyExists) - return ok -} - -func (err ErrRepoFileAlreadyExists) Error() string { - return fmt.Sprintf("repository file already exists [path: %s]", err.Path) -} - -func (err ErrRepoFileAlreadyExists) Unwrap() error { - return util.ErrAlreadyExist -} - -// ErrRepoFileDoesNotExist represents a "RepoFileDoesNotExist" kind of error. -type ErrRepoFileDoesNotExist struct { - Path string - Name string -} - -// IsErrRepoFileDoesNotExist checks if an error is a ErrRepoDoesNotExist. -func IsErrRepoFileDoesNotExist(err error) bool { - _, ok := err.(ErrRepoFileDoesNotExist) - return ok -} - -func (err ErrRepoFileDoesNotExist) Error() string { - return fmt.Sprintf("repository file does not exist [path: %s]", err.Path) -} - -func (err ErrRepoFileDoesNotExist) Unwrap() error { - return util.ErrNotExist -} - -// ErrFilenameInvalid represents a "FilenameInvalid" kind of error. -type ErrFilenameInvalid struct { - Path string -} - -// IsErrFilenameInvalid checks if an error is an ErrFilenameInvalid. -func IsErrFilenameInvalid(err error) bool { - _, ok := err.(ErrFilenameInvalid) - return ok -} - -func (err ErrFilenameInvalid) Error() string { - return fmt.Sprintf("path contains a malformed path component [path: %s]", err.Path) -} - -func (err ErrFilenameInvalid) Unwrap() error { - return util.ErrInvalidArgument -} - -// ErrUserCannotCommit represents "UserCannotCommit" kind of error. -type ErrUserCannotCommit struct { - UserName string -} - -// IsErrUserCannotCommit checks if an error is an ErrUserCannotCommit. -func IsErrUserCannotCommit(err error) bool { - _, ok := err.(ErrUserCannotCommit) - return ok -} - -func (err ErrUserCannotCommit) Error() string { - return fmt.Sprintf("user cannot commit to repo [user: %s]", err.UserName) -} - -func (err ErrUserCannotCommit) Unwrap() error { - return util.ErrPermissionDenied -} - -// ErrFilePathInvalid represents a "FilePathInvalid" kind of error. -type ErrFilePathInvalid struct { - Message string - Path string - Name string - Type git.EntryMode -} - -// IsErrFilePathInvalid checks if an error is an ErrFilePathInvalid. -func IsErrFilePathInvalid(err error) bool { - _, ok := err.(ErrFilePathInvalid) - return ok -} - -func (err ErrFilePathInvalid) Error() string { - if err.Message != "" { - return err.Message - } - return fmt.Sprintf("path is invalid [path: %s]", err.Path) -} - -func (err ErrFilePathInvalid) Unwrap() error { - return util.ErrInvalidArgument -} - -// ErrFilePathProtected represents a "FilePathProtected" kind of error. -type ErrFilePathProtected struct { - Message string - Path string -} - -// IsErrFilePathProtected checks if an error is an ErrFilePathProtected. -func IsErrFilePathProtected(err error) bool { - _, ok := err.(ErrFilePathProtected) - return ok -} - -func (err ErrFilePathProtected) Error() string { - if err.Message != "" { - return err.Message - } - return fmt.Sprintf("path is protected and can not be changed [path: %s]", err.Path) -} - -func (err ErrFilePathProtected) Unwrap() error { - return util.ErrPermissionDenied -} - -// ErrDisallowedToMerge represents an error that a branch is protected and the current user is not allowed to modify it. -type ErrDisallowedToMerge struct { - Reason string -} - -// IsErrDisallowedToMerge checks if an error is an ErrDisallowedToMerge. -func IsErrDisallowedToMerge(err error) bool { - _, ok := err.(ErrDisallowedToMerge) - return ok -} - -func (err ErrDisallowedToMerge) Error() string { - return fmt.Sprintf("not allowed to merge [reason: %s]", err.Reason) -} - -func (err ErrDisallowedToMerge) Unwrap() error { - return util.ErrPermissionDenied -} - -// ErrTagAlreadyExists represents an error that tag with such name already exists. -type ErrTagAlreadyExists struct { - TagName string -} - -// IsErrTagAlreadyExists checks if an error is an ErrTagAlreadyExists. -func IsErrTagAlreadyExists(err error) bool { - _, ok := err.(ErrTagAlreadyExists) - return ok -} - -func (err ErrTagAlreadyExists) Error() string { - return fmt.Sprintf("tag already exists [name: %s]", err.TagName) -} - -func (err ErrTagAlreadyExists) Unwrap() error { - return util.ErrAlreadyExist -} - -// ErrSHADoesNotMatch represents a "SHADoesNotMatch" kind of error. -type ErrSHADoesNotMatch struct { - Path string - GivenSHA string - CurrentSHA string -} - -// IsErrSHADoesNotMatch checks if an error is a ErrSHADoesNotMatch. -func IsErrSHADoesNotMatch(err error) bool { - _, ok := err.(ErrSHADoesNotMatch) - return ok -} - -func (err ErrSHADoesNotMatch) Error() string { - return fmt.Sprintf("sha does not match [given: %s, expected: %s]", err.GivenSHA, err.CurrentSHA) -} - -// ErrSHANotFound represents a "SHADoesNotMatch" kind of error. -type ErrSHANotFound struct { - SHA string -} - -// IsErrSHANotFound checks if an error is a ErrSHANotFound. -func IsErrSHANotFound(err error) bool { - _, ok := err.(ErrSHANotFound) - return ok -} - -func (err ErrSHANotFound) Error() string { - return fmt.Sprintf("sha not found [%s]", err.SHA) -} - -func (err ErrSHANotFound) Unwrap() error { - return util.ErrNotExist -} - -// ErrCommitIDDoesNotMatch represents a "CommitIDDoesNotMatch" kind of error. -type ErrCommitIDDoesNotMatch struct { - GivenCommitID string - CurrentCommitID string -} - -// IsErrCommitIDDoesNotMatch checks if an error is a ErrCommitIDDoesNotMatch. -func IsErrCommitIDDoesNotMatch(err error) bool { - _, ok := err.(ErrCommitIDDoesNotMatch) - return ok -} - -func (err ErrCommitIDDoesNotMatch) Error() string { - return fmt.Sprintf("file CommitID does not match [given: %s, expected: %s]", err.GivenCommitID, err.CurrentCommitID) -} - -// ErrSHAOrCommitIDNotProvided represents a "SHAOrCommitIDNotProvided" kind of error. -type ErrSHAOrCommitIDNotProvided struct{} - -// IsErrSHAOrCommitIDNotProvided checks if an error is a ErrSHAOrCommitIDNotProvided. -func IsErrSHAOrCommitIDNotProvided(err error) bool { - _, ok := err.(ErrSHAOrCommitIDNotProvided) - return ok -} - -func (err ErrSHAOrCommitIDNotProvided) Error() string { - return "a SHA or commit ID must be proved when updating a file" -} - -// ErrInvalidMergeStyle represents an error if merging with disabled merge strategy -type ErrInvalidMergeStyle struct { - ID int64 - Style repo_model.MergeStyle -} - -// IsErrInvalidMergeStyle checks if an error is a ErrInvalidMergeStyle. -func IsErrInvalidMergeStyle(err error) bool { - _, ok := err.(ErrInvalidMergeStyle) - return ok -} - -func (err ErrInvalidMergeStyle) Error() string { - return fmt.Sprintf("merge strategy is not allowed or is invalid [repo_id: %d, strategy: %s]", - err.ID, err.Style) -} - -func (err ErrInvalidMergeStyle) Unwrap() error { - return util.ErrInvalidArgument -} - -// ErrMergeConflicts represents an error if merging fails with a conflict -type ErrMergeConflicts struct { - Style repo_model.MergeStyle - StdOut string - StdErr string - Err error -} - -// IsErrMergeConflicts checks if an error is a ErrMergeConflicts. -func IsErrMergeConflicts(err error) bool { - _, ok := err.(ErrMergeConflicts) - return ok -} - -func (err ErrMergeConflicts) Error() string { - return fmt.Sprintf("Merge Conflict Error: %v: %s\n%s", err.Err, err.StdErr, err.StdOut) -} - -// ErrMergeUnrelatedHistories represents an error if merging fails due to unrelated histories -type ErrMergeUnrelatedHistories struct { - Style repo_model.MergeStyle - StdOut string - StdErr string - Err error -} - -// IsErrMergeUnrelatedHistories checks if an error is a ErrMergeUnrelatedHistories. -func IsErrMergeUnrelatedHistories(err error) bool { - _, ok := err.(ErrMergeUnrelatedHistories) - return ok -} - -func (err ErrMergeUnrelatedHistories) Error() string { - return fmt.Sprintf("Merge UnrelatedHistories Error: %v: %s\n%s", err.Err, err.StdErr, err.StdOut) -} - -// ErrMergeDivergingFastForwardOnly represents an error if a fast-forward-only merge fails because the branches diverge -type ErrMergeDivergingFastForwardOnly struct { - StdOut string - StdErr string - Err error -} - -// IsErrMergeDivergingFastForwardOnly checks if an error is a ErrMergeDivergingFastForwardOnly. -func IsErrMergeDivergingFastForwardOnly(err error) bool { - _, ok := err.(ErrMergeDivergingFastForwardOnly) - return ok -} - -func (err ErrMergeDivergingFastForwardOnly) Error() string { - return fmt.Sprintf("Merge DivergingFastForwardOnly Error: %v: %s\n%s", err.Err, err.StdErr, err.StdOut) -} - -// ErrRebaseConflicts represents an error if rebase fails with a conflict -type ErrRebaseConflicts struct { - Style repo_model.MergeStyle - CommitSHA string - StdOut string - StdErr string - Err error -} - -// IsErrRebaseConflicts checks if an error is a ErrRebaseConflicts. -func IsErrRebaseConflicts(err error) bool { - _, ok := err.(ErrRebaseConflicts) - return ok -} - -func (err ErrRebaseConflicts) Error() string { - return fmt.Sprintf("Rebase Error: %v: Whilst Rebasing: %s\n%s\n%s", err.Err, err.CommitSHA, err.StdErr, err.StdOut) -} - -// ErrPullRequestHasMerged represents a "PullRequestHasMerged"-error -type ErrPullRequestHasMerged struct { - ID int64 - IssueID int64 - HeadRepoID int64 - BaseRepoID int64 - HeadBranch string - BaseBranch string -} - -// IsErrPullRequestHasMerged checks if an error is a ErrPullRequestHasMerged. -func IsErrPullRequestHasMerged(err error) bool { - _, ok := err.(ErrPullRequestHasMerged) - return ok -} - -// Error does pretty-printing :D -func (err ErrPullRequestHasMerged) Error() string { - return fmt.Sprintf("pull request has merged [id: %d, issue_id: %d, head_repo_id: %d, base_repo_id: %d, head_branch: %s, base_branch: %s]", - err.ID, err.IssueID, err.HeadRepoID, err.BaseRepoID, err.HeadBranch, err.BaseBranch) -} diff --git a/models/organization/org_user.go b/models/organization/org_user.go index 1d3b2fab44..08d936d922 100644 --- a/models/organization/org_user.go +++ b/models/organization/org_user.go @@ -36,6 +36,21 @@ func init() { db.RegisterModel(new(OrgUser)) } +// ErrUserHasOrgs represents a "UserHasOrgs" kind of error. +type ErrUserHasOrgs struct { + UID int64 +} + +// IsErrUserHasOrgs checks if an error is a ErrUserHasOrgs. +func IsErrUserHasOrgs(err error) bool { + _, ok := err.(ErrUserHasOrgs) + return ok +} + +func (err ErrUserHasOrgs) Error() string { + return fmt.Sprintf("user still has membership of organizations [uid: %d]", err.UID) +} + // GetOrganizationCount returns count of membership of organization of the user. func GetOrganizationCount(ctx context.Context, u *user_model.User) (int64, error) { return db.GetEngine(ctx). diff --git a/models/packages/package.go b/models/packages/package.go index 417d62d199..c12f345f0e 100644 --- a/models/packages/package.go +++ b/models/packages/package.go @@ -301,6 +301,21 @@ func FindUnreferencedPackages(ctx context.Context) ([]*Package, error) { Find(&ps) } +// ErrUserOwnPackages notifies that the user (still) owns the packages. +type ErrUserOwnPackages struct { + UID int64 +} + +// IsErrUserOwnPackages checks if an error is an ErrUserOwnPackages. +func IsErrUserOwnPackages(err error) bool { + _, ok := err.(ErrUserOwnPackages) + return ok +} + +func (err ErrUserOwnPackages) Error() string { + return fmt.Sprintf("user still has ownership of packages [uid: %d]", err.UID) +} + // HasOwnerPackages tests if a user/org has accessible packages func HasOwnerPackages(ctx context.Context, ownerID int64) (bool, error) { return db.GetEngine(ctx). diff --git a/models/repo/repo.go b/models/repo/repo.go index 8d211caf40..2d9b9de88d 100644 --- a/models/repo/repo.go +++ b/models/repo/repo.go @@ -37,7 +37,7 @@ type ErrUserDoesNotHaveAccessToRepo struct { RepoName string } -// IsErrUserDoesNotHaveAccessToRepo checks if an error is a ErrRepoFileAlreadyExists. +// IsErrUserDoesNotHaveAccessToRepo checks if an error is a ErrUserDoesNotHaveAccessToRepo. func IsErrUserDoesNotHaveAccessToRepo(err error) bool { _, ok := err.(ErrUserDoesNotHaveAccessToRepo) return ok @@ -866,6 +866,21 @@ func (repo *Repository) TemplateRepo(ctx context.Context) *Repository { return repo } +// ErrUserOwnRepos represents a "UserOwnRepos" kind of error. +type ErrUserOwnRepos struct { + UID int64 +} + +// IsErrUserOwnRepos checks if an error is a ErrUserOwnRepos. +func IsErrUserOwnRepos(err error) bool { + _, ok := err.(ErrUserOwnRepos) + return ok +} + +func (err ErrUserOwnRepos) Error() string { + return fmt.Sprintf("user still has ownership of repositories [uid: %d]", err.UID) +} + type CountRepositoryOptions struct { OwnerID int64 Private optional.Option[bool] diff --git a/models/user/user.go b/models/user/user.go index bd92693b6e..72caafc3ba 100644 --- a/models/user/user.go +++ b/models/user/user.go @@ -788,6 +788,21 @@ func createUser(ctx context.Context, u *User, meta *Meta, createdByAdmin bool, o return committer.Commit() } +// ErrDeleteLastAdminUser represents a "DeleteLastAdminUser" kind of error. +type ErrDeleteLastAdminUser struct { + UID int64 +} + +// IsErrDeleteLastAdminUser checks if an error is a ErrDeleteLastAdminUser. +func IsErrDeleteLastAdminUser(err error) bool { + _, ok := err.(ErrDeleteLastAdminUser) + return ok +} + +func (err ErrDeleteLastAdminUser) Error() string { + return fmt.Sprintf("can not delete the last admin user [uid: %d]", err.UID) +} + // IsLastAdminUser check whether user is the last admin func IsLastAdminUser(ctx context.Context, user *User) bool { if user.IsAdmin && CountUsers(ctx, &CountUserFilter{IsAdmin: optional.Some(true)}) <= 1 { diff --git a/modules/git/batch_reader.go b/modules/git/batch_reader.go index 7dfda72155..532dbad989 100644 --- a/modules/git/batch_reader.go +++ b/modules/git/batch_reader.go @@ -7,10 +7,8 @@ import ( "bufio" "bytes" "context" - "fmt" "io" "math" - "runtime" "strconv" "strings" @@ -32,7 +30,6 @@ type WriteCloserError interface { func ensureValidGitRepository(ctx context.Context, repoPath string) error { stderr := strings.Builder{} err := NewCommand(ctx, "rev-parse"). - SetDescription(fmt.Sprintf("%s rev-parse [repo_path: %s]", GitExecutable, repoPath)). Run(&RunOpts{ Dir: repoPath, Stderr: &stderr, @@ -62,13 +59,9 @@ func catFileBatchCheck(ctx context.Context, repoPath string) (WriteCloserError, cancel() }() - _, filename, line, _ := runtime.Caller(2) - filename = strings.TrimPrefix(filename, callerPrefix) - go func() { stderr := strings.Builder{} err := NewCommand(ctx, "cat-file", "--batch-check"). - SetDescription(fmt.Sprintf("%s cat-file --batch-check [repo_path: %s] (%s:%d)", GitExecutable, repoPath, filename, line)). Run(&RunOpts{ Dir: repoPath, Stdin: batchStdinReader, @@ -114,13 +107,9 @@ func catFileBatch(ctx context.Context, repoPath string) (WriteCloserError, *bufi cancel() }() - _, filename, line, _ := runtime.Caller(2) - filename = strings.TrimPrefix(filename, callerPrefix) - go func() { stderr := strings.Builder{} err := NewCommand(ctx, "cat-file", "--batch"). - SetDescription(fmt.Sprintf("%s cat-file --batch [repo_path: %s] (%s:%d)", GitExecutable, repoPath, filename, line)). Run(&RunOpts{ Dir: repoPath, Stdin: batchStdinReader, @@ -320,13 +309,6 @@ func ParseTreeLine(objectFormat ObjectFormat, rd *bufio.Reader, modeBuf, fnameBu return mode, fname, sha, n, err } -var callerPrefix string - -func init() { - _, filename, _, _ := runtime.Caller(0) - callerPrefix = strings.TrimSuffix(filename, "modules/git/batch_reader.go") -} - func DiscardFull(rd *bufio.Reader, discard int64) error { if discard > math.MaxInt32 { n, err := rd.Discard(math.MaxInt32) diff --git a/modules/git/blame.go b/modules/git/blame.go index a9b2706f21..cad720edf4 100644 --- a/modules/git/blame.go +++ b/modules/git/blame.go @@ -7,7 +7,6 @@ import ( "bufio" "bytes" "context" - "fmt" "io" "os" @@ -142,9 +141,7 @@ func CreateBlameReader(ctx context.Context, objectFormat ObjectFormat, repoPath // There is no equivalent on Windows. May be implemented if Gitea uses an external git backend. cmd.AddOptionValues("--ignore-revs-file", *ignoreRevsFile) } - cmd.AddDynamicArguments(commit.ID.String()). - AddDashesAndList(file). - SetDescription(fmt.Sprintf("GetBlame [repo_path: %s]", repoPath)) + cmd.AddDynamicArguments(commit.ID.String()).AddDashesAndList(file) reader, stdout, err := os.Pipe() if err != nil { if ignoreRevsFile != nil { diff --git a/modules/git/command.go b/modules/git/command.go index 22cb275ab2..b231c3beea 100644 --- a/modules/git/command.go +++ b/modules/git/command.go @@ -12,6 +12,7 @@ import ( "io" "os" "os/exec" + "path/filepath" "runtime" "strings" "time" @@ -43,18 +44,24 @@ type Command struct { prog string args []string parentContext context.Context - desc string globalArgsLength int brokenArgs []string } -func (c *Command) String() string { - return c.toString(false) +func logArgSanitize(arg string) string { + if strings.Contains(arg, "://") && strings.Contains(arg, "@") { + return util.SanitizeCredentialURLs(arg) + } else if filepath.IsAbs(arg) { + base := filepath.Base(arg) + dir := filepath.Dir(arg) + return filepath.Join(filepath.Base(dir), base) + } + return arg } -func (c *Command) toString(sanitizing bool) string { +func (c *Command) LogString() string { // WARNING: this function is for debugging purposes only. It's much better than old code (which only joins args with space), - // It's impossible to make a simple and 100% correct implementation of argument quoting for different platforms. + // It's impossible to make a simple and 100% correct implementation of argument quoting for different platforms here. debugQuote := func(s string) string { if strings.ContainsAny(s, " `'\"\t\r\n") { return fmt.Sprintf("%q", s) @@ -63,12 +70,11 @@ func (c *Command) toString(sanitizing bool) string { } a := make([]string, 0, len(c.args)+1) a = append(a, debugQuote(c.prog)) - for _, arg := range c.args { - if sanitizing && (strings.Contains(arg, "://") && strings.Contains(arg, "@")) { - a = append(a, debugQuote(util.SanitizeCredentialURLs(arg))) - } else { - a = append(a, debugQuote(arg)) - } + if c.globalArgsLength > 0 { + a = append(a, "...global...") + } + for i := c.globalArgsLength; i < len(c.args); i++ { + a = append(a, debugQuote(logArgSanitize(c.args[i]))) } return strings.Join(a, " ") } @@ -112,12 +118,6 @@ func (c *Command) SetParentContext(ctx context.Context) *Command { return c } -// SetDescription sets the description for this command which be returned on c.String() -func (c *Command) SetDescription(desc string) *Command { - c.desc = desc - return c -} - // isSafeArgumentValue checks if the argument is safe to be used as a value (not an option) func isSafeArgumentValue(s string) bool { return s == "" || s[0] != '-' @@ -271,8 +271,12 @@ var ErrBrokenCommand = errors.New("git command is broken") // Run runs the command with the RunOpts func (c *Command) Run(opts *RunOpts) error { + return c.run(1, opts) +} + +func (c *Command) run(skip int, opts *RunOpts) error { if len(c.brokenArgs) != 0 { - log.Error("git command is broken: %s, broken args: %s", c.String(), strings.Join(c.brokenArgs, " ")) + log.Error("git command is broken: %s, broken args: %s", c.LogString(), strings.Join(c.brokenArgs, " ")) return ErrBrokenCommand } if opts == nil { @@ -285,20 +289,14 @@ func (c *Command) Run(opts *RunOpts) error { timeout = defaultCommandExecutionTimeout } - if len(opts.Dir) == 0 { - log.Debug("git.Command.Run: %s", c) - } else { - log.Debug("git.Command.RunDir(%s): %s", opts.Dir, c) - } - - desc := c.desc - if desc == "" { - if opts.Dir == "" { - desc = fmt.Sprintf("git: %s", c.toString(true)) - } else { - desc = fmt.Sprintf("git(dir:%s): %s", opts.Dir, c.toString(true)) - } + var desc string + callerInfo := util.CallerFuncName(1 /* util */ + 1 /* this */ + skip /* parent */) + if pos := strings.LastIndex(callerInfo, "/"); pos >= 0 { + callerInfo = callerInfo[pos+1:] } + // these logs are for debugging purposes only, so no guarantee of correctness or stability + desc = fmt.Sprintf("git.Run(by:%s, repo:%s): %s", callerInfo, logArgSanitize(opts.Dir), c.LogString()) + log.Debug("git.Command: %s", desc) var ctx context.Context var cancel context.CancelFunc @@ -401,7 +399,7 @@ func IsErrorExitCode(err error, code int) bool { // RunStdString runs the command with options and returns stdout/stderr as string. and store stderr to returned error (err combined with stderr). func (c *Command) RunStdString(opts *RunOpts) (stdout, stderr string, runErr RunStdError) { - stdoutBytes, stderrBytes, err := c.RunStdBytes(opts) + stdoutBytes, stderrBytes, err := c.runStdBytes(opts) stdout = util.UnsafeBytesToString(stdoutBytes) stderr = util.UnsafeBytesToString(stderrBytes) if err != nil { @@ -413,6 +411,10 @@ func (c *Command) RunStdString(opts *RunOpts) (stdout, stderr string, runErr Run // RunStdBytes runs the command with options and returns stdout/stderr as bytes. and store stderr to returned error (err combined with stderr). func (c *Command) RunStdBytes(opts *RunOpts) (stdout, stderr []byte, runErr RunStdError) { + return c.runStdBytes(opts) +} + +func (c *Command) runStdBytes(opts *RunOpts) (stdout, stderr []byte, runErr RunStdError) { if opts == nil { opts = &RunOpts{} } @@ -435,7 +437,7 @@ func (c *Command) RunStdBytes(opts *RunOpts) (stdout, stderr []byte, runErr RunS PipelineFunc: opts.PipelineFunc, } - err := c.Run(newOpts) + err := c.run(2, newOpts) stderr = stderrBuf.Bytes() if err != nil { return nil, stderr, &runStdError{err: err, stderr: util.UnsafeBytesToString(stderr)} diff --git a/modules/git/command_test.go b/modules/git/command_test.go index 9a6228c9ad..0823afd7f7 100644 --- a/modules/git/command_test.go +++ b/modules/git/command_test.go @@ -55,8 +55,8 @@ func TestGitArgument(t *testing.T) { func TestCommandString(t *testing.T) { cmd := NewCommandContextNoGlobals(context.Background(), "a", "-m msg", "it's a test", `say "hello"`) - assert.EqualValues(t, cmd.prog+` a "-m msg" "it's a test" "say \"hello\""`, cmd.String()) + assert.EqualValues(t, cmd.prog+` a "-m msg" "it's a test" "say \"hello\""`, cmd.LogString()) - cmd = NewCommandContextNoGlobals(context.Background(), "url: https://a:b@c/") - assert.EqualValues(t, cmd.prog+` "url: https://sanitized-credential@c/"`, cmd.toString(true)) + cmd = NewCommandContextNoGlobals(context.Background(), "url: https://a:b@c/", "/root/dir-a/dir-b") + assert.EqualValues(t, cmd.prog+` "url: https://sanitized-credential@c/" dir-a/dir-b`, cmd.LogString()) } diff --git a/modules/git/remote.go b/modules/git/remote.go index 7b10e6b663..de8d74eded 100644 --- a/modules/git/remote.go +++ b/modules/git/remote.go @@ -5,8 +5,12 @@ package git import ( "context" + "fmt" + "net/url" + "strings" giturl "code.gitea.io/gitea/modules/git/url" + "code.gitea.io/gitea/modules/util" ) // GetRemoteAddress returns remote url of git repository in the repoPath with special remote name @@ -37,3 +41,61 @@ func GetRemoteURL(ctx context.Context, repoPath, remoteName string) (*giturl.Git } return giturl.Parse(addr) } + +// ErrInvalidCloneAddr represents a "InvalidCloneAddr" kind of error. +type ErrInvalidCloneAddr struct { + Host string + IsURLError bool + IsInvalidPath bool + IsProtocolInvalid bool + IsPermissionDenied bool + LocalPath bool +} + +// IsErrInvalidCloneAddr checks if an error is a ErrInvalidCloneAddr. +func IsErrInvalidCloneAddr(err error) bool { + _, ok := err.(*ErrInvalidCloneAddr) + return ok +} + +func (err *ErrInvalidCloneAddr) Error() string { + if err.IsInvalidPath { + return fmt.Sprintf("migration/cloning from '%s' is not allowed: the provided path is invalid", err.Host) + } + if err.IsProtocolInvalid { + return fmt.Sprintf("migration/cloning from '%s' is not allowed: the provided url protocol is not allowed", err.Host) + } + if err.IsPermissionDenied { + return fmt.Sprintf("migration/cloning from '%s' is not allowed.", err.Host) + } + if err.IsURLError { + return fmt.Sprintf("migration/cloning from '%s' is not allowed: the provided url is invalid", err.Host) + } + + return fmt.Sprintf("migration/cloning from '%s' is not allowed", err.Host) +} + +func (err *ErrInvalidCloneAddr) Unwrap() error { + return util.ErrInvalidArgument +} + +// ParseRemoteAddr checks if given remote address is valid, +// and returns composed URL with needed username and password. +func ParseRemoteAddr(remoteAddr, authUsername, authPassword string) (string, error) { + remoteAddr = strings.TrimSpace(remoteAddr) + // Remote address can be HTTP/HTTPS/Git URL or local path. + if strings.HasPrefix(remoteAddr, "http://") || + strings.HasPrefix(remoteAddr, "https://") || + strings.HasPrefix(remoteAddr, "git://") { + u, err := url.Parse(remoteAddr) + if err != nil { + return "", &ErrInvalidCloneAddr{IsURLError: true, Host: remoteAddr} + } + if len(authUsername)+len(authPassword) > 0 { + u.User = url.UserPassword(authUsername, authPassword) + } + remoteAddr = u.String() + } + + return remoteAddr, nil +} diff --git a/modules/git/repo.go b/modules/git/repo.go index fc6e6e7acc..0993a4ac37 100644 --- a/modules/git/repo.go +++ b/modules/git/repo.go @@ -18,7 +18,6 @@ import ( "time" "code.gitea.io/gitea/modules/proxy" - "code.gitea.io/gitea/modules/util" ) // GPGSettings represents the default GPG settings for this repository @@ -160,12 +159,6 @@ func CloneWithArgs(ctx context.Context, args TrustedCmdArgs, from, to string, op } cmd.AddDashesAndList(from, to) - if strings.Contains(from, "://") && strings.Contains(from, "@") { - cmd.SetDescription(fmt.Sprintf("clone branch %s from %s to %s (shared: %t, mirror: %t, depth: %d)", opts.Branch, util.SanitizeCredentialURLs(from), to, opts.Shared, opts.Mirror, opts.Depth)) - } else { - cmd.SetDescription(fmt.Sprintf("clone branch %s from %s to %s (shared: %t, mirror: %t, depth: %d)", opts.Branch, from, to, opts.Shared, opts.Mirror, opts.Depth)) - } - if opts.Timeout <= 0 { opts.Timeout = -1 } @@ -213,12 +206,6 @@ func Push(ctx context.Context, repoPath string, opts PushOptions) error { } cmd.AddDashesAndList(remoteBranchArgs...) - if strings.Contains(opts.Remote, "://") && strings.Contains(opts.Remote, "@") { - cmd.SetDescription(fmt.Sprintf("push branch %s to %s (force: %t, mirror: %t)", opts.Branch, util.SanitizeCredentialURLs(opts.Remote), opts.Force, opts.Mirror)) - } else { - cmd.SetDescription(fmt.Sprintf("push branch %s to %s (force: %t, mirror: %t)", opts.Branch, opts.Remote, opts.Force, opts.Mirror)) - } - stdout, stderr, err := cmd.RunStdString(&RunOpts{Env: opts.Env, Timeout: opts.Timeout, Dir: repoPath}) if err != nil { if strings.Contains(stderr, "non-fast-forward") { diff --git a/modules/graceful/manager.go b/modules/graceful/manager.go index cac6ce62d6..433e8c4c27 100644 --- a/modules/graceful/manager.go +++ b/modules/graceful/manager.go @@ -9,6 +9,7 @@ import ( "sync" "time" + "code.gitea.io/gitea/modules/gtprof" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/process" "code.gitea.io/gitea/modules/setting" @@ -136,7 +137,7 @@ func (g *Manager) doShutdown() { } g.lock.Lock() g.shutdownCtxCancel() - atShutdownCtx := pprof.WithLabels(g.hammerCtx, pprof.Labels(LifecyclePProfLabel, "post-shutdown")) + atShutdownCtx := pprof.WithLabels(g.hammerCtx, pprof.Labels(gtprof.LabelGracefulLifecycle, "post-shutdown")) pprof.SetGoroutineLabels(atShutdownCtx) for _, fn := range g.toRunAtShutdown { go fn() @@ -167,7 +168,7 @@ func (g *Manager) doHammerTime(d time.Duration) { default: log.Warn("Setting Hammer condition") g.hammerCtxCancel() - atHammerCtx := pprof.WithLabels(g.terminateCtx, pprof.Labels(LifecyclePProfLabel, "post-hammer")) + atHammerCtx := pprof.WithLabels(g.terminateCtx, pprof.Labels(gtprof.LabelGracefulLifecycle, "post-hammer")) pprof.SetGoroutineLabels(atHammerCtx) } g.lock.Unlock() @@ -183,7 +184,7 @@ func (g *Manager) doTerminate() { default: log.Warn("Terminating") g.terminateCtxCancel() - atTerminateCtx := pprof.WithLabels(g.managerCtx, pprof.Labels(LifecyclePProfLabel, "post-terminate")) + atTerminateCtx := pprof.WithLabels(g.managerCtx, pprof.Labels(gtprof.LabelGracefulLifecycle, "post-terminate")) pprof.SetGoroutineLabels(atTerminateCtx) for _, fn := range g.toRunAtTerminate { diff --git a/modules/graceful/manager_common.go b/modules/graceful/manager_common.go index 15dd4406d5..7cfbdfbeb0 100644 --- a/modules/graceful/manager_common.go +++ b/modules/graceful/manager_common.go @@ -8,6 +8,8 @@ import ( "runtime/pprof" "sync" "time" + + "code.gitea.io/gitea/modules/gtprof" ) // FIXME: it seems that there is a bug when using systemd Type=notify: the "Install Page" (INSTALL_LOCK=false) doesn't notify properly. @@ -22,12 +24,6 @@ const ( watchdogMsg systemdNotifyMsg = "WATCHDOG=1" ) -// LifecyclePProfLabel is a label marking manager lifecycle phase -// Making it compliant with prometheus key regex https://prometheus.io/docs/concepts/data_model/#metric-names-and-labels -// would enable someone interested to be able to to continuously gather profiles into pyroscope. -// Other labels for pprof (in "modules/process" package) should also follow this rule. -const LifecyclePProfLabel = "graceful_lifecycle" - func statusMsg(msg string) systemdNotifyMsg { return systemdNotifyMsg("STATUS=" + msg) } @@ -71,10 +67,10 @@ func (g *Manager) prepare(ctx context.Context) { g.hammerCtx, g.hammerCtxCancel = context.WithCancel(ctx) g.managerCtx, g.managerCtxCancel = context.WithCancel(ctx) - g.terminateCtx = pprof.WithLabels(g.terminateCtx, pprof.Labels(LifecyclePProfLabel, "with-terminate")) - g.shutdownCtx = pprof.WithLabels(g.shutdownCtx, pprof.Labels(LifecyclePProfLabel, "with-shutdown")) - g.hammerCtx = pprof.WithLabels(g.hammerCtx, pprof.Labels(LifecyclePProfLabel, "with-hammer")) - g.managerCtx = pprof.WithLabels(g.managerCtx, pprof.Labels(LifecyclePProfLabel, "with-manager")) + g.terminateCtx = pprof.WithLabels(g.terminateCtx, pprof.Labels(gtprof.LabelGracefulLifecycle, "with-terminate")) + g.shutdownCtx = pprof.WithLabels(g.shutdownCtx, pprof.Labels(gtprof.LabelGracefulLifecycle, "with-shutdown")) + g.hammerCtx = pprof.WithLabels(g.hammerCtx, pprof.Labels(gtprof.LabelGracefulLifecycle, "with-hammer")) + g.managerCtx = pprof.WithLabels(g.managerCtx, pprof.Labels(gtprof.LabelGracefulLifecycle, "with-manager")) if !g.setStateTransition(stateInit, stateRunning) { panic("invalid graceful manager state: transition from init to running failed") diff --git a/modules/gtprof/gtprof.go b/modules/gtprof/gtprof.go new file mode 100644 index 0000000000..974b2c9757 --- /dev/null +++ b/modules/gtprof/gtprof.go @@ -0,0 +1,25 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package gtprof + +// This is a Gitea-specific profiling package, +// the name is chosen to distinguish it from the standard pprof tool and "GNU gprof" + +// LabelGracefulLifecycle is a label marking manager lifecycle phase +// Making it compliant with prometheus key regex https://prometheus.io/docs/concepts/data_model/#metric-names-and-labels +// would enable someone interested to be able to continuously gather profiles into pyroscope. +// Other labels for pprof should also follow this rule. +const LabelGracefulLifecycle = "graceful_lifecycle" + +// LabelPid is a label set on goroutines that have a process attached +const LabelPid = "pid" + +// LabelPpid is a label set on goroutines that have a process attached +const LabelPpid = "ppid" + +// LabelProcessType is a label set on goroutines that have a process attached +const LabelProcessType = "process_type" + +// LabelProcessDescription is a label set on goroutines that have a process attached +const LabelProcessDescription = "process_description" diff --git a/modules/log/event_format.go b/modules/log/event_format.go index 0b8d1cec79..8fda0a4980 100644 --- a/modules/log/event_format.go +++ b/modules/log/event_format.go @@ -13,10 +13,9 @@ import ( type Event struct { Time time.Time - GoroutinePid string - Caller string - Filename string - Line int + Caller string + Filename string + Line int Level Level @@ -218,17 +217,16 @@ func EventFormatTextMessage(mode *WriterMode, event *Event, msgFormat string, ms } if flags&Lgopid == Lgopid { - if event.GoroutinePid != "" { - buf = append(buf, '[') - if mode.Colorize { - buf = append(buf, ColorBytes(FgHiYellow)...) - } - buf = append(buf, event.GoroutinePid...) - if mode.Colorize { - buf = append(buf, resetBytes...) - } - buf = append(buf, ']', ' ') + deprecatedGoroutinePid := "no-gopid" // use a dummy value to avoid breaking the log format + buf = append(buf, '[') + if mode.Colorize { + buf = append(buf, ColorBytes(FgHiYellow)...) } + buf = append(buf, deprecatedGoroutinePid...) + if mode.Colorize { + buf = append(buf, resetBytes...) + } + buf = append(buf, ']', ' ') } buf = append(buf, msg...) diff --git a/modules/log/event_format_test.go b/modules/log/event_format_test.go index 7c299a607d..6fd0f36d48 100644 --- a/modules/log/event_format_test.go +++ b/modules/log/event_format_test.go @@ -24,34 +24,32 @@ func TestItoa(t *testing.T) { func TestEventFormatTextMessage(t *testing.T) { res := EventFormatTextMessage(&WriterMode{Prefix: "[PREFIX] ", Colorize: false, Flags: Flags{defined: true, flags: 0xffffffff}}, &Event{ - Time: time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC), - Caller: "caller", - Filename: "filename", - Line: 123, - GoroutinePid: "pid", - Level: ERROR, - Stacktrace: "stacktrace", + Time: time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC), + Caller: "caller", + Filename: "filename", + Line: 123, + Level: ERROR, + Stacktrace: "stacktrace", }, "msg format: %v %v", "arg0", NewColoredValue("arg1", FgBlue), ) - assert.Equal(t, `[PREFIX] 2020/01/02 03:04:05.000000 filename:123:caller [E] [pid] msg format: arg0 arg1 + assert.Equal(t, `[PREFIX] 2020/01/02 03:04:05.000000 filename:123:caller [E] [no-gopid] msg format: arg0 arg1 stacktrace `, string(res)) res = EventFormatTextMessage(&WriterMode{Prefix: "[PREFIX] ", Colorize: true, Flags: Flags{defined: true, flags: 0xffffffff}}, &Event{ - Time: time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC), - Caller: "caller", - Filename: "filename", - Line: 123, - GoroutinePid: "pid", - Level: ERROR, - Stacktrace: "stacktrace", + Time: time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC), + Caller: "caller", + Filename: "filename", + Line: 123, + Level: ERROR, + Stacktrace: "stacktrace", }, "msg format: %v %v", "arg0", NewColoredValue("arg1", FgBlue), ) - assert.Equal(t, "[PREFIX] \x1b[36m2020/01/02 03:04:05.000000 \x1b[0m\x1b[32mfilename:123:\x1b[32mcaller\x1b[0m \x1b[1;31m[E]\x1b[0m [\x1b[93mpid\x1b[0m] msg format: arg0 \x1b[34marg1\x1b[0m\n\tstacktrace\n\n", string(res)) + assert.Equal(t, "[PREFIX] \x1b[36m2020/01/02 03:04:05.000000 \x1b[0m\x1b[32mfilename:123:\x1b[32mcaller\x1b[0m \x1b[1;31m[E]\x1b[0m [\x1b[93mno-gopid\x1b[0m] msg format: arg0 \x1b[34marg1\x1b[0m\n\tstacktrace\n\n", string(res)) } diff --git a/modules/log/flags.go b/modules/log/flags.go index f025159d53..8064c91745 100644 --- a/modules/log/flags.go +++ b/modules/log/flags.go @@ -30,7 +30,7 @@ const ( LUTC // if Ldate or Ltime is set, use UTC rather than the local time zone Llevelinitial // Initial character of the provided level in brackets, eg. [I] for info Llevel // Provided level in brackets [INFO] - Lgopid // the Goroutine-PID of the context + Lgopid // the Goroutine-PID of the context, deprecated and it is always a const value Lmedfile = Lshortfile | Llongfile // last 20 characters of the filename LstdFlags = Ldate | Ltime | Lmedfile | Lshortfuncname | Llevelinitial // default diff --git a/modules/log/groutinelabel.go b/modules/log/groutinelabel.go deleted file mode 100644 index 56d7af42da..0000000000 --- a/modules/log/groutinelabel.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2022 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package log - -import "unsafe" - -//go:linkname runtime_getProfLabel runtime/pprof.runtime_getProfLabel -func runtime_getProfLabel() unsafe.Pointer //nolint - -type labelMap map[string]string - -func getGoroutineLabels() map[string]string { - l := (*labelMap)(runtime_getProfLabel()) - if l == nil { - return nil - } - return *l -} diff --git a/modules/log/groutinelabel_test.go b/modules/log/groutinelabel_test.go deleted file mode 100644 index 34e99653d6..0000000000 --- a/modules/log/groutinelabel_test.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2022 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package log - -import ( - "context" - "runtime/pprof" - "testing" - - "github.com/stretchr/testify/assert" -) - -func Test_getGoroutineLabels(t *testing.T) { - pprof.Do(context.Background(), pprof.Labels(), func(ctx context.Context) { - currentLabels := getGoroutineLabels() - pprof.ForLabels(ctx, func(key, value string) bool { - assert.EqualValues(t, value, currentLabels[key]) - return true - }) - - pprof.Do(ctx, pprof.Labels("Test_getGoroutineLabels", "Test_getGoroutineLabels_child1"), func(ctx context.Context) { - currentLabels := getGoroutineLabels() - pprof.ForLabels(ctx, func(key, value string) bool { - assert.EqualValues(t, value, currentLabels[key]) - return true - }) - if assert.NotNil(t, currentLabels) { - assert.EqualValues(t, "Test_getGoroutineLabels_child1", currentLabels["Test_getGoroutineLabels"]) - } - }) - }) -} diff --git a/modules/log/logger_impl.go b/modules/log/logger_impl.go index d38c6516ed..76dd5f43fb 100644 --- a/modules/log/logger_impl.go +++ b/modules/log/logger_impl.go @@ -200,11 +200,6 @@ func (l *LoggerImpl) Log(skip int, level Level, format string, logArgs ...any) { event.Stacktrace = Stack(skip + 1) } - labels := getGoroutineLabels() - if labels != nil { - event.GoroutinePid = labels["pid"] - } - // get a simple text message without color msgArgs := make([]any, len(logArgs)) copy(msgArgs, logArgs) diff --git a/modules/markup/common/linkify.go b/modules/markup/common/linkify.go index be6ab22b55..52888958fa 100644 --- a/modules/markup/common/linkify.go +++ b/modules/markup/common/linkify.go @@ -24,7 +24,7 @@ type GlobalVarsType struct { LinkRegex *regexp.Regexp // fast matching a URL link, no any extra validation. } -var GlobalVars = sync.OnceValue[*GlobalVarsType](func() *GlobalVarsType { +var GlobalVars = sync.OnceValue(func() *GlobalVarsType { v := &GlobalVarsType{} v.wwwURLRegxp = regexp.MustCompile(`^www\.[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}((?:/|[#?])[-a-zA-Z0-9@:%_\+.~#!?&//=\(\);,'">\^{}\[\]` + "`" + `]*)?`) v.LinkRegex, _ = xurls.StrictMatchingScheme("https?://") diff --git a/modules/markup/html.go b/modules/markup/html.go index 25628db39e..bb12febf27 100644 --- a/modules/markup/html.go +++ b/modules/markup/html.go @@ -42,7 +42,7 @@ type globalVarsType struct { nulCleaner *strings.Replacer } -var globalVars = sync.OnceValue[*globalVarsType](func() *globalVarsType { +var globalVars = sync.OnceValue(func() *globalVarsType { v := &globalVarsType{} // NOTE: All below regex matching do not perform any extra validation. // Thus a link is produced even if the linked entity does not exist. diff --git a/modules/markup/internal/renderinternal.go b/modules/markup/internal/renderinternal.go index 4775fecfc7..4d58f160a9 100644 --- a/modules/markup/internal/renderinternal.go +++ b/modules/markup/internal/renderinternal.go @@ -17,7 +17,7 @@ import ( "golang.org/x/net/html" ) -var reAttrClass = sync.OnceValue[*regexp.Regexp](func() *regexp.Regexp { +var reAttrClass = sync.OnceValue(func() *regexp.Regexp { // TODO: it isn't a problem at the moment because our HTML contents are always well constructed return regexp.MustCompile(`(<[^>]+)\s+class="([^"]+)"([^>]*>)`) }) diff --git a/modules/markup/markdown/goldmark.go b/modules/markup/markdown/goldmark.go index 620a39ebfd..69c2a96ff1 100644 --- a/modules/markup/markdown/goldmark.go +++ b/modules/markup/markdown/goldmark.go @@ -112,7 +112,7 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa } // it is copied from old code, which is quite doubtful whether it is correct -var reValidIconName = sync.OnceValue[*regexp.Regexp](func() *regexp.Regexp { +var reValidIconName = sync.OnceValue(func() *regexp.Regexp { return regexp.MustCompile(`^[-\w]+$`) // old: regexp.MustCompile("^[a-z ]+$") }) diff --git a/modules/packages/arch/metadata.go b/modules/packages/arch/metadata.go index 06a2206a36..3d7bdf3997 100644 --- a/modules/packages/arch/metadata.go +++ b/modules/packages/arch/metadata.go @@ -43,8 +43,9 @@ var ( ErrInvalidArchitecture = util.NewInvalidArgumentErrorf("package architecture is invalid") // https://man.archlinux.org/man/PKGBUILD.5 - namePattern = regexp.MustCompile(`\A[a-zA-Z0-9@._+-]+\z`) - versionPattern = regexp.MustCompile(`\A(?:[0-9]:)?[a-zA-Z0-9.+~]+(?:-[a-zA-Z0-9.+-~]+)?\z`) + namePattern = regexp.MustCompile(`\A[a-zA-Z0-9@._+-]+\z`) + // (epoch:pkgver-pkgrel) + versionPattern = regexp.MustCompile(`\A(?:\d:)?[\w.+~]+(?:-[-\w.+~]+)?\z`) ) type Package struct { diff --git a/modules/packages/arch/metadata_test.go b/modules/packages/arch/metadata_test.go index 37c0a553b8..5bdf63a3ee 100644 --- a/modules/packages/arch/metadata_test.go +++ b/modules/packages/arch/metadata_test.go @@ -122,6 +122,14 @@ func TestParsePackageInfo(t *testing.T) { assert.ErrorIs(t, err, ErrInvalidName) }) + t.Run("Regexp", func(t *testing.T) { + assert.Regexp(t, versionPattern, "1.2_3~4+5") + assert.Regexp(t, versionPattern, "1:2_3~4+5") + assert.NotRegexp(t, versionPattern, "a:1.0.0-1") + assert.NotRegexp(t, versionPattern, "0.0.1/1-1") + assert.NotRegexp(t, versionPattern, "1.0.0 -1") + }) + t.Run("InvalidVersion", func(t *testing.T) { data := createPKGINFOContent(packageName, "") diff --git a/modules/process/manager.go b/modules/process/manager.go index 7b8ada786e..661511ce8d 100644 --- a/modules/process/manager.go +++ b/modules/process/manager.go @@ -11,6 +11,8 @@ import ( "sync" "sync/atomic" "time" + + "code.gitea.io/gitea/modules/gtprof" ) // TODO: This packages still uses a singleton for the Manager. @@ -25,18 +27,6 @@ var ( DefaultContext = context.Background() ) -// DescriptionPProfLabel is a label set on goroutines that have a process attached -const DescriptionPProfLabel = "process_description" - -// PIDPProfLabel is a label set on goroutines that have a process attached -const PIDPProfLabel = "pid" - -// PPIDPProfLabel is a label set on goroutines that have a process attached -const PPIDPProfLabel = "ppid" - -// ProcessTypePProfLabel is a label set on goroutines that have a process attached -const ProcessTypePProfLabel = "process_type" - // IDType is a pid type type IDType string @@ -187,7 +177,12 @@ func (pm *Manager) Add(ctx context.Context, description string, cancel context.C Trace(true, pid, description, parentPID, processType) - pprofCtx := pprof.WithLabels(ctx, pprof.Labels(DescriptionPProfLabel, description, PPIDPProfLabel, string(parentPID), PIDPProfLabel, string(pid), ProcessTypePProfLabel, processType)) + pprofCtx := pprof.WithLabels(ctx, pprof.Labels( + gtprof.LabelProcessDescription, description, + gtprof.LabelPpid, string(parentPID), + gtprof.LabelPid, string(pid), + gtprof.LabelProcessType, processType, + )) if currentlyRunning { pprof.SetGoroutineLabels(pprofCtx) } diff --git a/modules/process/manager_stacktraces.go b/modules/process/manager_stacktraces.go index e260893113..d83060f6ee 100644 --- a/modules/process/manager_stacktraces.go +++ b/modules/process/manager_stacktraces.go @@ -10,6 +10,8 @@ import ( "sort" "time" + "code.gitea.io/gitea/modules/gtprof" + "github.com/google/pprof/profile" ) @@ -202,7 +204,7 @@ func (pm *Manager) ProcessStacktraces(flat, noSystem bool) ([]*Process, int, int // Add the non-process associated labels from the goroutine sample to the Stack for name, value := range sample.Label { - if name == DescriptionPProfLabel || name == PIDPProfLabel || (!flat && name == PPIDPProfLabel) || name == ProcessTypePProfLabel { + if name == gtprof.LabelProcessDescription || name == gtprof.LabelPid || (!flat && name == gtprof.LabelPpid) || name == gtprof.LabelProcessType { continue } @@ -224,7 +226,7 @@ func (pm *Manager) ProcessStacktraces(flat, noSystem bool) ([]*Process, int, int var process *Process // Try to get the PID from the goroutine labels - if pidvalue, ok := sample.Label[PIDPProfLabel]; ok && len(pidvalue) == 1 { + if pidvalue, ok := sample.Label[gtprof.LabelPid]; ok && len(pidvalue) == 1 { pid := IDType(pidvalue[0]) // Now try to get the process from our map @@ -238,20 +240,20 @@ func (pm *Manager) ProcessStacktraces(flat, noSystem bool) ([]*Process, int, int // get the parent PID ppid := IDType("") - if value, ok := sample.Label[PPIDPProfLabel]; ok && len(value) == 1 { + if value, ok := sample.Label[gtprof.LabelPpid]; ok && len(value) == 1 { ppid = IDType(value[0]) } // format the description description := "(dead process)" - if value, ok := sample.Label[DescriptionPProfLabel]; ok && len(value) == 1 { + if value, ok := sample.Label[gtprof.LabelProcessDescription]; ok && len(value) == 1 { description = value[0] + " " + description } // override the type of the process to "code" but add the old type as a label on the first stack ptype := NoneProcessType - if value, ok := sample.Label[ProcessTypePProfLabel]; ok && len(value) == 1 { - stack.Labels = append(stack.Labels, &Label{Name: ProcessTypePProfLabel, Value: value[0]}) + if value, ok := sample.Label[gtprof.LabelProcessType]; ok && len(value) == 1 { + stack.Labels = append(stack.Labels, &Label{Name: gtprof.LabelProcessType, Value: value[0]}) } process = &Process{ PID: pid, diff --git a/modules/queue/workerqueue.go b/modules/queue/workerqueue.go index 672e9a4114..0f5b105551 100644 --- a/modules/queue/workerqueue.go +++ b/modules/queue/workerqueue.go @@ -6,6 +6,7 @@ package queue import ( "context" "fmt" + "runtime/pprof" "sync" "sync/atomic" "time" @@ -241,6 +242,9 @@ func NewWorkerPoolQueueWithContext[T any](ctx context.Context, name string, queu w.origHandler = handler w.safeHandler = func(t ...T) (unhandled []T) { defer func() { + // FIXME: there is no ctx support in the handler, so process manager is unable to restore the labels + // so here we explicitly set the "queue ctx" labels again after the handler is done + pprof.SetGoroutineLabels(w.ctxRun) err := recover() if err != nil { log.Error("Recovered from panic in queue %q handler: %v\n%s", name, err, log.Stack(2)) diff --git a/modules/util/runtime.go b/modules/util/runtime.go new file mode 100644 index 0000000000..91ec3c869c --- /dev/null +++ b/modules/util/runtime.go @@ -0,0 +1,13 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package util + +import "runtime" + +func CallerFuncName(skip int) string { + pc := make([]uintptr, 1) + runtime.Callers(skip+1, pc) + funcName := runtime.FuncForPC(pc[0]).Name() + return funcName +} diff --git a/modules/util/runtime_test.go b/modules/util/runtime_test.go new file mode 100644 index 0000000000..20f9063b0b --- /dev/null +++ b/modules/util/runtime_test.go @@ -0,0 +1,32 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package util + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestCallerFuncName(t *testing.T) { + s := CallerFuncName(1) + assert.Equal(t, "code.gitea.io/gitea/modules/util.TestCallerFuncName", s) +} + +func BenchmarkCallerFuncName(b *testing.B) { + // BenchmarkCaller/sprintf-12 12744829 95.49 ns/op + b.Run("sprintf", func(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = fmt.Sprintf("aaaaaaaaaaaaaaaa %s %s %s", "bbbbbbbbbbbbbbbbbbb", b.Name(), "ccccccccccccccccccccc") + } + }) + // BenchmarkCaller/caller-12 10625133 113.6 ns/op + // It is almost as fast as fmt.Sprintf + b.Run("caller", func(b *testing.B) { + for i := 0; i < b.N; i++ { + CallerFuncName(1) + } + }) +} diff --git a/modules/util/time_str.go b/modules/util/time_str.go index b56f4740af..0fccfe82cc 100644 --- a/modules/util/time_str.go +++ b/modules/util/time_str.go @@ -25,7 +25,7 @@ type timeStrGlobalVarsType struct { // In the future, it could be some configurable options to help users // to convert the working time to different units. -var timeStrGlobalVars = sync.OnceValue[*timeStrGlobalVarsType](func() *timeStrGlobalVarsType { +var timeStrGlobalVars = sync.OnceValue(func() *timeStrGlobalVarsType { v := &timeStrGlobalVarsType{} v.re = regexp.MustCompile(`(?i)(\d+)\s*([hms])`) v.units = []struct { diff --git a/modules/util/util_test.go b/modules/util/util_test.go index 5abce08b41..52b05acc5b 100644 --- a/modules/util/util_test.go +++ b/modules/util/util_test.go @@ -242,10 +242,10 @@ func TestReserveLineBreakForTextarea(t *testing.T) { } func TestOptionalArg(t *testing.T) { - foo := func(other any, optArg ...int) int { + foo := func(_ any, optArg ...int) int { return OptionalArg(optArg) } - bar := func(other any, optArg ...int) int { + bar := func(_ any, optArg ...int) int { return OptionalArg(optArg, 42) } assert.Equal(t, 0, foo(nil)) diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index 2c84302f83..4d3c7118d7 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -1669,12 +1669,25 @@ issues.delete.title=このイシューを削除しますか? issues.delete.text=本当にこのイシューを削除しますか? (これはすべてのコンテンツを完全に削除します。 保存しておきたい場合は、代わりにクローズすることを検討してください) issues.tracker=タイムトラッカー +issues.timetracker_timer_start=タイマー開始 +issues.timetracker_timer_stop=タイマー終了 +issues.timetracker_timer_discard=タイマー破棄 +issues.timetracker_timer_manually_add=時間を追加 +issues.time_estimate_set=見積時間を設定 +issues.time_estimate_display=見積時間: %s +issues.change_time_estimate_at=が見積時間を %s に変更 %s +issues.remove_time_estimate_at=が見積時間を削除 %s +issues.time_estimate_invalid=見積時間のフォーマットが不正です +issues.start_tracking_history=が作業を開始 %s issues.tracker_auto_close=タイマーは、このイシューがクローズされると自動的に終了します issues.tracking_already_started=`別のイシューで既にタイムトラッキングを開始しています!` +issues.stop_tracking_history=が %s の作業を終了 %s issues.cancel_tracking_history=`がタイムトラッキングを中止 %s` issues.del_time=このタイムログを削除 +issues.add_time_history=が作業時間 %s を追加 %s issues.del_time_history=`が作業時間を削除 %s` +issues.add_time_manually=時間の手入力 issues.add_time_hours=時間 issues.add_time_minutes=分 issues.add_time_sum_to_small=時間が入力されていません。 @@ -1694,15 +1707,15 @@ issues.due_date_form_add=期日の追加 issues.due_date_form_edit=変更 issues.due_date_form_remove=削除 issues.due_date_not_writer=イシューの期日を変更するには、リポジトリへの書き込み権限が必要です。 -issues.due_date_not_set=期日は未設定です。 +issues.due_date_not_set=期日は設定されていません。 issues.due_date_added=が期日 %s を追加 %s issues.due_date_modified=が期日を %[2]s から %[1]s に変更 %[3]s issues.due_date_remove=が期日 %s を削除 %s issues.due_date_overdue=期日は過ぎています issues.due_date_invalid=期日が正しくないか範囲を超えています。 'yyyy-mm-dd' の形式で入力してください。 issues.dependency.title=依存関係 -issues.dependency.issue_no_dependencies=依存関係が設定されていません。 -issues.dependency.pr_no_dependencies=依存関係が設定されていません。 +issues.dependency.issue_no_dependencies=依存関係は設定されていません。 +issues.dependency.pr_no_dependencies=依存関係は設定されていません。 issues.dependency.no_permission_1=%d 個の依存関係への読み取り権限がありません issues.dependency.no_permission_n=%d 個の依存関係への読み取り権限がありません issues.dependency.no_permission.can_remove=この依存関係への読み取り権限はありませんが、この依存関係は削除できます diff --git a/package-lock.json b/package-lock.json index 8755cfe06f..60edfa95d0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "@github/relative-time-element": "4.4.4", "@github/text-expander-element": "2.8.0", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", - "@primer/octicons": "19.13.0", + "@primer/octicons": "19.14.0", "@silverwind/vue3-calendar-heatmap": "2.0.6", "add-asset-webpack-plugin": "3.0.0", "ansi_up": "6.0.2", @@ -33,12 +33,12 @@ "htmx.org": "2.0.4", "idiomorph": "0.3.0", "jquery": "3.7.1", - "katex": "0.16.11", + "katex": "0.16.18", "license-checker-webpack-plugin": "0.2.1", "mermaid": "11.4.1", "mini-css-extract-plugin": "2.9.2", "minimatch": "10.0.1", - "monaco-editor": "0.52.0", + "monaco-editor": "0.52.2", "monaco-editor-webpack-plugin": "7.1.0", "pdfobject": "2.3.0", "perfect-debounce": "1.0.0", @@ -47,7 +47,7 @@ "postcss-nesting": "13.0.1", "sortablejs": "1.15.6", "swagger-ui-dist": "5.18.2", - "tailwindcss": "3.4.16", + "tailwindcss": "3.4.17", "throttle-debounce": "5.0.2", "tinycolor2": "1.6.0", "tippy.js": "6.3.7", @@ -60,16 +60,16 @@ "vue-bar-graph": "2.2.0", "vue-chartjs": "5.3.2", "vue-loader": "17.4.2", - "webpack": "5.97.0", + "webpack": "5.97.1", "webpack-cli": "5.1.4", "wrap-ansi": "9.0.0" }, "devDependencies": { "@eslint-community/eslint-plugin-eslint-comments": "4.4.1", - "@playwright/test": "1.49.0", + "@playwright/test": "1.49.1", "@silverwind/vue-tsc": "2.1.13", "@stoplight/spectral-cli": "6.14.2", - "@stylistic/eslint-plugin-js": "2.11.0", + "@stylistic/eslint-plugin-js": "2.12.1", "@stylistic/stylelint-plugin": "3.1.1", "@types/dropzone": "5.7.9", "@types/jquery": "3.5.32", @@ -81,19 +81,19 @@ "@types/throttle-debounce": "5.0.2", "@types/tinycolor2": "1.4.6", "@types/toastify-js": "1.12.3", - "@typescript-eslint/eslint-plugin": "8.17.0", - "@typescript-eslint/parser": "8.17.0", + "@typescript-eslint/eslint-plugin": "8.18.1", + "@typescript-eslint/parser": "8.18.1", "@vitejs/plugin-vue": "5.2.1", "eslint": "8.57.0", "eslint-import-resolver-typescript": "3.7.0", "eslint-plugin-array-func": "4.0.0", - "eslint-plugin-github": "5.1.3", - "eslint-plugin-import-x": "4.5.0", + "eslint-plugin-github": "5.1.4", + "eslint-plugin-import-x": "4.6.1", "eslint-plugin-no-jquery": "3.1.0", "eslint-plugin-no-use-extend-native": "0.5.0", "eslint-plugin-playwright": "2.1.0", "eslint-plugin-regexp": "2.7.0", - "eslint-plugin-sonarjs": "2.0.4", + "eslint-plugin-sonarjs": "3.0.1", "eslint-plugin-unicorn": "56.0.1", "eslint-plugin-vitest": "0.4.1", "eslint-plugin-vitest-globals": "1.5.0", @@ -102,15 +102,15 @@ "eslint-plugin-wc": "2.2.0", "happy-dom": "15.11.7", "markdownlint-cli": "0.43.0", - "nolyfill": "1.0.42", + "nolyfill": "1.0.43", "postcss-html": "1.7.0", - "stylelint": "16.11.0", + "stylelint": "16.12.0", "stylelint-declaration-block-no-ignored-properties": "2.8.0", "stylelint-declaration-strict-value": "1.10.6", "stylelint-value-no-unknown-custom-properties": "6.0.1", "svgo": "3.3.2", - "type-fest": "4.30.0", - "updates": "16.4.0", + "type-fest": "4.30.2", + "updates": "16.4.1", "vite-string-plugin": "1.3.4", "vitest": "2.1.8" }, @@ -190,12 +190,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/code-frame/node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "license": "MIT" - }, "node_modules/@babel/compat-data": { "version": "7.26.3", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.3.tgz", @@ -207,22 +201,22 @@ } }, "node_modules/@babel/core": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", - "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", + "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.25.0", - "@babel/helper-compilation-targets": "^7.25.2", - "@babel/helper-module-transforms": "^7.25.2", - "@babel/helpers": "^7.25.0", - "@babel/parser": "^7.25.0", - "@babel/template": "^7.25.0", - "@babel/traverse": "^7.25.2", - "@babel/types": "^7.25.2", + "@babel/code-frame": "^7.26.0", + "@babel/generator": "^7.26.0", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helpers": "^7.26.0", + "@babel/parser": "^7.26.0", + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.26.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -248,9 +242,9 @@ } }, "node_modules/@babel/eslint-parser": { - "version": "7.25.1", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.25.1.tgz", - "integrity": "sha512-Y956ghgTT4j7rKesabkh5WeqgSFZVFwaPR0IWFm7KFHFmmJ4afbG49SmfW4S+GyRPx0Dy5jxEWA5t0rpxfElWg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.25.9.tgz", + "integrity": "sha512-5UXfgpK0j0Xr/xIdgdLEhOFxaDZ0bRPWJJchRpqOSur/3rZoPbqqki5mm0p4NE2cs28krBEiSM2MB7//afRSQQ==", "dev": true, "license": "MIT", "dependencies": { @@ -333,16 +327,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -706,15 +690,15 @@ } }, "node_modules/@babel/plugin-proposal-decorators": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.24.7.tgz", - "integrity": "sha512-RL9GR0pUG5Kc8BUWLNDm2T5OpYwSX15r98I0IkgmRQTXuELq/OynH8xtMTMvTJFjXbMWFVTKtYkTaYQsuAwQlQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.25.9.tgz", + "integrity": "sha512-smkNLL/O1ezy9Nhy4CNosc4Va+1wo5w4gzSZeLe6y6dM4mmHfYOCPolXQPHQxonZCF+ZyebxN9vqOolkYrSn5g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-decorators": "^7.24.7" + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-syntax-decorators": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -736,48 +720,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-decorators": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.25.9.tgz", @@ -794,32 +736,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-flow": { "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.26.0.tgz", @@ -868,32 +784,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-jsx": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", @@ -910,116 +800,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-unicode-sets-regex": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", @@ -1789,6 +1569,23 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.26.0.tgz", + "integrity": "sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/plugin-transform-reserved-words": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.9.tgz", @@ -1954,94 +1751,80 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.25.4.tgz", - "integrity": "sha512-W9Gyo+KmcxjGahtt3t9fb14vFRWvPpu5pT6GBlovAK6BTBcxgjfVMSQCfJl4oi35ODrxP6xx2Wr8LNST57Mraw==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.0.tgz", + "integrity": "sha512-H84Fxq0CQJNdPFT2DrfnylZ3cf5K43rGfWK4LJGPpjKHiZlk0/RzwEus3PDDZZg+/Er7lCA03MVacueUuXdzfw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.25.4", - "@babel/helper-compilation-targets": "^7.25.2", - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/helper-validator-option": "^7.24.8", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.3", - "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.0", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.0", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.0", + "@babel/compat-data": "^7.26.0", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.9", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.9", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.9", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.9", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.9", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.24.7", - "@babel/plugin-syntax-import-attributes": "^7.24.7", - "@babel/plugin-syntax-import-meta": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-import-assertions": "^7.26.0", + "@babel/plugin-syntax-import-attributes": "^7.26.0", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.24.7", - "@babel/plugin-transform-async-generator-functions": "^7.25.4", - "@babel/plugin-transform-async-to-generator": "^7.24.7", - "@babel/plugin-transform-block-scoped-functions": "^7.24.7", - "@babel/plugin-transform-block-scoping": "^7.25.0", - "@babel/plugin-transform-class-properties": "^7.25.4", - "@babel/plugin-transform-class-static-block": "^7.24.7", - "@babel/plugin-transform-classes": "^7.25.4", - "@babel/plugin-transform-computed-properties": "^7.24.7", - "@babel/plugin-transform-destructuring": "^7.24.8", - "@babel/plugin-transform-dotall-regex": "^7.24.7", - "@babel/plugin-transform-duplicate-keys": "^7.24.7", - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.0", - "@babel/plugin-transform-dynamic-import": "^7.24.7", - "@babel/plugin-transform-exponentiation-operator": "^7.24.7", - "@babel/plugin-transform-export-namespace-from": "^7.24.7", - "@babel/plugin-transform-for-of": "^7.24.7", - "@babel/plugin-transform-function-name": "^7.25.1", - "@babel/plugin-transform-json-strings": "^7.24.7", - "@babel/plugin-transform-literals": "^7.25.2", - "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", - "@babel/plugin-transform-member-expression-literals": "^7.24.7", - "@babel/plugin-transform-modules-amd": "^7.24.7", - "@babel/plugin-transform-modules-commonjs": "^7.24.8", - "@babel/plugin-transform-modules-systemjs": "^7.25.0", - "@babel/plugin-transform-modules-umd": "^7.24.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", - "@babel/plugin-transform-new-target": "^7.24.7", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", - "@babel/plugin-transform-numeric-separator": "^7.24.7", - "@babel/plugin-transform-object-rest-spread": "^7.24.7", - "@babel/plugin-transform-object-super": "^7.24.7", - "@babel/plugin-transform-optional-catch-binding": "^7.24.7", - "@babel/plugin-transform-optional-chaining": "^7.24.8", - "@babel/plugin-transform-parameters": "^7.24.7", - "@babel/plugin-transform-private-methods": "^7.25.4", - "@babel/plugin-transform-private-property-in-object": "^7.24.7", - "@babel/plugin-transform-property-literals": "^7.24.7", - "@babel/plugin-transform-regenerator": "^7.24.7", - "@babel/plugin-transform-reserved-words": "^7.24.7", - "@babel/plugin-transform-shorthand-properties": "^7.24.7", - "@babel/plugin-transform-spread": "^7.24.7", - "@babel/plugin-transform-sticky-regex": "^7.24.7", - "@babel/plugin-transform-template-literals": "^7.24.7", - "@babel/plugin-transform-typeof-symbol": "^7.24.8", - "@babel/plugin-transform-unicode-escapes": "^7.24.7", - "@babel/plugin-transform-unicode-property-regex": "^7.24.7", - "@babel/plugin-transform-unicode-regex": "^7.24.7", - "@babel/plugin-transform-unicode-sets-regex": "^7.25.4", + "@babel/plugin-transform-arrow-functions": "^7.25.9", + "@babel/plugin-transform-async-generator-functions": "^7.25.9", + "@babel/plugin-transform-async-to-generator": "^7.25.9", + "@babel/plugin-transform-block-scoped-functions": "^7.25.9", + "@babel/plugin-transform-block-scoping": "^7.25.9", + "@babel/plugin-transform-class-properties": "^7.25.9", + "@babel/plugin-transform-class-static-block": "^7.26.0", + "@babel/plugin-transform-classes": "^7.25.9", + "@babel/plugin-transform-computed-properties": "^7.25.9", + "@babel/plugin-transform-destructuring": "^7.25.9", + "@babel/plugin-transform-dotall-regex": "^7.25.9", + "@babel/plugin-transform-duplicate-keys": "^7.25.9", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.9", + "@babel/plugin-transform-dynamic-import": "^7.25.9", + "@babel/plugin-transform-exponentiation-operator": "^7.25.9", + "@babel/plugin-transform-export-namespace-from": "^7.25.9", + "@babel/plugin-transform-for-of": "^7.25.9", + "@babel/plugin-transform-function-name": "^7.25.9", + "@babel/plugin-transform-json-strings": "^7.25.9", + "@babel/plugin-transform-literals": "^7.25.9", + "@babel/plugin-transform-logical-assignment-operators": "^7.25.9", + "@babel/plugin-transform-member-expression-literals": "^7.25.9", + "@babel/plugin-transform-modules-amd": "^7.25.9", + "@babel/plugin-transform-modules-commonjs": "^7.25.9", + "@babel/plugin-transform-modules-systemjs": "^7.25.9", + "@babel/plugin-transform-modules-umd": "^7.25.9", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.9", + "@babel/plugin-transform-new-target": "^7.25.9", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.25.9", + "@babel/plugin-transform-numeric-separator": "^7.25.9", + "@babel/plugin-transform-object-rest-spread": "^7.25.9", + "@babel/plugin-transform-object-super": "^7.25.9", + "@babel/plugin-transform-optional-catch-binding": "^7.25.9", + "@babel/plugin-transform-optional-chaining": "^7.25.9", + "@babel/plugin-transform-parameters": "^7.25.9", + "@babel/plugin-transform-private-methods": "^7.25.9", + "@babel/plugin-transform-private-property-in-object": "^7.25.9", + "@babel/plugin-transform-property-literals": "^7.25.9", + "@babel/plugin-transform-regenerator": "^7.25.9", + "@babel/plugin-transform-regexp-modifiers": "^7.26.0", + "@babel/plugin-transform-reserved-words": "^7.25.9", + "@babel/plugin-transform-shorthand-properties": "^7.25.9", + "@babel/plugin-transform-spread": "^7.25.9", + "@babel/plugin-transform-sticky-regex": "^7.25.9", + "@babel/plugin-transform-template-literals": "^7.25.9", + "@babel/plugin-transform-typeof-symbol": "^7.25.9", + "@babel/plugin-transform-unicode-escapes": "^7.25.9", + "@babel/plugin-transform-unicode-property-regex": "^7.25.9", + "@babel/plugin-transform-unicode-regex": "^7.25.9", + "@babel/plugin-transform-unicode-sets-regex": "^7.25.9", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.10", "babel-plugin-polyfill-corejs3": "^0.10.6", "babel-plugin-polyfill-regenerator": "^0.6.1", - "core-js-compat": "^3.37.1", + "core-js-compat": "^3.38.1", "semver": "^6.3.1" }, "engines": { @@ -2062,15 +1845,15 @@ } }, "node_modules/@babel/preset-flow": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.24.7.tgz", - "integrity": "sha512-NL3Lo0NorCU607zU3NwRyJbpaB6E3t0xtd3LfAQKDfkeX4/ggcDXvkmkW42QWT5owUeW/jAe4hn+2qvkV1IbfQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.25.9.tgz", + "integrity": "sha512-EASHsAhE+SSlEzJ4bzfusnXSHiU+JfAYzj+jbw2vgQKgq5HrUr8qs+vgtiEL5dOH6sEweI+PNt2D7AqrDSHyqQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-validator-option": "^7.24.7", - "@babel/plugin-transform-flow-strip-types": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-transform-flow-strip-types": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2095,18 +1878,18 @@ } }, "node_modules/@babel/preset-react": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.24.7.tgz", - "integrity": "sha512-AAH4lEkpmzFWrGVlHaxJB7RLH21uPQ9+He+eFLWHmF9IuFQVugz8eAsamaW0DXRrTfco5zj1wWtpdcXJUOfsag==", + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.26.3.tgz", + "integrity": "sha512-Nl03d6T9ky516DGK2YMxrTqvnpUW63TnJMOMonj+Zae0JiPC5BC9xPMSL6L8fiSpA5vP88qfygavVQvnLp+6Cw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-validator-option": "^7.24.7", - "@babel/plugin-transform-react-display-name": "^7.24.7", - "@babel/plugin-transform-react-jsx": "^7.24.7", - "@babel/plugin-transform-react-jsx-development": "^7.24.7", - "@babel/plugin-transform-react-pure-annotations": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-transform-react-display-name": "^7.25.9", + "@babel/plugin-transform-react-jsx": "^7.25.9", + "@babel/plugin-transform-react-jsx-development": "^7.25.9", + "@babel/plugin-transform-react-pure-annotations": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2143,9 +1926,9 @@ } }, "node_modules/@babel/traverse": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.3.tgz", - "integrity": "sha512-yTmc8J+Sj8yLzwr4PD5Xb/WF3bOYu2C2OoSZPzbuqRm4n98XirsbzaX+GloeO376UnSYIYJ4NCanwV5/ugZkwA==", + "version": "7.26.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.4.tgz", + "integrity": "sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w==", "dev": true, "license": "MIT", "dependencies": { @@ -3109,18 +2892,31 @@ "license": "MIT" }, "node_modules/@iconify/utils": { - "version": "2.1.33", - "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-2.1.33.tgz", - "integrity": "sha512-jP9h6v/g0BIZx0p7XGJJVtkVnydtbgTgt9mVNcGDYwaa7UhdHdI9dvoq+gKj9sijMSJKxUPEG2JyjsgXjxL7Kw==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-2.2.1.tgz", + "integrity": "sha512-0/7J7hk4PqXmxo5PDBDxmnecw5PxklZJfNjIVG9FM0mEfVrvfudS22rYWsqVk6gR3UJ/mSYS90X4R3znXnqfNA==", "license": "MIT", "dependencies": { - "@antfu/install-pkg": "^0.4.0", + "@antfu/install-pkg": "^0.4.1", "@antfu/utils": "^0.7.10", "@iconify/types": "^2.0.0", - "debug": "^4.3.6", + "debug": "^4.4.0", + "globals": "^15.13.0", "kolorist": "^1.8.0", - "local-pkg": "^0.5.0", - "mlly": "^1.7.1" + "local-pkg": "^0.5.1", + "mlly": "^1.7.3" + } + }, + "node_modules/@iconify/utils/node_modules/globals": { + "version": "15.14.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.14.0.tgz", + "integrity": "sha512-OkToC372DtlQeje9/zHIo5CT8lRP/FUgEOKBEhU4e0abL7J7CD24fD9ohiLN5hagG/kWCYj4K5oaxxtj2Z0Dig==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/@isaacs/cliui": { @@ -3214,9 +3010,9 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.2.1", @@ -3486,13 +3282,13 @@ } }, "node_modules/@playwright/test": { - "version": "1.49.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.49.0.tgz", - "integrity": "sha512-DMulbwQURa8rNIQrf94+jPJQ4FmOVdpE5ZppRNvWVjvhC+6sOeo28r8MgIpQRYouXRtt/FCCXU7zn20jnHR4Qw==", + "version": "1.49.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.49.1.tgz", + "integrity": "sha512-Ky+BVzPz8pL6PQxHqNRW1k3mIyv933LML7HktS8uik0bUXNCdPhoS/kLihiO1tMf/egaJb4IutXd7UywvXEW+g==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright": "1.49.0" + "playwright": "1.49.1" }, "bin": { "playwright": "cli.js" @@ -3512,9 +3308,9 @@ } }, "node_modules/@primer/octicons": { - "version": "19.13.0", - "resolved": "https://registry.npmjs.org/@primer/octicons/-/octicons-19.13.0.tgz", - "integrity": "sha512-U5g7Bv89At8qFXUy9MQlOUs4iPXR5XR4QPnSZWhmOn2oCgwf4LjdvfC+8OzhUFx2wC8k9TbRRAMVuCkqFLPlfQ==", + "version": "19.14.0", + "resolved": "https://registry.npmjs.org/@primer/octicons/-/octicons-19.14.0.tgz", + "integrity": "sha512-9Ovw/xcUFHC/zbsNhr/Hkp1+m9XnNeQvnGHDHrI5vhlf6PRZVzSsdMnesV2xCzQh7jXP3EVRcaeXsUGlsZrfcA==", "license": "MIT", "dependencies": { "object-assign": "^4.1.1" @@ -3568,9 +3364,9 @@ "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.28.0.tgz", - "integrity": "sha512-wLJuPLT6grGZsy34g4N1yRfYeouklTgPhH1gWXCYspenKYD0s3cR99ZevOGw5BexMNywkbV3UkjADisozBmpPQ==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.28.1.tgz", + "integrity": "sha512-2aZp8AES04KI2dy3Ss6/MDjXbwBzj+i0GqKtWXgw2/Ma6E4jJvujryO6gJAghIRVz7Vwr9Gtl/8na3nDUKpraQ==", "cpu": [ "arm" ], @@ -3582,9 +3378,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.28.0.tgz", - "integrity": "sha512-eiNkznlo0dLmVG/6wf+Ifi/v78G4d4QxRhuUl+s8EWZpDewgk7PX3ZyECUXU0Zq/Ca+8nU8cQpNC4Xgn2gFNDA==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.28.1.tgz", + "integrity": "sha512-EbkK285O+1YMrg57xVA+Dp0tDBRB93/BZKph9XhMjezf6F4TpYjaUSuPt5J0fZXlSag0LmZAsTmdGGqPp4pQFA==", "cpu": [ "arm64" ], @@ -3596,9 +3392,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.28.0.tgz", - "integrity": "sha512-lmKx9yHsppblnLQZOGxdO66gT77bvdBtr/0P+TPOseowE7D9AJoBw8ZDULRasXRWf1Z86/gcOdpBrV6VDUY36Q==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.28.1.tgz", + "integrity": "sha512-prduvrMKU6NzMq6nxzQw445zXgaDBbMQvmKSJaxpaZ5R1QDM8w+eGxo6Y/jhT/cLoCvnZI42oEqf9KQNYz1fqQ==", "cpu": [ "arm64" ], @@ -3610,9 +3406,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.28.0.tgz", - "integrity": "sha512-8hxgfReVs7k9Js1uAIhS6zq3I+wKQETInnWQtgzt8JfGx51R1N6DRVy3F4o0lQwumbErRz52YqwjfvuwRxGv1w==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.28.1.tgz", + "integrity": "sha512-WsvbOunsUk0wccO/TV4o7IKgloJ942hVFK1CLatwv6TJspcCZb9umQkPdvB7FihmdxgaKR5JyxDjWpCOp4uZlQ==", "cpu": [ "x64" ], @@ -3624,9 +3420,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.28.0.tgz", - "integrity": "sha512-lA1zZB3bFx5oxu9fYud4+g1mt+lYXCoch0M0V/xhqLoGatbzVse0wlSQ1UYOWKpuSu3gyN4qEc0Dxf/DII1bhQ==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.28.1.tgz", + "integrity": "sha512-HTDPdY1caUcU4qK23FeeGxCdJF64cKkqajU0iBnTVxS8F7H/7BewvYoG+va1KPSL63kQ1PGNyiwKOfReavzvNA==", "cpu": [ "arm64" ], @@ -3638,9 +3434,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.28.0.tgz", - "integrity": "sha512-aI2plavbUDjCQB/sRbeUZWX9qp12GfYkYSJOrdYTL/C5D53bsE2/nBPuoiJKoWp5SN78v2Vr8ZPnB+/VbQ2pFA==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.28.1.tgz", + "integrity": "sha512-m/uYasxkUevcFTeRSM9TeLyPe2QDuqtjkeoTpP9SW0XxUWfcYrGDMkO/m2tTw+4NMAF9P2fU3Mw4ahNvo7QmsQ==", "cpu": [ "x64" ], @@ -3652,9 +3448,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.28.0.tgz", - "integrity": "sha512-WXveUPKtfqtaNvpf0iOb0M6xC64GzUX/OowbqfiCSXTdi/jLlOmH0Ba94/OkiY2yTGTwteo4/dsHRfh5bDCZ+w==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.28.1.tgz", + "integrity": "sha512-QAg11ZIt6mcmzpNE6JZBpKfJaKkqTm1A9+y9O+frdZJEuhQxiugM05gnCWiANHj4RmbgeVJpTdmKRmH/a+0QbA==", "cpu": [ "arm" ], @@ -3666,9 +3462,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.28.0.tgz", - "integrity": "sha512-yLc3O2NtOQR67lI79zsSc7lk31xjwcaocvdD1twL64PK1yNaIqCeWI9L5B4MFPAVGEVjH5k1oWSGuYX1Wutxpg==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.28.1.tgz", + "integrity": "sha512-dRP9PEBfolq1dmMcFqbEPSd9VlRuVWEGSmbxVEfiq2cs2jlZAl0YNxFzAQS2OrQmsLBLAATDMb3Z6MFv5vOcXg==", "cpu": [ "arm" ], @@ -3680,9 +3476,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.28.0.tgz", - "integrity": "sha512-+P9G9hjEpHucHRXqesY+3X9hD2wh0iNnJXX/QhS/J5vTdG6VhNYMxJ2rJkQOxRUd17u5mbMLHM7yWGZdAASfcg==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.28.1.tgz", + "integrity": "sha512-uGr8khxO+CKT4XU8ZUH1TTEUtlktK6Kgtv0+6bIFSeiSlnGJHG1tSFSjm41uQ9sAO/5ULx9mWOz70jYLyv1QkA==", "cpu": [ "arm64" ], @@ -3694,9 +3490,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.28.0.tgz", - "integrity": "sha512-1xsm2rCKSTpKzi5/ypT5wfc+4bOGa/9yI/eaOLW0oMs7qpC542APWhl4A37AENGZ6St6GBMWhCCMM6tXgTIplw==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.28.1.tgz", + "integrity": "sha512-QF54q8MYGAqMLrX2t7tNpi01nvq5RI59UBNx+3+37zoKX5KViPo/gk2QLhsuqok05sSCRluj0D00LzCwBikb0A==", "cpu": [ "arm64" ], @@ -3707,10 +3503,24 @@ "linux" ] }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.28.1.tgz", + "integrity": "sha512-vPul4uodvWvLhRco2w0GcyZcdyBfpfDRgNKU+p35AWEbJ/HPs1tOUrkSueVbBS0RQHAf/A+nNtDpvw95PeVKOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.28.0.tgz", - "integrity": "sha512-zgWxMq8neVQeXL+ouSf6S7DoNeo6EPgi1eeqHXVKQxqPy1B2NvTbaOUWPn/7CfMKL7xvhV0/+fq/Z/J69g1WAQ==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.28.1.tgz", + "integrity": "sha512-pTnTdBuC2+pt1Rmm2SV7JWRqzhYpEILML4PKODqLz+C7Ou2apEV52h19CR7es+u04KlqplggmN9sqZlekg3R1A==", "cpu": [ "ppc64" ], @@ -3722,9 +3532,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.28.0.tgz", - "integrity": "sha512-VEdVYacLniRxbRJLNtzwGt5vwS0ycYshofI7cWAfj7Vg5asqj+pt+Q6x4n+AONSZW/kVm+5nklde0qs2EUwU2g==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.28.1.tgz", + "integrity": "sha512-vWXy1Nfg7TPBSuAncfInmAI/WZDd5vOklyLJDdIRKABcZWojNDY0NJwruY2AcnCLnRJKSaBgf/GiJfauu8cQZA==", "cpu": [ "riscv64" ], @@ -3736,9 +3546,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.28.0.tgz", - "integrity": "sha512-LQlP5t2hcDJh8HV8RELD9/xlYtEzJkm/aWGsauvdO2ulfl3QYRjqrKW+mGAIWP5kdNCBheqqqYIGElSRCaXfpw==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.28.1.tgz", + "integrity": "sha512-/yqC2Y53oZjb0yz8PVuGOQQNOTwxcizudunl/tFs1aLvObTclTwZ0JhXF2XcPT/zuaymemCDSuuUPXJJyqeDOg==", "cpu": [ "s390x" ], @@ -3750,9 +3560,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.28.0.tgz", - "integrity": "sha512-Nl4KIzteVEKE9BdAvYoTkW19pa7LR/RBrT6F1dJCV/3pbjwDcaOq+edkP0LXuJ9kflW/xOK414X78r+K84+msw==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.28.1.tgz", + "integrity": "sha512-fzgeABz7rrAlKYB0y2kSEiURrI0691CSL0+KXwKwhxvj92VULEDQLpBYLHpF49MSiPG4sq5CK3qHMnb9tlCjBw==", "cpu": [ "x64" ], @@ -3764,9 +3574,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.28.0.tgz", - "integrity": "sha512-eKpJr4vBDOi4goT75MvW+0dXcNUqisK4jvibY9vDdlgLx+yekxSm55StsHbxUsRxSTt3JEQvlr3cGDkzcSP8bw==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.28.1.tgz", + "integrity": "sha512-xQTDVzSGiMlSshpJCtudbWyRfLaNiVPXt1WgdWTwWz9n0U12cI2ZVtWe/Jgwyv/6wjL7b66uu61Vg0POWVfz4g==", "cpu": [ "x64" ], @@ -3778,9 +3588,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.28.0.tgz", - "integrity": "sha512-Vi+WR62xWGsE/Oj+mD0FNAPY2MEox3cfyG0zLpotZdehPFXwz6lypkGs5y38Jd/NVSbOD02aVad6q6QYF7i8Bg==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.28.1.tgz", + "integrity": "sha512-wSXmDRVupJstFP7elGMgv+2HqXelQhuNf+IS4V+nUpNVi/GUiBgDmfwD0UGN3pcAnWsgKG3I52wMOBnk1VHr/A==", "cpu": [ "arm64" ], @@ -3792,9 +3602,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.28.0.tgz", - "integrity": "sha512-kN/Vpip8emMLn/eOza+4JwqDZBL6MPNpkdaEsgUtW1NYN3DZvZqSQrbKzJcTL6hd8YNmFTn7XGWMwccOcJBL0A==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.28.1.tgz", + "integrity": "sha512-ZkyTJ/9vkgrE/Rk9vhMXhf8l9D+eAhbAVbsGsXKy2ohmJaWg0LPQLnIxRdRp/bKyr8tXuPlXhIoGlEB5XpJnGA==", "cpu": [ "ia32" ], @@ -3806,9 +3616,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.28.0.tgz", - "integrity": "sha512-Bvno2/aZT6usSa7lRDL2+hMjVAGjuqaymF1ApZm31JXzniR/hvr14jpU+/z4X6Gt5BPlzosscyJZGUvguXIqeQ==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.28.1.tgz", + "integrity": "sha512-ZvK2jBafvttJjoIdKm/Q/Bh7IJ1Ose9IBOwpOXcOvW3ikGTQGmKDgxTC6oCAzW6PynbkKP8+um1du81XJHZ0JA==", "cpu": [ "x64" ], @@ -4383,9 +4193,9 @@ } }, "node_modules/@stylistic/eslint-plugin-js": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-2.11.0.tgz", - "integrity": "sha512-btchD0P3iij6cIk5RR5QMdEhtCCV0+L6cNheGhGCd//jaHILZMTi/EOqgEDAf1s4ZoViyExoToM+S2Iwa3U9DA==", + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-2.12.1.tgz", + "integrity": "sha512-5ybogtEgWIGCR6dMnaabztbWyVdAPDsf/5XOk6jBonWug875Q9/a6gm9QxnU3rhdyDEnckWKX7dduwYJMOWrVA==", "dev": true, "license": "MIT", "dependencies": { @@ -4700,6 +4510,13 @@ "@types/d3-selection": "*" } }, + "node_modules/@types/doctrine": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/@types/doctrine/-/doctrine-0.0.9.tgz", + "integrity": "sha512-eOIHzCUSH7SMfonMG1LsC2f8vxBFtho6NGBznK41R84YzPuvSBzrhEps33IsQiOW9+VL6NQ9DbjQJznk/S4uRA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/dropzone": { "version": "5.7.9", "resolved": "https://registry.npmjs.org/@types/dropzone/-/dropzone-5.7.9.tgz", @@ -4747,9 +4564,9 @@ "license": "MIT" }, "node_modules/@types/geojson": { - "version": "7946.0.14", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.14.tgz", - "integrity": "sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==", + "version": "7946.0.15", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.15.tgz", + "integrity": "sha512-9oSxFzDCT2Rj6DfcHF8G++jxBKS7mBqXl5xrRW+Kbvjry6Uduya2iiwqHPhVXpasAVMBYKkEPGgKhd3+/HZ6xA==", "license": "MIT" }, "node_modules/@types/hammerjs": { @@ -4812,9 +4629,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.10.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.1.tgz", - "integrity": "sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==", + "version": "22.10.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz", + "integrity": "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==", "license": "MIT", "dependencies": { "undici-types": "~6.20.0" @@ -4968,17 +4785,17 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.17.0.tgz", - "integrity": "sha512-HU1KAdW3Tt8zQkdvNoIijfWDMvdSweFYm4hWh+KwhPstv+sCmWb89hCIP8msFm9N1R/ooh9honpSuvqKWlYy3w==", + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.18.1.tgz", + "integrity": "sha512-Ncvsq5CT3Gvh+uJG0Lwlho6suwDfUXH0HztslDf5I+F2wAFAZMRwYLEorumpKLzmO2suAXZ/td1tBg4NZIi9CQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.17.0", - "@typescript-eslint/type-utils": "8.17.0", - "@typescript-eslint/utils": "8.17.0", - "@typescript-eslint/visitor-keys": "8.17.0", + "@typescript-eslint/scope-manager": "8.18.1", + "@typescript-eslint/type-utils": "8.18.1", + "@typescript-eslint/utils": "8.18.1", + "@typescript-eslint/visitor-keys": "8.18.1", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -4993,25 +4810,21 @@ }, "peerDependencies": { "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.17.0.tgz", - "integrity": "sha512-Drp39TXuUlD49F7ilHHCG7TTg8IkA+hxCuULdmzWYICxGXvDXmDmWEjJYZQYgf6l/TFfYNE167m7isnc3xlIEg==", + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.18.1.tgz", + "integrity": "sha512-rBnTWHCdbYM2lh7hjyXqxk70wvon3p2FyaniZuey5TrcGBpfhVp0OxOa6gxr9Q9YhZFKyfbEnxc24ZnVbbUkCA==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.17.0", - "@typescript-eslint/types": "8.17.0", - "@typescript-eslint/typescript-estree": "8.17.0", - "@typescript-eslint/visitor-keys": "8.17.0", + "@typescript-eslint/scope-manager": "8.18.1", + "@typescript-eslint/types": "8.18.1", + "@typescript-eslint/typescript-estree": "8.18.1", + "@typescript-eslint/visitor-keys": "8.18.1", "debug": "^4.3.4" }, "engines": { @@ -5022,23 +4835,19 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.17.0.tgz", - "integrity": "sha512-/ewp4XjvnxaREtqsZjF4Mfn078RD/9GmiEAtTeLQ7yFdKnqwTOgRMSvFz4et9U5RiJQ15WTGXPLj89zGusvxBg==", + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.18.1.tgz", + "integrity": "sha512-HxfHo2b090M5s2+/9Z3gkBhI6xBH8OJCFjH9MhQ+nnoZqxU3wNxkLT+VWXWSFWc3UF3Z+CfPAyqdCTdoXtDPCQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.17.0", - "@typescript-eslint/visitor-keys": "8.17.0" + "@typescript-eslint/types": "8.18.1", + "@typescript-eslint/visitor-keys": "8.18.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -5049,14 +4858,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.17.0.tgz", - "integrity": "sha512-q38llWJYPd63rRnJ6wY/ZQqIzPrBCkPdpIsaCfkR3Q4t3p6sb422zougfad4TFW9+ElIFLVDzWGiGAfbb/v2qw==", + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.18.1.tgz", + "integrity": "sha512-jAhTdK/Qx2NJPNOTxXpMwlOiSymtR2j283TtPqXkKBdH8OAMmhiUfP0kJjc/qSE51Xrq02Gj9NY7MwK+UxVwHQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.17.0", - "@typescript-eslint/utils": "8.17.0", + "@typescript-eslint/typescript-estree": "8.18.1", + "@typescript-eslint/utils": "8.18.1", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -5068,18 +4877,14 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/types": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.17.0.tgz", - "integrity": "sha512-gY2TVzeve3z6crqh2Ic7Cr+CAv6pfb0Egee7J5UAVWCpVvDI/F71wNfolIim4FE6hT15EbpZFVUj9j5i38jYXA==", + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.18.1.tgz", + "integrity": "sha512-7uoAUsCj66qdNQNpH2G8MyTFlgerum8ubf21s3TSM3XmKXuIn+H2Sifh/ES2nPOPiYSRJWAk0fDkW0APBWcpfw==", "dev": true, "license": "MIT", "engines": { @@ -5091,14 +4896,14 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.17.0.tgz", - "integrity": "sha512-JqkOopc1nRKZpX+opvKqnM3XUlM7LpFMD0lYxTqOTKQfCWAmxw45e3qlOCsEqEB2yuacujivudOFpCnqkBDNMw==", + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.18.1.tgz", + "integrity": "sha512-z8U21WI5txzl2XYOW7i9hJhxoKKNG1kcU4RzyNvKrdZDmbjkmLBo8bgeiOJmA06kizLI76/CCBAAGlTlEeUfyg==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.17.0", - "@typescript-eslint/visitor-keys": "8.17.0", + "@typescript-eslint/types": "8.18.1", + "@typescript-eslint/visitor-keys": "8.18.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -5113,10 +4918,8 @@ "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { @@ -5136,16 +4939,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.17.0.tgz", - "integrity": "sha512-bQC8BnEkxqG8HBGKwG9wXlZqg37RKSMY7v/X8VEWD8JG2JuTHuNK0VFvMPMUKQcbk6B+tf05k+4AShAEtCtJ/w==", + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.18.1.tgz", + "integrity": "sha512-8vikiIj2ebrC4WRdcAdDcmnu9Q/MXXwg+STf40BVfT8exDqBCUPdypvzcUPxEqRGKg9ALagZ0UWcYCtn+4W2iQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.17.0", - "@typescript-eslint/types": "8.17.0", - "@typescript-eslint/typescript-estree": "8.17.0" + "@typescript-eslint/scope-manager": "8.18.1", + "@typescript-eslint/types": "8.18.1", + "@typescript-eslint/typescript-estree": "8.18.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -5155,22 +4958,18 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.17.0.tgz", - "integrity": "sha512-1Hm7THLpO6ww5QU6H/Qp+AusUUl+z/CAm3cNZZ0jQvon9yicgO7Rwd+/WWRpMKLYV6p2UvdbR27c86rzCPpreg==", + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.18.1.tgz", + "integrity": "sha512-Vj0WLm5/ZsD013YeUKn+K0y8p1M0jPpxOkKdbD1wB0ns53a5piVY02zjf072TblEweAbcYiFiPoSMF3kp+VhhQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.17.0", + "@typescript-eslint/types": "8.18.1", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -5182,9 +4981,9 @@ } }, "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.1.tgz", + "integrity": "sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==", "dev": true, "license": "ISC" }, @@ -5263,9 +5062,9 @@ } }, "node_modules/@vitest/mocker/node_modules/magic-string": { - "version": "0.30.14", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.14.tgz", - "integrity": "sha512-5c99P1WKTed11ZC0HMJOj6CDIue6F8ySu+bJL+85q1zBEIY8IklrJ1eiKC2NDRh3Ct3FcvmJPyQHb9erXMTJNw==", + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", "dev": true, "license": "MIT", "dependencies": { @@ -5315,9 +5114,9 @@ } }, "node_modules/@vitest/snapshot/node_modules/magic-string": { - "version": "0.30.14", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.14.tgz", - "integrity": "sha512-5c99P1WKTed11ZC0HMJOj6CDIue6F8ySu+bJL+85q1zBEIY8IklrJ1eiKC2NDRh3Ct3FcvmJPyQHb9erXMTJNw==", + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", "dev": true, "license": "MIT", "dependencies": { @@ -5422,9 +5221,9 @@ } }, "node_modules/@vue/compiler-sfc/node_modules/magic-string": { - "version": "0.30.14", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.14.tgz", - "integrity": "sha512-5c99P1WKTed11ZC0HMJOj6CDIue6F8ySu+bJL+85q1zBEIY8IklrJ1eiKC2NDRh3Ct3FcvmJPyQHb9erXMTJNw==", + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" @@ -5978,27 +5777,6 @@ "node": ">=8" } }, - "node_modules/array.prototype.findlast": { - "name": "@nolyfill/array.prototype.findlast", - "version": "1.0.24", - "resolved": "https://registry.npmjs.org/@nolyfill/array.prototype.findlast/-/array.prototype.findlast-1.0.24.tgz", - "integrity": "sha512-yFCyZLs0iNNubzYnBINcOCJAiGtusxiR2F1DnwkOB1HQbWXl/zltkDIWIXO3cJxhQdngDlmM4ysTfyAfoB297g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nolyfill/shared": "1.0.24" - }, - "engines": { - "node": ">=12.4.0" - } - }, - "node_modules/array.prototype.findlast/node_modules/@nolyfill/shared": { - "version": "1.0.24", - "resolved": "https://registry.npmjs.org/@nolyfill/shared/-/shared-1.0.24.tgz", - "integrity": "sha512-TGCpg3k5N7jj9AgU/1xFw9K1g4AC1vEE5ZFkW77oPNNLzprxT17PvFaNr/lr3BkkT5fJ5LNMntaTIq+pyWaeEA==", - "dev": true, - "license": "MIT" - }, "node_modules/array.prototype.findlastindex": { "name": "@nolyfill/array.prototype.findlastindex", "version": "1.0.24", @@ -6048,27 +5826,6 @@ "node": ">=12.4.0" } }, - "node_modules/array.prototype.tosorted": { - "name": "@nolyfill/array.prototype.tosorted", - "version": "1.0.24", - "resolved": "https://registry.npmjs.org/@nolyfill/array.prototype.tosorted/-/array.prototype.tosorted-1.0.24.tgz", - "integrity": "sha512-lVo8TVDqaslOaOvEH7iL7glu/WdlX7ZrB+7FZY4BL25hg8TLHvg3e9pxafCp8vAQ96IOL+tdgBdfeoC7qLeQYg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nolyfill/shared": "1.0.24" - }, - "engines": { - "node": ">=12.4.0" - } - }, - "node_modules/array.prototype.tosorted/node_modules/@nolyfill/shared": { - "version": "1.0.24", - "resolved": "https://registry.npmjs.org/@nolyfill/shared/-/shared-1.0.24.tgz", - "integrity": "sha512-TGCpg3k5N7jj9AgU/1xFw9K1g4AC1vEE5ZFkW77oPNNLzprxT17PvFaNr/lr3BkkT5fJ5LNMntaTIq+pyWaeEA==", - "dev": true, - "license": "MIT" - }, "node_modules/as-table": { "version": "1.0.55", "resolved": "https://registry.npmjs.org/as-table/-/as-table-1.0.55.tgz", @@ -6300,9 +6057,9 @@ } }, "node_modules/browserslist": { - "version": "4.24.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", - "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", + "version": "4.24.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.3.tgz", + "integrity": "sha512-1CPmv8iobE2fyRMV97dAcMVegvvWKxmq94hkLiAkUGwKVTyDLw33K+ZxiFrREKmmps4rIw6grcCFCnTMSZ/YiA==", "funding": [ { "type": "opencollective", @@ -6319,9 +6076,9 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001669", - "electron-to-chromium": "^1.5.41", - "node-releases": "^2.0.18", + "caniuse-lite": "^1.0.30001688", + "electron-to-chromium": "^1.5.73", + "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.1" }, "bin": { @@ -6420,9 +6177,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001686", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001686.tgz", - "integrity": "sha512-Y7deg0Aergpa24M3qLC5xjNklnKnhsmSyR/V89dLZ1n0ucJIFNs7PgR2Yfa/Zf6W79SbBicgtGxZr2juHkEUIA==", + "version": "1.0.30001690", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001690.tgz", + "integrity": "sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w==", "funding": [ { "type": "opencollective", @@ -6933,13 +6690,13 @@ } }, "node_modules/css-tree": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.0.1.tgz", - "integrity": "sha512-8Fxxv+tGhORlshCdCwnNJytvlvq46sOLSYEx2ZIGurahWvMucSRnyjPA3AmrMq4VPRYbHVpWj5VkiVasrM2H4Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.1.0.tgz", + "integrity": "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==", "dev": true, "license": "MIT", "dependencies": { - "mdn-data": "2.12.1", + "mdn-data": "2.12.2", "source-map-js": "^1.0.1" }, "engines": { @@ -7549,9 +7306,9 @@ "license": "MIT" }, "node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -7585,20 +7342,6 @@ "node": ">=6" } }, - "node_modules/deep-equal": { - "name": "@nolyfill/deep-equal", - "version": "1.0.29", - "resolved": "https://registry.npmjs.org/@nolyfill/deep-equal/-/deep-equal-1.0.29.tgz", - "integrity": "sha512-EtrJBbOXHhVz8Y1gMYolKgPqh2u96UPqkZMHR0lcjn3y4TC4R7GuN3E4kEhDIpyK3q1+y7HHPHHkt5fGvW1crQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "dequal": "2.0.3" - }, - "engines": { - "node": ">=12.4.0" - } - }, "node_modules/deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", @@ -7635,16 +7378,6 @@ "node": ">= 0.6.0" } }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -7737,9 +7470,9 @@ } }, "node_modules/dompurify": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.2.tgz", - "integrity": "sha512-YMM+erhdZ2nkZ4fTNRTSI94mb7VG7uVF5vj5Zde7tImgnhZE3R6YW/IACGIHb2ux+QkEXMhe591N+5jWOmL4Zw==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.3.tgz", + "integrity": "sha512-U1U5Hzc2MO0oW3DF+G9qYN0aT7atAou4AgI0XjWz061nyBPbdxkfdhfy5uMgGn6+oLFCfn44ZGbdDqCzVmlOWA==", "license": "(MPL-2.0 OR Apache-2.0)", "optionalDependencies": { "@types/trusted-types": "^2.0.7" @@ -7790,9 +7523,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.68", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.68.tgz", - "integrity": "sha512-FgMdJlma0OzUYlbrtZ4AeXjKxKPk6KT8WOP8BjcqxWtlg8qyJQjRzPJzUtUn5GBg1oQ26hFs7HOOHJMYiJRnvQ==", + "version": "1.5.74", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.74.tgz", + "integrity": "sha512-ck3//9RC+6oss/1Bh9tiAVFy5vfSKbRHAFh7Z3/eTRkEqJeWgymloShB17Vg3Z4nmDNp35vAd1BZ6CMW4Wt6Iw==", "license": "ISC" }, "node_modules/emoji-regex": { @@ -7879,27 +7612,6 @@ "node": ">=12.4.0" } }, - "node_modules/es-iterator-helpers": { - "name": "@nolyfill/es-iterator-helpers", - "version": "1.0.21", - "resolved": "https://registry.npmjs.org/@nolyfill/es-iterator-helpers/-/es-iterator-helpers-1.0.21.tgz", - "integrity": "sha512-i326KeE0nhW4STobcUhkxpXzZUddedCmfh7b/IyXR9kW0CFHiNNT80C3JSEy33mUlhZtk/ezX47nymcFxyBigg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nolyfill/shared": "1.0.21" - }, - "engines": { - "node": ">=12.4.0" - } - }, - "node_modules/es-iterator-helpers/node_modules/@nolyfill/shared": { - "version": "1.0.21", - "resolved": "https://registry.npmjs.org/@nolyfill/shared/-/shared-1.0.21.tgz", - "integrity": "sha512-qDc/NoaFU23E0hhiDPeUrvWzTXIPE+RbvRQtRWSeHHNmCIgYI9HS1jKzNYNJxv4jvZ/1VmM3L6rNVxbj+LBMNA==", - "dev": true, - "license": "MIT" - }, "node_modules/es-module-lexer": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", @@ -8241,9 +7953,9 @@ } }, "node_modules/eslint-plugin-github": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-github/-/eslint-plugin-github-5.1.3.tgz", - "integrity": "sha512-/0lyEqLLodXW3p+D9eYtmEp6e9DcJmV5FhnE9wNWV1bcqyShuZFXn5kOeJIvxSbFbdbrKiNO8zFiV/VXeSpRSw==", + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-github/-/eslint-plugin-github-5.1.4.tgz", + "integrity": "sha512-j5IgIxsDoch06zJzeqPvenfzRXDKI9Z8YwfUg1pm2ay1q44tMSFwvEu6l0uEIrTpA3v8QdPyLr98LqDl1TIhSA==", "dev": true, "license": "MIT", "dependencies": { @@ -8333,9 +8045,9 @@ } }, "node_modules/eslint-plugin-github/node_modules/@eslint/js": { - "version": "9.16.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.16.0.tgz", - "integrity": "sha512-tw2HxzQkrbeuvyj1tG2Yqq+0H9wGoI2IMk4EOsQeX+vmd75FtJAzf+gTA69WF+baUKRYQ3x2kbLE08js5OsTVg==", + "version": "9.17.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.17.0.tgz", + "integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==", "dev": true, "license": "MIT", "engines": { @@ -8371,9 +8083,9 @@ } }, "node_modules/eslint-plugin-github/node_modules/globals": { - "version": "15.13.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.13.0.tgz", - "integrity": "sha512-49TewVEz0UxZjr1WYYsWpPrhyC/B/pA8Bq0fUmet2n+eR7yn0IvNzNaoBwnK6mdkzcN+se7Ez9zUgULTz2QH4g==", + "version": "15.14.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.14.0.tgz", + "integrity": "sha512-OkToC372DtlQeje9/zHIo5CT8lRP/FUgEOKBEhU4e0abL7J7CD24fD9ohiLN5hagG/kWCYj4K5oaxxtj2Z0Dig==", "dev": true, "license": "MIT", "engines": { @@ -8448,16 +8160,18 @@ } }, "node_modules/eslint-plugin-import-x": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import-x/-/eslint-plugin-import-x-4.5.0.tgz", - "integrity": "sha512-l0OTfnPF8RwmSXfjT75N8d6ZYLVrVYWpaGlgvVkVqFERCI5SyBfDP7QEMr3kt0zWi2sOa9EQ47clbdFsHkF83Q==", + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import-x/-/eslint-plugin-import-x-4.6.1.tgz", + "integrity": "sha512-wluSUifMIb7UfwWXqx7Yx0lE/SGCcGXECLx/9bCmbY2nneLwvAZ4vkd1IXDjPKFvdcdUgr1BaRnaRpx3k2+Pfw==", "dev": true, "license": "MIT", "dependencies": { + "@types/doctrine": "^0.0.9", "@typescript-eslint/scope-manager": "^8.1.0", "@typescript-eslint/utils": "^8.1.0", "debug": "^4.3.4", "doctrine": "^3.0.0", + "enhanced-resolve": "^5.17.1", "eslint-import-resolver-node": "^0.3.9", "get-tsconfig": "^4.7.3", "is-glob": "^4.0.3", @@ -8686,117 +8400,6 @@ } } }, - "node_modules/eslint-plugin-react": { - "version": "7.36.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.36.1.tgz", - "integrity": "sha512-/qwbqNXZoq+VP30s1d4Nc1C5GTxjJQjk4Jzs4Wq2qzxFM7dSmuG2UkIjg2USMLh3A/aVcUNrK7v0J5U1XEGGwA==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-includes": "^3.1.8", - "array.prototype.findlast": "^1.2.5", - "array.prototype.flatmap": "^1.3.2", - "array.prototype.tosorted": "^1.1.4", - "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.0.19", - "estraverse": "^5.3.0", - "hasown": "^2.0.2", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.8", - "object.fromentries": "^2.0.8", - "object.values": "^1.2.0", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.5", - "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.11", - "string.prototype.repeat": "^1.0.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" - } - }, - "node_modules/eslint-plugin-react-hooks": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", - "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" - } - }, - "node_modules/eslint-plugin-react/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint-plugin-react/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-react/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.5", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", - "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/eslint-plugin-react/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/eslint-plugin-regexp": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/eslint-plugin-regexp/-/eslint-plugin-regexp-2.7.0.tgz", @@ -8820,256 +8423,33 @@ } }, "node_modules/eslint-plugin-sonarjs": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-2.0.4.tgz", - "integrity": "sha512-XVVAB/t0WSgHitHNajIcIDmviCO8kB9VSsrjy+4WUEVM3eieY9SDHEtCDaOMTjj6XMtcAr8BFDXCFaP005s+tg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-3.0.1.tgz", + "integrity": "sha512-RT6VgdPqizbMLmTryIc3fB169hRjvDFlqieSZEEswGtApPb4Dn9BndmN9qyfBV/By0hbseIX8zQWKBz5E7lyiQ==", "dev": true, "license": "LGPL-3.0-only", "dependencies": { - "@babel/core": "7.25.2", - "@babel/eslint-parser": "7.25.1", - "@babel/plugin-proposal-decorators": "7.24.7", - "@babel/preset-env": "7.25.4", - "@babel/preset-flow": "7.24.7", - "@babel/preset-react": "7.24.7", - "@eslint-community/regexpp": "4.11.1", - "@typescript-eslint/eslint-plugin": "7.16.1", - "@typescript-eslint/utils": "7.16.1", + "@babel/core": "7.26.0", + "@babel/eslint-parser": "7.25.9", + "@babel/plugin-proposal-decorators": "7.25.9", + "@babel/preset-env": "7.26.0", + "@babel/preset-flow": "7.25.9", + "@babel/preset-react": "7.26.3", + "@eslint-community/regexpp": "4.12.1", "builtin-modules": "3.3.0", "bytes": "3.1.2", - "eslint-plugin-import": "2.30.0", - "eslint-plugin-jsx-a11y": "6.10.0", - "eslint-plugin-react": "7.36.1", - "eslint-plugin-react-hooks": "4.6.2", - "eslint-scope": "8.1.0", "functional-red-black-tree": "1.0.1", "jsx-ast-utils": "3.3.5", - "minimatch": "10.0.1", + "minimatch": "9.0.5", "scslre": "0.3.0", "semver": "7.6.3", - "typescript": "5.6.2", - "vue-eslint-parser": "9.4.3" + "typescript": "^5" }, "peerDependencies": { "eslint": "^8.0.0 || ^9.0.0" } }, - "node_modules/eslint-plugin-sonarjs/node_modules/@eslint-community/regexpp": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.1.tgz", - "integrity": "sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.16.1.tgz", - "integrity": "sha512-SxdPak/5bO0EnGktV05+Hq8oatjAYVY3Zh2bye9pGZy6+jwyR3LG3YKkV4YatlsgqXP28BTeVm9pqwJM96vf2A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.16.1", - "@typescript-eslint/type-utils": "7.16.1", - "@typescript-eslint/utils": "7.16.1", - "@typescript-eslint/visitor-keys": "7.16.1", - "graphemer": "^1.4.0", - "ignore": "^5.3.1", - "natural-compare": "^1.4.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^7.0.0", - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/@typescript-eslint/parser": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz", - "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==", - "dev": true, - "license": "BSD-2-Clause", - "peer": true, - "dependencies": { - "@typescript-eslint/scope-manager": "7.18.0", - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/typescript-estree": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", - "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", - "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@typescript-eslint/types": "7.18.0", - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/@typescript-eslint/scope-manager": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.16.1.tgz", - "integrity": "sha512-nYpyv6ALte18gbMz323RM+vpFpTjfNdyakbf3nsLvF43uF9KeNC289SUEW3QLZ1xPtyINJ1dIsZOuWuSRIWygw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "7.16.1", - "@typescript-eslint/visitor-keys": "7.16.1" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/@typescript-eslint/scope-manager/node_modules/@typescript-eslint/types": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.16.1.tgz", - "integrity": "sha512-AQn9XqCzUXd4bAVEsAXM/Izk11Wx2u4H3BAfQVhSfzfDOm/wAON9nP7J5rpkCxts7E5TELmN845xTUCQrD1xIQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/@typescript-eslint/type-utils": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.16.1.tgz", - "integrity": "sha512-rbu/H2MWXN4SkjIIyWcmYBjlp55VT+1G3duFOIukTNFxr9PI35pLc2ydwAfejCEitCv4uztA07q0QWanOHC7dA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/typescript-estree": "7.16.1", - "@typescript-eslint/utils": "7.16.1", - "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.16.1.tgz", - "integrity": "sha512-AQn9XqCzUXd4bAVEsAXM/Izk11Wx2u4H3BAfQVhSfzfDOm/wAON9nP7J5rpkCxts7E5TELmN845xTUCQrD1xIQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.16.1.tgz", - "integrity": "sha512-0vFPk8tMjj6apaAZ1HlwM8w7jbghC8jc1aRNJG5vN8Ym5miyhTQGMqU++kuBFDNKe9NcPeZ6x0zfSzV8xC1UlQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/types": "7.16.1", - "@typescript-eslint/visitor-keys": "7.16.1", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/@typescript-eslint/type-utils/node_modules/minimatch": { + "node_modules/eslint-plugin-sonarjs/node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", @@ -9085,400 +8465,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/eslint-plugin-sonarjs/node_modules/@typescript-eslint/types": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", - "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", - "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", - "dev": true, - "license": "BSD-2-Clause", - "peer": true, - "dependencies": { - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", - "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@typescript-eslint/types": "7.18.0", - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/@typescript-eslint/utils": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.16.1.tgz", - "integrity": "sha512-WrFM8nzCowV0he0RlkotGDujx78xudsxnGMBHI88l5J8wEhED6yBwaSLP99ygfrzAjsQvcYQ94quDwI0d7E1fA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.16.1", - "@typescript-eslint/types": "7.16.1", - "@typescript-eslint/typescript-estree": "7.16.1" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.16.1.tgz", - "integrity": "sha512-AQn9XqCzUXd4bAVEsAXM/Izk11Wx2u4H3BAfQVhSfzfDOm/wAON9nP7J5rpkCxts7E5TELmN845xTUCQrD1xIQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.16.1.tgz", - "integrity": "sha512-0vFPk8tMjj6apaAZ1HlwM8w7jbghC8jc1aRNJG5vN8Ym5miyhTQGMqU++kuBFDNKe9NcPeZ6x0zfSzV8xC1UlQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/types": "7.16.1", - "@typescript-eslint/visitor-keys": "7.16.1", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/@typescript-eslint/utils/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.16.1.tgz", - "integrity": "sha512-Qlzzx4sE4u3FsHTPQAAQFJFNOuqtuY0LFrZHwQ8IHK705XxBiWOFkfKRWu6niB7hwfgnwIpO4jTC75ozW1PHWg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "7.16.1", - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/@typescript-eslint/visitor-keys/node_modules/@typescript-eslint/types": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.16.1.tgz", - "integrity": "sha512-AQn9XqCzUXd4bAVEsAXM/Izk11Wx2u4H3BAfQVhSfzfDOm/wAON9nP7J5rpkCxts7E5TELmN845xTUCQrD1xIQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/aria-query": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", - "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "deep-equal": "^2.0.5" - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/eslint-plugin-import": { - "version": "2.30.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.30.0.tgz", - "integrity": "sha512-/mHNE9jINJfiD2EKkg1BKyPyUk4zdnT54YgbOgfjSakWT5oyX/qQLVNTkehyfpcMxZXMy1zyonZ2v7hZTX43Yw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rtsao/scc": "^1.1.0", - "array-includes": "^3.1.8", - "array.prototype.findlastindex": "^1.2.5", - "array.prototype.flat": "^1.3.2", - "array.prototype.flatmap": "^1.3.2", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.9.0", - "hasown": "^2.0.2", - "is-core-module": "^2.15.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.8", - "object.groupby": "^1.0.3", - "object.values": "^1.2.0", - "semver": "^6.3.1", - "tsconfig-paths": "^3.15.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/eslint-plugin-import/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/eslint-plugin-import/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/eslint-plugin-import/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/eslint-plugin-jsx-a11y": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.0.tgz", - "integrity": "sha512-ySOHvXX8eSN6zz8Bywacm7CvGNhUtdjvqfQDVe6020TUK34Cywkw7m0KsCCk1Qtm9G1FayfTN1/7mMYnYO2Bhg==", - "dev": true, - "license": "MIT", - "dependencies": { - "aria-query": "~5.1.3", - "array-includes": "^3.1.8", - "array.prototype.flatmap": "^1.3.2", - "ast-types-flow": "^0.0.8", - "axe-core": "^4.10.0", - "axobject-query": "^4.1.0", - "damerau-levenshtein": "^1.0.8", - "emoji-regex": "^9.2.2", - "es-iterator-helpers": "^1.0.19", - "hasown": "^2.0.2", - "jsx-ast-utils": "^3.3.5", - "language-tags": "^1.0.9", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.8", - "safe-regex-test": "^1.0.3", - "string.prototype.includes": "^2.0.0" - }, - "engines": { - "node": ">=4.0" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/eslint-plugin-jsx-a11y/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/eslint-plugin-jsx-a11y/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/eslint-scope": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.1.0.tgz", - "integrity": "sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-plugin-sonarjs/node_modules/typescript": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", - "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, "node_modules/eslint-plugin-unicorn": { "version": "56.0.1", "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-56.0.1.tgz", @@ -9514,9 +8500,9 @@ } }, "node_modules/eslint-plugin-unicorn/node_modules/globals": { - "version": "15.13.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.13.0.tgz", - "integrity": "sha512-49TewVEz0UxZjr1WYYsWpPrhyC/B/pA8Bq0fUmet2n+eR7yn0IvNzNaoBwnK6mdkzcN+se7Ez9zUgULTz2QH4g==", + "version": "15.14.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.14.0.tgz", + "integrity": "sha512-OkToC372DtlQeje9/zHIo5CT8lRP/FUgEOKBEhU4e0abL7J7CD24fD9ohiLN5hagG/kWCYj4K5oaxxtj2Z0Dig==", "dev": true, "license": "MIT", "engines": { @@ -10995,9 +9981,9 @@ } }, "node_modules/jiti": { - "version": "1.21.6", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", - "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", "license": "MIT", "bin": { "jiti": "bin/jiti.js" @@ -11017,10 +10003,9 @@ "license": "MIT" }, "node_modules/js-tokens": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", - "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", - "dev": true, + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "license": "MIT" }, "node_modules/js-types": { @@ -11066,9 +10051,9 @@ } }, "node_modules/jsesc": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", - "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "dev": true, "license": "MIT", "bin": { @@ -11188,9 +10173,9 @@ "license": "MIT" }, "node_modules/katex": { - "version": "0.16.11", - "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.11.tgz", - "integrity": "sha512-RQrI8rlHY92OLf3rho/Ts8i/XvjgguEjOkO1BEXcU3N8BqPpSzBNwV/G0Ukr+P/l3ivvJUE/Fa/CwbS6HesGNQ==", + "version": "0.16.18", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.18.tgz", + "integrity": "sha512-LRuk0rPdXrecAFwQucYjMiIs0JFefk6N1q/04mlw14aVIVgxq1FO0MA9RiIIGVaKOB5GIP5GH4aBBNraZERmaQ==", "funding": [ "https://opencollective.com/katex", "https://github.com/sponsors/katex" @@ -11555,26 +10540,6 @@ "dev": true, "license": "MIT" }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/loose-envify/node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, - "license": "MIT" - }, "node_modules/loupe": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.2.tgz", @@ -11593,13 +10558,13 @@ } }, "node_modules/lru-cache": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.2.tgz", - "integrity": "sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, "license": "ISC", - "engines": { - "node": "20 || >=22" + "dependencies": { + "yallist": "^3.0.2" } }, "node_modules/magic-string": { @@ -11767,9 +10732,9 @@ } }, "node_modules/mdn-data": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.1.tgz", - "integrity": "sha512-rsfnCbOHjqrhWxwt5/wtSLzpoKTzW7OXdT5lLOIH1OTYhWu9rRJveGq0sKvDZODABH7RX+uoR+DYcpFnq4Tf6Q==", + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz", + "integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==", "dev": true, "license": "CC0-1.0" }, @@ -11959,9 +10924,9 @@ } }, "node_modules/monaco-editor": { - "version": "0.52.0", - "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.52.0.tgz", - "integrity": "sha512-OeWhNpABLCeTqubfqLMXGsqf6OmPU6pHM85kF3dhy6kq5hnhuVS1p3VrEW/XhWHc71P2tHyS5JFySD8mgs1crw==", + "version": "0.52.2", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.52.2.tgz", + "integrity": "sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ==", "license": "MIT" }, "node_modules/monaco-editor-webpack-plugin": { @@ -12079,9 +11044,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", "license": "MIT" }, "node_modules/node-sarif-builder": { @@ -12099,9 +11064,9 @@ } }, "node_modules/nolyfill": { - "version": "1.0.42", - "resolved": "https://registry.npmjs.org/nolyfill/-/nolyfill-1.0.42.tgz", - "integrity": "sha512-OG++zEsBoEbEmsuF/yjh91dLCTxt8tSJdV7ZzufpszpvG69opWsK9MfAnfjntVVQhreEeBNvwnftI/mCZVBh6w==", + "version": "1.0.43", + "resolved": "https://registry.npmjs.org/nolyfill/-/nolyfill-1.0.43.tgz", + "integrity": "sha512-wi8cCDStYl2cmKOWoF5Jv/0PZXkFcRgKpk9rtxWk+7/VDlI6WDBdPM5nUOsphZjibudajsyAh1+QQvxCyLnbMA==", "dev": true, "license": "MIT", "bin": { @@ -12198,20 +11163,6 @@ "node": ">=12.4.0" } }, - "node_modules/object.entries": { - "name": "@nolyfill/object.entries", - "version": "1.0.28", - "resolved": "https://registry.npmjs.org/@nolyfill/object.entries/-/object.entries-1.0.28.tgz", - "integrity": "sha512-2t4PayP6Sx7Z20HJjcf8XhhPBO8/H31bwMdP0yEdDcxSXeEhl90Ibb9E3XKzSlcsGf43nXyfabHNrnfvdWE4Ng==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nolyfill/shared": "1.0.28" - }, - "engines": { - "node": ">=12.4.0" - } - }, "node_modules/object.fromentries": { "name": "@nolyfill/object.fromentries", "version": "1.0.28", @@ -12434,6 +11385,16 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.2.tgz", + "integrity": "sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "20 || >=22" + } + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -12584,13 +11545,13 @@ } }, "node_modules/playwright": { - "version": "1.49.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.49.0.tgz", - "integrity": "sha512-eKpmys0UFDnfNb3vfsf8Vx2LEOtflgRebl0Im2eQQnYMA4Aqd+Zw8bEOB+7ZKvN76901mRnqdsiOGKxzVTbi7A==", + "version": "1.49.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.49.1.tgz", + "integrity": "sha512-VYL8zLoNTBxVOrJBbDuRgDWa3i+mfQgDTrL8Ah9QXZ7ax4Dsj0MSq5bYgytRnDVVe+njoKnfsYkH3HzqVj5UZA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.49.0" + "playwright-core": "1.49.1" }, "bin": { "playwright": "cli.js" @@ -12603,9 +11564,9 @@ } }, "node_modules/playwright-core": { - "version": "1.49.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.49.0.tgz", - "integrity": "sha512-R+3KKTQF3npy5GTiKH/T+kdhoJfJojjHESR1YEWhYuEKRVfVaxH3+4+GvXE5xyCngCxhxnykk0Vlah9v8fs3jA==", + "version": "1.49.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.49.1.tgz", + "integrity": "sha512-BzmpVcs4kE2CH15rWfzpjzVGhWERJfmnXmniSyKeRZUs9Ws65m+RGIi7mjJK/euCegfn3i7jvqWeWyHe9y3Vgg==", "dev": true, "license": "Apache-2.0", "bin": { @@ -12695,6 +11656,13 @@ "node": "^12 || >=14" } }, + "node_modules/postcss-html/node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "license": "MIT" + }, "node_modules/postcss-import": { "version": "15.1.0", "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", @@ -12810,9 +11778,9 @@ } }, "node_modules/postcss-modules-local-by-default": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.1.0.tgz", - "integrity": "sha512-rm0bdSv4jC3BDma3s9H19ZddW0aHX6EoqwDYU2IfZhRN+53QrufTRo2IdkAbRqLx4R2IYbZnbjKKxg4VN5oU9Q==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz", + "integrity": "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==", "license": "MIT", "dependencies": { "icss-utils": "^5.0.0", @@ -13127,18 +12095,6 @@ "dev": true, "license": "Unlicense" }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, - "license": "MIT", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, "node_modules/proto-props": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/proto-props/-/proto-props-2.0.0.tgz", @@ -13197,13 +12153,6 @@ "safe-buffer": "^5.1.0" } }, - "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true, - "license": "MIT" - }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -13438,6 +12387,19 @@ "node": ">=4" } }, + "node_modules/regexpu-core/node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/regexpu-core/node_modules/regjsparser": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", @@ -13509,12 +12471,12 @@ } }, "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "version": "1.22.9", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.9.tgz", + "integrity": "sha512-QxrmX1DzraFIi9PxdG5VkRfRwIgjwyud+z/iBwfRRrVmHc+P9Q7u2lSSpQ6bjr2gy5lrqIiU9vb6iAeGf2400A==", "license": "MIT", "dependencies": { - "is-core-module": "^2.13.0", + "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -13716,9 +12678,9 @@ "license": "ISC" }, "node_modules/schema-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", - "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz", + "integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==", "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.9", @@ -13727,7 +12689,7 @@ "ajv-keywords": "^5.1.0" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 10.13.0" }, "funding": { "type": "opencollective", @@ -14125,34 +13087,6 @@ "node": ">=12.4.0" } }, - "node_modules/string.prototype.matchall": { - "name": "@nolyfill/string.prototype.matchall", - "version": "1.0.28", - "resolved": "https://registry.npmjs.org/@nolyfill/string.prototype.matchall/-/string.prototype.matchall-1.0.28.tgz", - "integrity": "sha512-k74WKi7WmtRV847QWlY1ndg6XU1loeAyO9+NVoXrd7RL5lEjBtovp4CPZkifipBMBrZrZu2WwrQqkGrvLNZYpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nolyfill/shared": "1.0.28" - }, - "engines": { - "node": ">=12.4.0" - } - }, - "node_modules/string.prototype.repeat": { - "name": "@nolyfill/string.prototype.repeat", - "version": "1.0.28", - "resolved": "https://registry.npmjs.org/@nolyfill/string.prototype.repeat/-/string.prototype.repeat-1.0.28.tgz", - "integrity": "sha512-8ww39xe0r4qki8HwAaXTRamO0KpkHHyYoG+PCOFGaBZ8rrlAKcGQcJhu5aB2axauggqsnUfU25j5snEC0aJvYg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nolyfill/shared": "1.0.28" - }, - "engines": { - "node": ">=12.4.0" - } - }, "node_modules/string.prototype.trimend": { "name": "@nolyfill/string.prototype.trimend", "version": "1.0.28", @@ -14236,9 +13170,9 @@ "license": "ISC" }, "node_modules/stylelint": { - "version": "16.11.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.11.0.tgz", - "integrity": "sha512-zrl4IrKmjJQ+h9FoMp69UMCq5SxeHk0URhxUBj4d3ISzo/DplOFBJZc7t7Dr6otB+1bfbbKNLOmCDpzKSlW+Nw==", + "version": "16.12.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.12.0.tgz", + "integrity": "sha512-F8zZ3L/rBpuoBZRvI4JVT20ZanPLXfQLzMOZg1tzPflRVh9mKpOZ8qcSIhh1my3FjAjZWG4T2POwGnmn6a6hbg==", "dev": true, "funding": [ { @@ -14288,7 +13222,7 @@ "string-width": "^4.2.3", "supports-hyperlinks": "^3.1.0", "svg-tags": "^1.0.0", - "table": "^6.8.2", + "table": "^6.9.0", "write-file-atomic": "^5.0.1" }, "bin": { @@ -14801,9 +13735,9 @@ } }, "node_modules/tailwindcss": { - "version": "3.4.16", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.16.tgz", - "integrity": "sha512-TI4Cyx7gDiZ6r44ewaJmt0o6BrMCT5aK5e0rmJ/G9Xq3w7CX/5VXl/zIPEJZFUK5VEqwByyhqNPycPlvcK4ZNw==", + "version": "3.4.17", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz", + "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==", "license": "MIT", "dependencies": { "@alloc/quick-lru": "^5.2.0", @@ -14847,9 +13781,9 @@ } }, "node_modules/terser": { - "version": "5.36.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.36.0.tgz", - "integrity": "sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.37.0.tgz", + "integrity": "sha512-B8wRRkmre4ERucLM/uXx4MOV5cbnOlVAqUst+1+iLKPI0dOgFO28f84ptoQt9HEI537PMzfYa/d+GEPKTRXmYA==", "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -14865,16 +13799,16 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.10", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", - "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "version": "5.3.11", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.11.tgz", + "integrity": "sha512-RVCsMfuD0+cTt3EwX8hSl2Ks56EbFHWmhluwcqoPKtBnfjiT6olaq7PRIRfhyU8nnC2MrnDrBLfrD/RGE+cVXQ==", "license": "MIT", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.20", + "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.1", - "terser": "^5.26.0" + "schema-utils": "^4.3.0", + "serialize-javascript": "^6.0.2", + "terser": "^5.31.1" }, "engines": { "node": ">= 10.13.0" @@ -14898,55 +13832,6 @@ } } }, - "node_modules/terser-webpack-plugin/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "license": "MIT", - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "license": "MIT" - }, - "node_modules/terser-webpack-plugin/node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, "node_modules/terser/node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -15153,9 +14038,9 @@ } }, "node_modules/type-fest": { - "version": "4.30.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.30.0.tgz", - "integrity": "sha512-G6zXWS1dLj6eagy6sVhOMQiLtJdxQBHIA9Z6HFUNLOlr6MFOgzV8wvmidtPONfPtEUv0uZsy77XJNzTAfwPDaA==", + "version": "4.30.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.30.2.tgz", + "integrity": "sha512-UJShLPYi1aWqCdq9HycOL/gwsuqda1OISdBO3t8RlXQC4QvtuIz4b5FCfe2dQIWEpmlRExKmcTBfP1r9bhY7ig==", "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { @@ -15179,15 +14064,15 @@ } }, "node_modules/typescript-eslint": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.17.0.tgz", - "integrity": "sha512-409VXvFd/f1br1DCbuKNFqQpXICoTB+V51afcwG1pn1a3Cp92MqAUges3YjwEdQ0cMUoCIodjVDAYzyD8h3SYA==", + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.18.1.tgz", + "integrity": "sha512-Mlaw6yxuaDEPQvb/2Qwu3/TfgeBHy9iTJ3mTwe7OvpPmF6KPQjVOfGyEJpPv6Ez2C34OODChhXrzYw/9phI0MQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.17.0", - "@typescript-eslint/parser": "8.17.0", - "@typescript-eslint/utils": "8.17.0" + "@typescript-eslint/eslint-plugin": "8.18.1", + "@typescript-eslint/parser": "8.18.1", + "@typescript-eslint/utils": "8.18.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -15197,18 +14082,14 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/typo-js": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/typo-js/-/typo-js-1.2.4.tgz", - "integrity": "sha512-Oy/k+tFle5NAA3J/yrrYGfvEnPVrDZ8s8/WCwjUE75k331QyKIsFss7byQ/PzBmXLY6h1moRnZbnaxWBe3I3CA==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/typo-js/-/typo-js-1.2.5.tgz", + "integrity": "sha512-F45vFWdGX8xahIk/sOp79z2NJs8ETMYsmMChm9D5Hlx3+9j7VnCyQyvij5MOCrNY3NNe8noSyokRjQRfq+Bc7A==", "license": "BSD-3-Clause" }, "node_modules/uc.micro": { @@ -15321,9 +14202,9 @@ } }, "node_modules/updates": { - "version": "16.4.0", - "resolved": "https://registry.npmjs.org/updates/-/updates-16.4.0.tgz", - "integrity": "sha512-HtkG1MgXbQ5gpqu5eX4qVOwclMHbygiTYjSkFMVDEXuwb5clwkDh75xRb11PzRX9ozVOfcVUHl7lpBNDPquXrw==", + "version": "16.4.1", + "resolved": "https://registry.npmjs.org/updates/-/updates-16.4.1.tgz", + "integrity": "sha512-dYsXzAISSiTFk6mg2ZB7IOlhIN5CO4qINxpbN7rrE9ffpuycq82SZ8rvLSc2QpBEO98BBY7wKm3d8SdA94o5TQ==", "dev": true, "license": "BSD-2-Clause", "bin": { @@ -15518,9 +14399,9 @@ } }, "node_modules/vite/node_modules/rollup": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.28.0.tgz", - "integrity": "sha512-G9GOrmgWHBma4YfCcX8PjH0qhXSdH8B4HDE2o4/jaxj93S4DPCIDoLcXz99eWMji4hB29UFCEd7B2gwGJDR9cQ==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.28.1.tgz", + "integrity": "sha512-61fXYl/qNVinKmGSTHAZ6Yy8I3YIJC/r2m9feHo6SwVAVcLT5MPwOUFe7EuURA/4m0NR8lXG4BBXuo/IZEsjMg==", "dev": true, "license": "MIT", "dependencies": { @@ -15534,24 +14415,25 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.28.0", - "@rollup/rollup-android-arm64": "4.28.0", - "@rollup/rollup-darwin-arm64": "4.28.0", - "@rollup/rollup-darwin-x64": "4.28.0", - "@rollup/rollup-freebsd-arm64": "4.28.0", - "@rollup/rollup-freebsd-x64": "4.28.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.28.0", - "@rollup/rollup-linux-arm-musleabihf": "4.28.0", - "@rollup/rollup-linux-arm64-gnu": "4.28.0", - "@rollup/rollup-linux-arm64-musl": "4.28.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.28.0", - "@rollup/rollup-linux-riscv64-gnu": "4.28.0", - "@rollup/rollup-linux-s390x-gnu": "4.28.0", - "@rollup/rollup-linux-x64-gnu": "4.28.0", - "@rollup/rollup-linux-x64-musl": "4.28.0", - "@rollup/rollup-win32-arm64-msvc": "4.28.0", - "@rollup/rollup-win32-ia32-msvc": "4.28.0", - "@rollup/rollup-win32-x64-msvc": "4.28.0", + "@rollup/rollup-android-arm-eabi": "4.28.1", + "@rollup/rollup-android-arm64": "4.28.1", + "@rollup/rollup-darwin-arm64": "4.28.1", + "@rollup/rollup-darwin-x64": "4.28.1", + "@rollup/rollup-freebsd-arm64": "4.28.1", + "@rollup/rollup-freebsd-x64": "4.28.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.28.1", + "@rollup/rollup-linux-arm-musleabihf": "4.28.1", + "@rollup/rollup-linux-arm64-gnu": "4.28.1", + "@rollup/rollup-linux-arm64-musl": "4.28.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.28.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.28.1", + "@rollup/rollup-linux-riscv64-gnu": "4.28.1", + "@rollup/rollup-linux-s390x-gnu": "4.28.1", + "@rollup/rollup-linux-x64-gnu": "4.28.1", + "@rollup/rollup-linux-x64-musl": "4.28.1", + "@rollup/rollup-win32-arm64-msvc": "4.28.1", + "@rollup/rollup-win32-ia32-msvc": "4.28.1", + "@rollup/rollup-win32-x64-msvc": "4.28.1", "fsevents": "~2.3.2" } }, @@ -15622,9 +14504,9 @@ } }, "node_modules/vitest/node_modules/magic-string": { - "version": "0.30.14", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.14.tgz", - "integrity": "sha512-5c99P1WKTed11ZC0HMJOj6CDIue6F8ySu+bJL+85q1zBEIY8IklrJ1eiKC2NDRh3Ct3FcvmJPyQHb9erXMTJNw==", + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", "dev": true, "license": "MIT", "dependencies": { @@ -15822,9 +14704,9 @@ } }, "node_modules/webpack": { - "version": "5.97.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.97.0.tgz", - "integrity": "sha512-CWT8v7ShSfj7tGs4TLRtaOLmOCPWhoKEvp+eA7FVx8Xrjb3XfT0aXdxDItnRZmE8sHcH+a8ayDrJCOjXKxVFfQ==", + "version": "5.97.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.97.1.tgz", + "integrity": "sha512-EksG6gFY3L1eFMROS/7Wzgrii5mBAFe4rIr3r2BTfo7bcc+DWwFZ4OJ/miOuHJO/A85HwyI4eQ0F6IKXesO7Fg==", "license": "MIT", "dependencies": { "@types/eslint-scope": "^3.7.7", diff --git a/package.json b/package.json index 61e65c1f43..9f5fbe3fdd 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "@github/relative-time-element": "4.4.4", "@github/text-expander-element": "2.8.0", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", - "@primer/octicons": "19.13.0", + "@primer/octicons": "19.14.0", "@silverwind/vue3-calendar-heatmap": "2.0.6", "add-asset-webpack-plugin": "3.0.0", "ansi_up": "6.0.2", @@ -32,12 +32,12 @@ "htmx.org": "2.0.4", "idiomorph": "0.3.0", "jquery": "3.7.1", - "katex": "0.16.11", + "katex": "0.16.18", "license-checker-webpack-plugin": "0.2.1", "mermaid": "11.4.1", "mini-css-extract-plugin": "2.9.2", "minimatch": "10.0.1", - "monaco-editor": "0.52.0", + "monaco-editor": "0.52.2", "monaco-editor-webpack-plugin": "7.1.0", "pdfobject": "2.3.0", "perfect-debounce": "1.0.0", @@ -46,7 +46,7 @@ "postcss-nesting": "13.0.1", "sortablejs": "1.15.6", "swagger-ui-dist": "5.18.2", - "tailwindcss": "3.4.16", + "tailwindcss": "3.4.17", "throttle-debounce": "5.0.2", "tinycolor2": "1.6.0", "tippy.js": "6.3.7", @@ -59,16 +59,16 @@ "vue-bar-graph": "2.2.0", "vue-chartjs": "5.3.2", "vue-loader": "17.4.2", - "webpack": "5.97.0", + "webpack": "5.97.1", "webpack-cli": "5.1.4", "wrap-ansi": "9.0.0" }, "devDependencies": { "@eslint-community/eslint-plugin-eslint-comments": "4.4.1", - "@playwright/test": "1.49.0", + "@playwright/test": "1.49.1", "@silverwind/vue-tsc": "2.1.13", "@stoplight/spectral-cli": "6.14.2", - "@stylistic/eslint-plugin-js": "2.11.0", + "@stylistic/eslint-plugin-js": "2.12.1", "@stylistic/stylelint-plugin": "3.1.1", "@types/dropzone": "5.7.9", "@types/jquery": "3.5.32", @@ -80,19 +80,19 @@ "@types/throttle-debounce": "5.0.2", "@types/tinycolor2": "1.4.6", "@types/toastify-js": "1.12.3", - "@typescript-eslint/eslint-plugin": "8.17.0", - "@typescript-eslint/parser": "8.17.0", + "@typescript-eslint/eslint-plugin": "8.18.1", + "@typescript-eslint/parser": "8.18.1", "@vitejs/plugin-vue": "5.2.1", "eslint": "8.57.0", "eslint-import-resolver-typescript": "3.7.0", "eslint-plugin-array-func": "4.0.0", - "eslint-plugin-github": "5.1.3", - "eslint-plugin-import-x": "4.5.0", + "eslint-plugin-github": "5.1.4", + "eslint-plugin-import-x": "4.6.1", "eslint-plugin-no-jquery": "3.1.0", "eslint-plugin-no-use-extend-native": "0.5.0", "eslint-plugin-playwright": "2.1.0", "eslint-plugin-regexp": "2.7.0", - "eslint-plugin-sonarjs": "2.0.4", + "eslint-plugin-sonarjs": "3.0.1", "eslint-plugin-unicorn": "56.0.1", "eslint-plugin-vitest": "0.4.1", "eslint-plugin-vitest-globals": "1.5.0", @@ -101,15 +101,15 @@ "eslint-plugin-wc": "2.2.0", "happy-dom": "15.11.7", "markdownlint-cli": "0.43.0", - "nolyfill": "1.0.42", + "nolyfill": "1.0.43", "postcss-html": "1.7.0", - "stylelint": "16.11.0", + "stylelint": "16.12.0", "stylelint-declaration-block-no-ignored-properties": "2.8.0", "stylelint-declaration-strict-value": "1.10.6", "stylelint-value-no-unknown-custom-properties": "6.0.1", "svgo": "3.3.2", - "type-fest": "4.30.0", - "updates": "16.4.0", + "type-fest": "4.30.2", + "updates": "16.4.1", "vite-string-plugin": "1.3.4", "vitest": "2.1.8" }, diff --git a/routers/api/v1/admin/user.go b/routers/api/v1/admin/user.go index b0f40084da..3f4a73dcad 100644 --- a/routers/api/v1/admin/user.go +++ b/routers/api/v1/admin/user.go @@ -9,10 +9,12 @@ import ( "fmt" "net/http" - "code.gitea.io/gitea/models" asymkey_model "code.gitea.io/gitea/models/asymkey" "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/db" + org_model "code.gitea.io/gitea/models/organization" + packages_model "code.gitea.io/gitea/models/packages" + repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/auth/password" "code.gitea.io/gitea/modules/log" @@ -247,7 +249,7 @@ func EditUser(ctx *context.APIContext) { } if err := user_service.UpdateUser(ctx, ctx.ContextUser, opts); err != nil { - if models.IsErrDeleteLastAdminUser(err) { + if user_model.IsErrDeleteLastAdminUser(err) { ctx.Error(http.StatusBadRequest, "LastAdmin", err) } else { ctx.Error(http.StatusInternalServerError, "UpdateUser", err) @@ -299,10 +301,10 @@ func DeleteUser(ctx *context.APIContext) { } if err := user_service.DeleteUser(ctx, ctx.ContextUser, ctx.FormBool("purge")); err != nil { - if models.IsErrUserOwnRepos(err) || - models.IsErrUserHasOrgs(err) || - models.IsErrUserOwnPackages(err) || - models.IsErrDeleteLastAdminUser(err) { + if repo_model.IsErrUserOwnRepos(err) || + org_model.IsErrUserHasOrgs(err) || + packages_model.IsErrUserOwnPackages(err) || + user_model.IsErrDeleteLastAdminUser(err) { ctx.Error(http.StatusUnprocessableEntity, "", err) } else { ctx.Error(http.StatusInternalServerError, "DeleteUser", err) diff --git a/routers/api/v1/repo/branch.go b/routers/api/v1/repo/branch.go index 946203e97e..9a31aec314 100644 --- a/routers/api/v1/repo/branch.go +++ b/routers/api/v1/repo/branch.go @@ -9,7 +9,6 @@ import ( "fmt" "net/http" - "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" git_model "code.gitea.io/gitea/models/git" "code.gitea.io/gitea/models/organization" @@ -24,6 +23,7 @@ import ( "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" pull_service "code.gitea.io/gitea/services/pull" + release_service "code.gitea.io/gitea/services/release" repo_service "code.gitea.io/gitea/services/repository" ) @@ -247,7 +247,7 @@ func CreateBranch(ctx *context.APIContext) { if err != nil { if git_model.IsErrBranchNotExist(err) { ctx.Error(http.StatusNotFound, "", "The old branch does not exist") - } else if models.IsErrTagAlreadyExists(err) { + } else if release_service.IsErrTagAlreadyExists(err) { ctx.Error(http.StatusConflict, "", "The branch with the same tag already exists.") } else if git_model.IsErrBranchAlreadyExists(err) || git.IsErrPushOutOfDate(err) { ctx.Error(http.StatusConflict, "", "The branch already exists.") diff --git a/routers/api/v1/repo/file.go b/routers/api/v1/repo/file.go index 959a4b952a..83848b7add 100644 --- a/routers/api/v1/repo/file.go +++ b/routers/api/v1/repo/file.go @@ -15,7 +15,6 @@ import ( "strings" "time" - "code.gitea.io/gitea/models" git_model "code.gitea.io/gitea/models/git" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" @@ -30,6 +29,7 @@ import ( "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/common" "code.gitea.io/gitea/services/context" + pull_service "code.gitea.io/gitea/services/pull" archiver_service "code.gitea.io/gitea/services/repository/archiver" files_service "code.gitea.io/gitea/services/repository/files" ) @@ -736,12 +736,12 @@ func UpdateFile(ctx *context.APIContext) { } func handleCreateOrUpdateFileError(ctx *context.APIContext, err error) { - if models.IsErrUserCannotCommit(err) || models.IsErrFilePathProtected(err) { + if files_service.IsErrUserCannotCommit(err) || pull_service.IsErrFilePathProtected(err) { ctx.Error(http.StatusForbidden, "Access", err) return } - if git_model.IsErrBranchAlreadyExists(err) || models.IsErrFilenameInvalid(err) || models.IsErrSHADoesNotMatch(err) || - models.IsErrFilePathInvalid(err) || models.IsErrRepoFileAlreadyExists(err) { + if git_model.IsErrBranchAlreadyExists(err) || files_service.IsErrFilenameInvalid(err) || pull_service.IsErrSHADoesNotMatch(err) || + files_service.IsErrFilePathInvalid(err) || files_service.IsErrRepoFileAlreadyExists(err) { ctx.Error(http.StatusUnprocessableEntity, "Invalid", err) return } @@ -887,17 +887,17 @@ func DeleteFile(ctx *context.APIContext) { } if filesResponse, err := files_service.ChangeRepoFiles(ctx, ctx.Repo.Repository, ctx.Doer, opts); err != nil { - if git.IsErrBranchNotExist(err) || models.IsErrRepoFileDoesNotExist(err) || git.IsErrNotExist(err) { + if git.IsErrBranchNotExist(err) || files_service.IsErrRepoFileDoesNotExist(err) || git.IsErrNotExist(err) { ctx.Error(http.StatusNotFound, "DeleteFile", err) return } else if git_model.IsErrBranchAlreadyExists(err) || - models.IsErrFilenameInvalid(err) || - models.IsErrSHADoesNotMatch(err) || - models.IsErrCommitIDDoesNotMatch(err) || - models.IsErrSHAOrCommitIDNotProvided(err) { + files_service.IsErrFilenameInvalid(err) || + pull_service.IsErrSHADoesNotMatch(err) || + files_service.IsErrCommitIDDoesNotMatch(err) || + files_service.IsErrSHAOrCommitIDNotProvided(err) { ctx.Error(http.StatusBadRequest, "DeleteFile", err) return - } else if models.IsErrUserCannotCommit(err) { + } else if files_service.IsErrUserCannotCommit(err) { ctx.Error(http.StatusForbidden, "DeleteFile", err) return } diff --git a/routers/api/v1/repo/migrate.go b/routers/api/v1/repo/migrate.go index dcbd8f3dd5..452825c0a3 100644 --- a/routers/api/v1/repo/migrate.go +++ b/routers/api/v1/repo/migrate.go @@ -10,13 +10,13 @@ import ( "net/http" "strings" - "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/perm" access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/lfs" "code.gitea.io/gitea/modules/log" @@ -27,7 +27,6 @@ import ( "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" - "code.gitea.io/gitea/services/forms" "code.gitea.io/gitea/services/migrations" notify_service "code.gitea.io/gitea/services/notify" repo_service "code.gitea.io/gitea/services/repository" @@ -104,7 +103,7 @@ func Migrate(ctx *context.APIContext) { } } - remoteAddr, err := forms.ParseRemoteAddr(form.CloneAddr, form.AuthUsername, form.AuthPassword) + remoteAddr, err := git.ParseRemoteAddr(form.CloneAddr, form.AuthUsername, form.AuthPassword) if err == nil { err = migrations.IsMigrateURLAllowed(remoteAddr, ctx.Doer) } @@ -237,7 +236,7 @@ func handleMigrateError(ctx *context.APIContext, repoOwner *user_model.User, err ctx.Error(http.StatusUnprocessableEntity, "", fmt.Sprintf("The username '%s' contains invalid characters.", err.(db.ErrNameCharsNotAllowed).Name)) case db.IsErrNamePatternNotAllowed(err): ctx.Error(http.StatusUnprocessableEntity, "", fmt.Sprintf("The pattern '%s' is not allowed in a username.", err.(db.ErrNamePatternNotAllowed).Pattern)) - case models.IsErrInvalidCloneAddr(err): + case git.IsErrInvalidCloneAddr(err): ctx.Error(http.StatusUnprocessableEntity, "", err) case base.IsErrNotSupported(err): ctx.Error(http.StatusUnprocessableEntity, "", err) @@ -256,8 +255,8 @@ func handleMigrateError(ctx *context.APIContext, repoOwner *user_model.User, err } func handleRemoteAddrError(ctx *context.APIContext, err error) { - if models.IsErrInvalidCloneAddr(err) { - addrErr := err.(*models.ErrInvalidCloneAddr) + if git.IsErrInvalidCloneAddr(err) { + addrErr := err.(*git.ErrInvalidCloneAddr) switch { case addrErr.IsURLError: ctx.Error(http.StatusUnprocessableEntity, "", err) diff --git a/routers/api/v1/repo/mirror.go b/routers/api/v1/repo/mirror.go index 310b82881e..047203501e 100644 --- a/routers/api/v1/repo/mirror.go +++ b/routers/api/v1/repo/mirror.go @@ -9,10 +9,10 @@ import ( "net/http" "time" - "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" @@ -20,7 +20,6 @@ import ( "code.gitea.io/gitea/routers/api/v1/utils" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" - "code.gitea.io/gitea/services/forms" "code.gitea.io/gitea/services/migrations" mirror_service "code.gitea.io/gitea/services/mirror" ) @@ -344,7 +343,7 @@ func CreatePushMirror(ctx *context.APIContext, mirrorOption *api.CreatePushMirro return } - address, err := forms.ParseRemoteAddr(mirrorOption.RemoteAddress, mirrorOption.RemoteUsername, mirrorOption.RemotePassword) + address, err := git.ParseRemoteAddr(mirrorOption.RemoteAddress, mirrorOption.RemoteUsername, mirrorOption.RemotePassword) if err == nil { err = migrations.IsMigrateURLAllowed(address, ctx.ContextUser) } @@ -397,8 +396,8 @@ func CreatePushMirror(ctx *context.APIContext, mirrorOption *api.CreatePushMirro } func HandleRemoteAddressError(ctx *context.APIContext, err error) { - if models.IsErrInvalidCloneAddr(err) { - addrErr := err.(*models.ErrInvalidCloneAddr) + if git.IsErrInvalidCloneAddr(err) { + addrErr := err.(*git.ErrInvalidCloneAddr) switch { case addrErr.IsProtocolInvalid: ctx.Error(http.StatusBadRequest, "CreatePushMirror", "Invalid mirror protocol") diff --git a/routers/api/v1/repo/patch.go b/routers/api/v1/repo/patch.go index 0e0601b7d9..5e24dcf891 100644 --- a/routers/api/v1/repo/patch.go +++ b/routers/api/v1/repo/patch.go @@ -7,13 +7,13 @@ import ( "net/http" "time" - "code.gitea.io/gitea/models" git_model "code.gitea.io/gitea/models/git" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/git" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/context" + pull_service "code.gitea.io/gitea/services/pull" "code.gitea.io/gitea/services/repository/files" ) @@ -92,12 +92,12 @@ func ApplyDiffPatch(ctx *context.APIContext) { fileResponse, err := files.ApplyDiffPatch(ctx, ctx.Repo.Repository, ctx.Doer, opts) if err != nil { - if models.IsErrUserCannotCommit(err) || models.IsErrFilePathProtected(err) { + if files.IsErrUserCannotCommit(err) || pull_service.IsErrFilePathProtected(err) { ctx.Error(http.StatusForbidden, "Access", err) return } - if git_model.IsErrBranchAlreadyExists(err) || models.IsErrFilenameInvalid(err) || models.IsErrSHADoesNotMatch(err) || - models.IsErrFilePathInvalid(err) || models.IsErrRepoFileAlreadyExists(err) { + if git_model.IsErrBranchAlreadyExists(err) || files.IsErrFilenameInvalid(err) || pull_service.IsErrSHADoesNotMatch(err) || + files.IsErrFilePathInvalid(err) || files.IsErrRepoFileAlreadyExists(err) { ctx.Error(http.StatusUnprocessableEntity, "Invalid", err) return } diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index 6f4f3efaa1..71c4c81b67 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -12,7 +12,6 @@ import ( "strings" "time" - "code.gitea.io/gitea/models" activities_model "code.gitea.io/gitea/models/activities" git_model "code.gitea.io/gitea/models/git" issues_model "code.gitea.io/gitea/models/issues" @@ -765,7 +764,7 @@ func EditPullRequest(ctx *context.APIContext) { } else if issues_model.IsErrIssueIsClosed(err) { ctx.Error(http.StatusUnprocessableEntity, "IsErrIssueIsClosed", err) return - } else if models.IsErrPullRequestHasMerged(err) { + } else if pull_service.IsErrPullRequestHasMerged(err) { ctx.Error(http.StatusConflict, "IsErrPullRequestHasMerged", err) return } @@ -941,7 +940,7 @@ func MergePullRequest(ctx *context.APIContext) { ctx.Error(http.StatusMethodNotAllowed, "PR is a work in progress", "Work in progress PRs cannot be merged") } else if errors.Is(err, pull_service.ErrNotMergeableState) { ctx.Error(http.StatusMethodNotAllowed, "PR not in mergeable state", "Please try again later") - } else if models.IsErrDisallowedToMerge(err) { + } else if pull_service.IsErrDisallowedToMerge(err) { ctx.Error(http.StatusMethodNotAllowed, "PR is not ready to be merged", err) } else if asymkey_service.IsErrWontSign(err) { ctx.Error(http.StatusMethodNotAllowed, fmt.Sprintf("Protected branch %s requires signed commits but this merge would not be signed", pr.BaseBranch), err) @@ -954,7 +953,7 @@ func MergePullRequest(ctx *context.APIContext) { // handle manually-merged mark if manuallyMerged { if err := pull_service.MergedManually(ctx, pr, ctx.Doer, ctx.Repo.GitRepo, form.MergeCommitID); err != nil { - if models.IsErrInvalidMergeStyle(err) { + if pull_service.IsErrInvalidMergeStyle(err) { ctx.Error(http.StatusMethodNotAllowed, "Invalid merge style", fmt.Errorf("%s is not allowed an allowed merge style for this repository", repo_model.MergeStyle(form.Do))) return } @@ -1004,20 +1003,20 @@ func MergePullRequest(ctx *context.APIContext) { } if err := pull_service.Merge(ctx, pr, ctx.Doer, ctx.Repo.GitRepo, repo_model.MergeStyle(form.Do), form.HeadCommitID, message, false); err != nil { - if models.IsErrInvalidMergeStyle(err) { + if pull_service.IsErrInvalidMergeStyle(err) { ctx.Error(http.StatusMethodNotAllowed, "Invalid merge style", fmt.Errorf("%s is not allowed an allowed merge style for this repository", repo_model.MergeStyle(form.Do))) - } else if models.IsErrMergeConflicts(err) { - conflictError := err.(models.ErrMergeConflicts) + } else if pull_service.IsErrMergeConflicts(err) { + conflictError := err.(pull_service.ErrMergeConflicts) ctx.JSON(http.StatusConflict, conflictError) - } else if models.IsErrRebaseConflicts(err) { - conflictError := err.(models.ErrRebaseConflicts) + } else if pull_service.IsErrRebaseConflicts(err) { + conflictError := err.(pull_service.ErrRebaseConflicts) ctx.JSON(http.StatusConflict, conflictError) - } else if models.IsErrMergeUnrelatedHistories(err) { - conflictError := err.(models.ErrMergeUnrelatedHistories) + } else if pull_service.IsErrMergeUnrelatedHistories(err) { + conflictError := err.(pull_service.ErrMergeUnrelatedHistories) ctx.JSON(http.StatusConflict, conflictError) } else if git.IsErrPushOutOfDate(err) { ctx.Error(http.StatusConflict, "Merge", "merge push out of date") - } else if models.IsErrSHADoesNotMatch(err) { + } else if pull_service.IsErrSHADoesNotMatch(err) { ctx.Error(http.StatusConflict, "Merge", "head out of date") } else if git.IsErrPushRejected(err) { errPushRej := err.(*git.ErrPushRejected) @@ -1308,10 +1307,10 @@ func UpdatePullRequest(ctx *context.APIContext) { message := fmt.Sprintf("Merge branch '%s' into %s", pr.BaseBranch, pr.HeadBranch) if err = pull_service.Update(ctx, pr, ctx.Doer, message, rebase); err != nil { - if models.IsErrMergeConflicts(err) { + if pull_service.IsErrMergeConflicts(err) { ctx.Error(http.StatusConflict, "Update", "merge failed because of conflict") return - } else if models.IsErrRebaseConflicts(err) { + } else if pull_service.IsErrRebaseConflicts(err) { ctx.Error(http.StatusConflict, "Update", "rebase failed because of conflict") return } diff --git a/routers/api/v1/repo/release.go b/routers/api/v1/repo/release.go index 478bdbd797..141f812172 100644 --- a/routers/api/v1/repo/release.go +++ b/routers/api/v1/repo/release.go @@ -7,7 +7,6 @@ import ( "fmt" "net/http" - "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/perm" repo_model "code.gitea.io/gitea/models/repo" @@ -250,7 +249,7 @@ func CreateRelease(ctx *context.APIContext) { if err := release_service.CreateRelease(ctx.Repo.GitRepo, rel, nil, ""); err != nil { if repo_model.IsErrReleaseAlreadyExist(err) { ctx.Error(http.StatusConflict, "ReleaseAlreadyExist", err) - } else if models.IsErrProtectedTagName(err) { + } else if release_service.IsErrProtectedTagName(err) { ctx.Error(http.StatusUnprocessableEntity, "ProtectedTagName", err) } else if git.IsErrNotExist(err) { ctx.Error(http.StatusNotFound, "ErrNotExist", fmt.Errorf("target \"%v\" not found: %w", rel.Target, err)) @@ -408,7 +407,7 @@ func DeleteRelease(ctx *context.APIContext) { return } if err := release_service.DeleteReleaseByID(ctx, ctx.Repo.Repository, rel, ctx.Doer, false); err != nil { - if models.IsErrProtectedTagName(err) { + if release_service.IsErrProtectedTagName(err) { ctx.Error(http.StatusUnprocessableEntity, "delTag", "user not allowed to delete protected tag") return } diff --git a/routers/api/v1/repo/release_tags.go b/routers/api/v1/repo/release_tags.go index 6df47af8d9..99f7a8cbf2 100644 --- a/routers/api/v1/repo/release_tags.go +++ b/routers/api/v1/repo/release_tags.go @@ -6,11 +6,10 @@ package repo import ( "net/http" - "code.gitea.io/gitea/models" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" - releaseservice "code.gitea.io/gitea/services/release" + release_service "code.gitea.io/gitea/services/release" ) // GetReleaseByTag get a single release of a repository by tag name @@ -112,8 +111,8 @@ func DeleteReleaseByTag(ctx *context.APIContext) { return } - if err = releaseservice.DeleteReleaseByID(ctx, ctx.Repo.Repository, release, ctx.Doer, false); err != nil { - if models.IsErrProtectedTagName(err) { + if err = release_service.DeleteReleaseByID(ctx, ctx.Repo.Repository, release, ctx.Doer, false); err != nil { + if release_service.IsErrProtectedTagName(err) { ctx.Error(http.StatusUnprocessableEntity, "delTag", "user not allowed to delete protected tag") return } diff --git a/routers/api/v1/repo/tag.go b/routers/api/v1/repo/tag.go index a72df78666..fe0910c735 100644 --- a/routers/api/v1/repo/tag.go +++ b/routers/api/v1/repo/tag.go @@ -9,7 +9,6 @@ import ( "net/http" "strings" - "code.gitea.io/gitea/models" git_model "code.gitea.io/gitea/models/git" "code.gitea.io/gitea/models/organization" repo_model "code.gitea.io/gitea/models/repo" @@ -19,7 +18,7 @@ import ( "code.gitea.io/gitea/routers/api/v1/utils" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" - releaseservice "code.gitea.io/gitea/services/release" + release_service "code.gitea.io/gitea/services/release" ) // ListTags list all the tags of a repository @@ -205,12 +204,12 @@ func CreateTag(ctx *context.APIContext) { return } - if err := releaseservice.CreateNewTag(ctx, ctx.Doer, ctx.Repo.Repository, commit.ID.String(), form.TagName, form.Message); err != nil { - if models.IsErrTagAlreadyExists(err) { + if err := release_service.CreateNewTag(ctx, ctx.Doer, ctx.Repo.Repository, commit.ID.String(), form.TagName, form.Message); err != nil { + if release_service.IsErrTagAlreadyExists(err) { ctx.Error(http.StatusConflict, "tag exist", err) return } - if models.IsErrProtectedTagName(err) { + if release_service.IsErrProtectedTagName(err) { ctx.Error(http.StatusUnprocessableEntity, "CreateNewTag", "user not allowed to create protected tag") return } @@ -280,8 +279,8 @@ func DeleteTag(ctx *context.APIContext) { return } - if err = releaseservice.DeleteReleaseByID(ctx, ctx.Repo.Repository, tag, ctx.Doer, true); err != nil { - if models.IsErrProtectedTagName(err) { + if err = release_service.DeleteReleaseByID(ctx, ctx.Repo.Repository, tag, ctx.Doer, true); err != nil { + if release_service.IsErrProtectedTagName(err) { ctx.Error(http.StatusUnprocessableEntity, "delTag", "user not allowed to delete protected tag") return } diff --git a/routers/private/hook_pre_receive.go b/routers/private/hook_pre_receive.go index 73fe9b886c..eb7bb2b480 100644 --- a/routers/private/hook_pre_receive.go +++ b/routers/private/hook_pre_receive.go @@ -8,7 +8,6 @@ import ( "net/http" "os" - "code.gitea.io/gitea/models" asymkey_model "code.gitea.io/gitea/models/asymkey" git_model "code.gitea.io/gitea/models/git" issues_model "code.gitea.io/gitea/models/issues" @@ -237,7 +236,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID string, r if len(globs) > 0 { _, err := pull_service.CheckFileProtection(gitRepo, branchName, oldCommitID, newCommitID, globs, 1, ctx.env) if err != nil { - if !models.IsErrFilePathProtected(err) { + if !pull_service.IsErrFilePathProtected(err) { log.Error("Unable to check file protection for commits from %s to %s in %-v: %v", oldCommitID, newCommitID, repo, err) ctx.JSON(http.StatusInternalServerError, private.Response{ Err: fmt.Sprintf("Unable to check file protection for commits from %s to %s: %v", oldCommitID, newCommitID, err), @@ -246,7 +245,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID string, r } changedProtectedfiles = true - protectedFilePath = err.(models.ErrFilePathProtected).Path + protectedFilePath = err.(pull_service.ErrFilePathProtected).Path } } @@ -374,7 +373,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID string, r // Check all status checks and reviews are ok if err := pull_service.CheckPullBranchProtections(ctx, pr, true); err != nil { - if models.IsErrDisallowedToMerge(err) { + if pull_service.IsErrDisallowedToMerge(err) { log.Warn("Forbidden: User %d is not allowed push to protected branch %s in %-v and pr #%d is not ready to be merged: %s", ctx.opts.UserID, branchName, repo, pr.Index, err.Error()) ctx.JSON(http.StatusForbidden, private.Response{ UserMsg: fmt.Sprintf("Not allowed to push to protected branch %s and pr #%d is not ready to be merged: %s", branchName, ctx.opts.PullRequestID, err.Error()), diff --git a/routers/web/admin/users.go b/routers/web/admin/users.go index a6b0b5c78b..1eaa37bfbd 100644 --- a/routers/web/admin/users.go +++ b/routers/web/admin/users.go @@ -11,10 +11,10 @@ import ( "strconv" "strings" - "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/db" org_model "code.gitea.io/gitea/models/organization" + packages_model "code.gitea.io/gitea/models/packages" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/auth/password" @@ -446,7 +446,7 @@ func EditUserPost(ctx *context.Context) { } if err := user_service.UpdateUser(ctx, u, opts); err != nil { - if models.IsErrDeleteLastAdminUser(err) { + if user_model.IsErrDeleteLastAdminUser(err) { ctx.RenderWithErr(ctx.Tr("auth.last_admin"), tplUserEdit, &form) } else { ctx.ServerError("UpdateUser", err) @@ -501,16 +501,16 @@ func DeleteUser(ctx *context.Context) { if err = user_service.DeleteUser(ctx, u, ctx.FormBool("purge")); err != nil { switch { - case models.IsErrUserOwnRepos(err): + case repo_model.IsErrUserOwnRepos(err): ctx.Flash.Error(ctx.Tr("admin.users.still_own_repo")) ctx.Redirect(setting.AppSubURL + "/-/admin/users/" + url.PathEscape(ctx.PathParam(":userid"))) - case models.IsErrUserHasOrgs(err): + case org_model.IsErrUserHasOrgs(err): ctx.Flash.Error(ctx.Tr("admin.users.still_has_org")) ctx.Redirect(setting.AppSubURL + "/-/admin/users/" + url.PathEscape(ctx.PathParam(":userid"))) - case models.IsErrUserOwnPackages(err): + case packages_model.IsErrUserOwnPackages(err): ctx.Flash.Error(ctx.Tr("admin.users.still_own_packages")) ctx.Redirect(setting.AppSubURL + "/-/admin/users/" + url.PathEscape(ctx.PathParam(":userid"))) - case models.IsErrDeleteLastAdminUser(err): + case user_model.IsErrDeleteLastAdminUser(err): ctx.Flash.Error(ctx.Tr("auth.last_admin")) ctx.Redirect(setting.AppSubURL + "/-/admin/users/" + url.PathEscape(ctx.PathParam(":userid"))) default: diff --git a/routers/web/org/setting.go b/routers/web/org/setting.go index 494ada4323..551019c717 100644 --- a/routers/web/org/setting.go +++ b/routers/web/org/setting.go @@ -8,8 +8,8 @@ import ( "net/http" "net/url" - "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" + packages_model "code.gitea.io/gitea/models/packages" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/models/webhook" @@ -178,10 +178,10 @@ func SettingsDelete(ctx *context.Context) { } if err := org_service.DeleteOrganization(ctx, ctx.Org.Organization, false); err != nil { - if models.IsErrUserOwnRepos(err) { + if repo_model.IsErrUserOwnRepos(err) { ctx.Flash.Error(ctx.Tr("form.org_still_own_repo")) ctx.Redirect(ctx.Org.OrgLink + "/settings/delete") - } else if models.IsErrUserOwnPackages(err) { + } else if packages_model.IsErrUserOwnPackages(err) { ctx.Flash.Error(ctx.Tr("form.org_still_own_packages")) ctx.Redirect(ctx.Org.OrgLink + "/settings/delete") } else { diff --git a/routers/web/repo/branch.go b/routers/web/repo/branch.go index c918cd7a72..3e1c6fc61c 100644 --- a/routers/web/repo/branch.go +++ b/routers/web/repo/branch.go @@ -11,7 +11,6 @@ import ( "net/url" "strings" - "code.gitea.io/gitea/models" git_model "code.gitea.io/gitea/models/git" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" @@ -26,6 +25,7 @@ import ( "code.gitea.io/gitea/routers/utils" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" + pull_service "code.gitea.io/gitea/services/pull" release_service "code.gitea.io/gitea/services/release" repo_service "code.gitea.io/gitea/services/repository" ) @@ -203,14 +203,14 @@ func CreateBranch(ctx *context.Context) { err = repo_service.CreateNewBranchFromCommit(ctx, ctx.Doer, ctx.Repo.Repository, ctx.Repo.GitRepo, ctx.Repo.CommitID, form.NewBranchName) } if err != nil { - if models.IsErrProtectedTagName(err) { + if release_service.IsErrProtectedTagName(err) { ctx.Flash.Error(ctx.Tr("repo.release.tag_name_protected")) ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL()) return } - if models.IsErrTagAlreadyExists(err) { - e := err.(models.ErrTagAlreadyExists) + if release_service.IsErrTagAlreadyExists(err) { + e := err.(release_service.ErrTagAlreadyExists) ctx.Flash.Error(ctx.Tr("repo.branch.tag_collision", e.TagName)) ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL()) return @@ -267,7 +267,7 @@ func MergeUpstream(ctx *context.Context) { if errors.Is(err, util.ErrNotExist) { ctx.JSONError(ctx.Tr("error.not_found")) return - } else if models.IsErrMergeConflicts(err) { + } else if pull_service.IsErrMergeConflicts(err) { ctx.JSONError(ctx.Tr("repo.pulls.merge_conflict")) return } diff --git a/routers/web/repo/cherry_pick.go b/routers/web/repo/cherry_pick.go index 61aff78d49..71671ec628 100644 --- a/routers/web/repo/cherry_pick.go +++ b/routers/web/repo/cherry_pick.go @@ -8,7 +8,6 @@ import ( "errors" "strings" - "code.gitea.io/gitea/models" git_model "code.gitea.io/gitea/models/git" "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/base" @@ -131,7 +130,7 @@ func CherryPickPost(ctx *context.Context) { ctx.Data["Err_NewBranchName"] = true ctx.RenderWithErr(ctx.Tr("repo.editor.branch_already_exists", branchErr.BranchName), tplCherryPick, &form) return - } else if models.IsErrCommitIDDoesNotMatch(err) { + } else if files.IsErrCommitIDDoesNotMatch(err) { ctx.RenderWithErr(ctx.Tr("repo.editor.file_changed_while_editing", ctx.Repo.RepoLink+"/compare/"+form.LastCommit+"..."+ctx.Repo.CommitID), tplPatchFile, &form) return } @@ -168,7 +167,7 @@ func CherryPickPost(ctx *context.Context) { ctx.Data["Err_NewBranchName"] = true ctx.RenderWithErr(ctx.Tr("repo.editor.branch_already_exists", branchErr.BranchName), tplCherryPick, &form) return - } else if models.IsErrCommitIDDoesNotMatch(err) { + } else if files.IsErrCommitIDDoesNotMatch(err) { ctx.RenderWithErr(ctx.Tr("repo.editor.file_changed_while_editing", ctx.Repo.RepoLink+"/compare/"+form.LastCommit+"..."+ctx.Repo.CommitID), tplPatchFile, &form) return } diff --git a/routers/web/repo/editor.go b/routers/web/repo/editor.go index 9396115b0d..afc69bffdf 100644 --- a/routers/web/repo/editor.go +++ b/routers/web/repo/editor.go @@ -10,7 +10,6 @@ import ( "path" "strings" - "code.gitea.io/gitea/models" git_model "code.gitea.io/gitea/models/git" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" @@ -303,12 +302,12 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b } else if git_model.IsErrLFSFileLocked(err) { ctx.Data["Err_TreePath"] = true ctx.RenderWithErr(ctx.Tr("repo.editor.upload_file_is_locked", err.(git_model.ErrLFSFileLocked).Path, err.(git_model.ErrLFSFileLocked).UserName), tplEditFile, &form) - } else if models.IsErrFilenameInvalid(err) { + } else if files_service.IsErrFilenameInvalid(err) { ctx.Data["Err_TreePath"] = true ctx.RenderWithErr(ctx.Tr("repo.editor.filename_is_invalid", form.TreePath), tplEditFile, &form) - } else if models.IsErrFilePathInvalid(err) { + } else if files_service.IsErrFilePathInvalid(err) { ctx.Data["Err_TreePath"] = true - if fileErr, ok := err.(models.ErrFilePathInvalid); ok { + if fileErr, ok := err.(files_service.ErrFilePathInvalid); ok { switch fileErr.Type { case git.EntryModeSymlink: ctx.RenderWithErr(ctx.Tr("repo.editor.file_is_a_symlink", fileErr.Path), tplEditFile, &form) @@ -322,7 +321,7 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b } else { ctx.Error(http.StatusInternalServerError, err.Error()) } - } else if models.IsErrRepoFileAlreadyExists(err) { + } else if files_service.IsErrRepoFileAlreadyExists(err) { ctx.Data["Err_TreePath"] = true ctx.RenderWithErr(ctx.Tr("repo.editor.file_already_exists", form.TreePath), tplEditFile, &form) } else if git.IsErrBranchNotExist(err) { @@ -340,7 +339,7 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b } else { ctx.Error(http.StatusInternalServerError, err.Error()) } - } else if models.IsErrCommitIDDoesNotMatch(err) { + } else if files_service.IsErrCommitIDDoesNotMatch(err) { ctx.RenderWithErr(ctx.Tr("repo.editor.commit_id_not_matching"), tplEditFile, &form) } else if git.IsErrPushOutOfDate(err) { ctx.RenderWithErr(ctx.Tr("repo.editor.push_out_of_date"), tplEditFile, &form) @@ -506,14 +505,14 @@ func DeleteFilePost(ctx *context.Context) { Signoff: form.Signoff, }); err != nil { // This is where we handle all the errors thrown by repofiles.DeleteRepoFile - if git.IsErrNotExist(err) || models.IsErrRepoFileDoesNotExist(err) { + if git.IsErrNotExist(err) || files_service.IsErrRepoFileDoesNotExist(err) { ctx.RenderWithErr(ctx.Tr("repo.editor.file_deleting_no_longer_exists", ctx.Repo.TreePath), tplDeleteFile, &form) - } else if models.IsErrFilenameInvalid(err) { + } else if files_service.IsErrFilenameInvalid(err) { ctx.Data["Err_TreePath"] = true ctx.RenderWithErr(ctx.Tr("repo.editor.filename_is_invalid", ctx.Repo.TreePath), tplDeleteFile, &form) - } else if models.IsErrFilePathInvalid(err) { + } else if files_service.IsErrFilePathInvalid(err) { ctx.Data["Err_TreePath"] = true - if fileErr, ok := err.(models.ErrFilePathInvalid); ok { + if fileErr, ok := err.(files_service.ErrFilePathInvalid); ok { switch fileErr.Type { case git.EntryModeSymlink: ctx.RenderWithErr(ctx.Tr("repo.editor.file_is_a_symlink", fileErr.Path), tplDeleteFile, &form) @@ -541,7 +540,7 @@ func DeleteFilePost(ctx *context.Context) { } else { ctx.Error(http.StatusInternalServerError, err.Error()) } - } else if models.IsErrCommitIDDoesNotMatch(err) || git.IsErrPushOutOfDate(err) { + } else if files_service.IsErrCommitIDDoesNotMatch(err) || git.IsErrPushOutOfDate(err) { ctx.RenderWithErr(ctx.Tr("repo.editor.file_changed_while_deleting", ctx.Repo.RepoLink+"/compare/"+util.PathEscapeSegments(form.LastCommit)+"..."+util.PathEscapeSegments(ctx.Repo.CommitID)), tplDeleteFile, &form) } else if git.IsErrPushRejected(err) { errPushRej := err.(*git.ErrPushRejected) @@ -715,12 +714,12 @@ func UploadFilePost(ctx *context.Context) { if git_model.IsErrLFSFileLocked(err) { ctx.Data["Err_TreePath"] = true ctx.RenderWithErr(ctx.Tr("repo.editor.upload_file_is_locked", err.(git_model.ErrLFSFileLocked).Path, err.(git_model.ErrLFSFileLocked).UserName), tplUploadFile, &form) - } else if models.IsErrFilenameInvalid(err) { + } else if files_service.IsErrFilenameInvalid(err) { ctx.Data["Err_TreePath"] = true ctx.RenderWithErr(ctx.Tr("repo.editor.filename_is_invalid", form.TreePath), tplUploadFile, &form) - } else if models.IsErrFilePathInvalid(err) { + } else if files_service.IsErrFilePathInvalid(err) { ctx.Data["Err_TreePath"] = true - fileErr := err.(models.ErrFilePathInvalid) + fileErr := err.(files_service.ErrFilePathInvalid) switch fileErr.Type { case git.EntryModeSymlink: ctx.RenderWithErr(ctx.Tr("repo.editor.file_is_a_symlink", fileErr.Path), tplUploadFile, &form) @@ -731,7 +730,7 @@ func UploadFilePost(ctx *context.Context) { default: ctx.Error(http.StatusInternalServerError, err.Error()) } - } else if models.IsErrRepoFileAlreadyExists(err) { + } else if files_service.IsErrRepoFileAlreadyExists(err) { ctx.Data["Err_TreePath"] = true ctx.RenderWithErr(ctx.Tr("repo.editor.file_already_exists", form.TreePath), tplUploadFile, &form) } else if git.IsErrBranchNotExist(err) { diff --git a/routers/web/repo/githttp.go b/routers/web/repo/githttp.go index 58a2bdbab1..a8a7a4bd79 100644 --- a/routers/web/repo/githttp.go +++ b/routers/web/repo/githttp.go @@ -458,7 +458,6 @@ func serviceRPC(ctx *context.Context, h *serviceHandler, service string) { var stderr bytes.Buffer cmd.AddArguments("--stateless-rpc").AddDynamicArguments(h.getRepoDir()) - cmd.SetDescription(fmt.Sprintf("%s %s %s [repo_path: %s]", git.GitExecutable, service, "--stateless-rpc", h.getRepoDir())) if err := cmd.Run(&git.RunOpts{ Dir: h.getRepoDir(), Env: append(os.Environ(), h.environ...), diff --git a/routers/web/repo/migrate.go b/routers/web/repo/migrate.go index 3eaf05f383..a2c257940e 100644 --- a/routers/web/repo/migrate.go +++ b/routers/web/repo/migrate.go @@ -9,12 +9,12 @@ import ( "net/url" "strings" - "code.gitea.io/gitea/models" admin_model "code.gitea.io/gitea/models/admin" "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/lfs" "code.gitea.io/gitea/modules/log" @@ -123,8 +123,8 @@ func handleMigrateError(ctx *context.Context, owner *user_model.User, err error, } func handleMigrateRemoteAddrError(ctx *context.Context, err error, tpl base.TplName, form *forms.MigrateRepoForm) { - if models.IsErrInvalidCloneAddr(err) { - addrErr := err.(*models.ErrInvalidCloneAddr) + if git.IsErrInvalidCloneAddr(err) { + addrErr := err.(*git.ErrInvalidCloneAddr) switch { case addrErr.IsProtocolInvalid: ctx.RenderWithErr(ctx.Tr("repo.mirror_address_protocol_invalid"), tpl, form) @@ -176,7 +176,7 @@ func MigratePost(ctx *context.Context) { return } - remoteAddr, err := forms.ParseRemoteAddr(form.CloneAddr, form.AuthUsername, form.AuthPassword) + remoteAddr, err := git.ParseRemoteAddr(form.CloneAddr, form.AuthUsername, form.AuthPassword) if err == nil { err = migrations.IsMigrateURLAllowed(remoteAddr, ctx.Doer) } diff --git a/routers/web/repo/patch.go b/routers/web/repo/patch.go index 0dee02dd9c..5906ec6f3d 100644 --- a/routers/web/repo/patch.go +++ b/routers/web/repo/patch.go @@ -6,7 +6,6 @@ package repo import ( "strings" - "code.gitea.io/gitea/models" git_model "code.gitea.io/gitea/models/git" "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/base" @@ -101,7 +100,7 @@ func NewDiffPatchPost(ctx *context.Context) { ctx.Data["Err_NewBranchName"] = true ctx.RenderWithErr(ctx.Tr("repo.editor.branch_already_exists", branchErr.BranchName), tplEditFile, &form) return - } else if models.IsErrCommitIDDoesNotMatch(err) { + } else if files.IsErrCommitIDDoesNotMatch(err) { ctx.RenderWithErr(ctx.Tr("repo.editor.file_changed_while_editing", ctx.Repo.RepoLink+"/compare/"+form.LastCommit+"..."+ctx.Repo.CommitID), tplPatchFile, &form) return } diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index 9694ae845b..7cc7bf58d2 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -14,7 +14,6 @@ import ( "strings" "time" - "code.gitea.io/gitea/models" activities_model "code.gitea.io/gitea/models/activities" "code.gitea.io/gitea/models/db" git_model "code.gitea.io/gitea/models/git" @@ -701,9 +700,6 @@ func viewPullFiles(ctx *context.Context, specifiedStartCommit, specifiedEndCommi if ctx.Written() { return - } else if prInfo == nil { - ctx.NotFound("ViewPullFiles", nil) - return } headCommitID, err := gitRepo.GetRefCommitID(pull.GetGitRefName()) @@ -971,8 +967,8 @@ func UpdatePullRequest(ctx *context.Context) { message := fmt.Sprintf("Merge branch '%s' into %s", issue.PullRequest.BaseBranch, issue.PullRequest.HeadBranch) if err = pull_service.Update(ctx, issue.PullRequest, ctx.Doer, message, rebase); err != nil { - if models.IsErrMergeConflicts(err) { - conflictError := err.(models.ErrMergeConflicts) + if pull_service.IsErrMergeConflicts(err) { + conflictError := err.(pull_service.ErrMergeConflicts) flashError, err := ctx.RenderToHTML(tplAlertDetails, map[string]any{ "Message": ctx.Tr("repo.pulls.merge_conflict"), "Summary": ctx.Tr("repo.pulls.merge_conflict_summary"), @@ -985,8 +981,8 @@ func UpdatePullRequest(ctx *context.Context) { ctx.Flash.Error(flashError) ctx.Redirect(issue.Link()) return - } else if models.IsErrRebaseConflicts(err) { - conflictError := err.(models.ErrRebaseConflicts) + } else if pull_service.IsErrRebaseConflicts(err) { + conflictError := err.(pull_service.ErrRebaseConflicts) flashError, err := ctx.RenderToHTML(tplAlertDetails, map[string]any{ "Message": ctx.Tr("repo.pulls.rebase_conflict", utils.SanitizeFlashErrorString(conflictError.CommitSHA)), "Summary": ctx.Tr("repo.pulls.rebase_conflict_summary"), @@ -1050,7 +1046,7 @@ func MergePullRequest(ctx *context.Context) { ctx.JSONError(ctx.Tr("repo.pulls.no_merge_wip")) case errors.Is(err, pull_service.ErrNotMergeableState): ctx.JSONError(ctx.Tr("repo.pulls.no_merge_not_ready")) - case models.IsErrDisallowedToMerge(err): + case pull_service.IsErrDisallowedToMerge(err): ctx.JSONError(ctx.Tr("repo.pulls.no_merge_not_ready")) case asymkey_service.IsErrWontSign(err): ctx.JSONError(err.Error()) // has no translation ... @@ -1067,7 +1063,7 @@ func MergePullRequest(ctx *context.Context) { if manuallyMerged { if err := pull_service.MergedManually(ctx, pr, ctx.Doer, ctx.Repo.GitRepo, form.MergeCommitID); err != nil { switch { - case models.IsErrInvalidMergeStyle(err): + case pull_service.IsErrInvalidMergeStyle(err): ctx.JSONError(ctx.Tr("repo.pulls.invalid_merge_option")) case strings.Contains(err.Error(), "Wrong commit ID"): ctx.JSONError(ctx.Tr("repo.pulls.wrong_commit_id")) @@ -1114,10 +1110,10 @@ func MergePullRequest(ctx *context.Context) { } if err := pull_service.Merge(ctx, pr, ctx.Doer, ctx.Repo.GitRepo, repo_model.MergeStyle(form.Do), form.HeadCommitID, message, false); err != nil { - if models.IsErrInvalidMergeStyle(err) { + if pull_service.IsErrInvalidMergeStyle(err) { ctx.JSONError(ctx.Tr("repo.pulls.invalid_merge_option")) - } else if models.IsErrMergeConflicts(err) { - conflictError := err.(models.ErrMergeConflicts) + } else if pull_service.IsErrMergeConflicts(err) { + conflictError := err.(pull_service.ErrMergeConflicts) flashError, err := ctx.RenderToHTML(tplAlertDetails, map[string]any{ "Message": ctx.Tr("repo.editor.merge_conflict"), "Summary": ctx.Tr("repo.editor.merge_conflict_summary"), @@ -1129,8 +1125,8 @@ func MergePullRequest(ctx *context.Context) { } ctx.Flash.Error(flashError) ctx.JSONRedirect(issue.Link()) - } else if models.IsErrRebaseConflicts(err) { - conflictError := err.(models.ErrRebaseConflicts) + } else if pull_service.IsErrRebaseConflicts(err) { + conflictError := err.(pull_service.ErrRebaseConflicts) flashError, err := ctx.RenderToHTML(tplAlertDetails, map[string]any{ "Message": ctx.Tr("repo.pulls.rebase_conflict", utils.SanitizeFlashErrorString(conflictError.CommitSHA)), "Summary": ctx.Tr("repo.pulls.rebase_conflict_summary"), @@ -1142,7 +1138,7 @@ func MergePullRequest(ctx *context.Context) { } ctx.Flash.Error(flashError) ctx.JSONRedirect(issue.Link()) - } else if models.IsErrMergeUnrelatedHistories(err) { + } else if pull_service.IsErrMergeUnrelatedHistories(err) { log.Debug("MergeUnrelatedHistories error: %v", err) ctx.Flash.Error(ctx.Tr("repo.pulls.unrelated_histories")) ctx.JSONRedirect(issue.Link()) @@ -1150,7 +1146,7 @@ func MergePullRequest(ctx *context.Context) { log.Debug("MergePushOutOfDate error: %v", err) ctx.Flash.Error(ctx.Tr("repo.pulls.merge_out_of_date")) ctx.JSONRedirect(issue.Link()) - } else if models.IsErrSHADoesNotMatch(err) { + } else if pull_service.IsErrSHADoesNotMatch(err) { log.Debug("MergeHeadOutOfDate error: %v", err) ctx.Flash.Error(ctx.Tr("repo.pulls.head_out_of_date")) ctx.JSONRedirect(issue.Link()) @@ -1609,7 +1605,7 @@ func UpdatePullRequestTarget(ctx *context.Context) { "error": err.Error(), "user_error": errorMessage, }) - } else if models.IsErrPullRequestHasMerged(err) { + } else if pull_service.IsErrPullRequestHasMerged(err) { errorMessage := ctx.Tr("repo.pulls.has_merged") ctx.Flash.Error(errorMessage) diff --git a/routers/web/repo/release.go b/routers/web/repo/release.go index b3a91a6070..5c5191fc3b 100644 --- a/routers/web/repo/release.go +++ b/routers/web/repo/release.go @@ -10,7 +10,6 @@ import ( "net/http" "strings" - "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" git_model "code.gitea.io/gitea/models/git" "code.gitea.io/gitea/models/renderhelper" @@ -30,7 +29,7 @@ import ( "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/context/upload" "code.gitea.io/gitea/services/forms" - releaseservice "code.gitea.io/gitea/services/release" + release_service "code.gitea.io/gitea/services/release" ) const ( @@ -432,27 +431,27 @@ func NewReleasePost(ctx *context.Context) { } if len(form.TagOnly) > 0 { - if err = releaseservice.CreateNewTag(ctx, ctx.Doer, ctx.Repo.Repository, form.Target, form.TagName, msg); err != nil { - if models.IsErrTagAlreadyExists(err) { - e := err.(models.ErrTagAlreadyExists) + if err = release_service.CreateNewTag(ctx, ctx.Doer, ctx.Repo.Repository, form.Target, form.TagName, msg); err != nil { + if release_service.IsErrTagAlreadyExists(err) { + e := err.(release_service.ErrTagAlreadyExists) ctx.Flash.Error(ctx.Tr("repo.branch.tag_collision", e.TagName)) ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL()) return } - if models.IsErrInvalidTagName(err) { + if release_service.IsErrInvalidTagName(err) { ctx.Flash.Error(ctx.Tr("repo.release.tag_name_invalid")) ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL()) return } - if models.IsErrProtectedTagName(err) { + if release_service.IsErrProtectedTagName(err) { ctx.Flash.Error(ctx.Tr("repo.release.tag_name_protected")) ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL()) return } - ctx.ServerError("releaseservice.CreateNewTag", err) + ctx.ServerError("release_service.CreateNewTag", err) return } @@ -475,14 +474,14 @@ func NewReleasePost(ctx *context.Context) { IsTag: false, } - if err = releaseservice.CreateRelease(ctx.Repo.GitRepo, rel, attachmentUUIDs, msg); err != nil { + if err = release_service.CreateRelease(ctx.Repo.GitRepo, rel, attachmentUUIDs, msg); err != nil { ctx.Data["Err_TagName"] = true switch { case repo_model.IsErrReleaseAlreadyExist(err): ctx.RenderWithErr(ctx.Tr("repo.release.tag_name_already_exist"), tplReleaseNew, &form) - case models.IsErrInvalidTagName(err): + case release_service.IsErrInvalidTagName(err): ctx.RenderWithErr(ctx.Tr("repo.release.tag_name_invalid"), tplReleaseNew, &form) - case models.IsErrProtectedTagName(err): + case release_service.IsErrProtectedTagName(err): ctx.RenderWithErr(ctx.Tr("repo.release.tag_name_protected"), tplReleaseNew, &form) default: ctx.ServerError("CreateRelease", err) @@ -504,7 +503,7 @@ func NewReleasePost(ctx *context.Context) { rel.PublisherID = ctx.Doer.ID rel.IsTag = false - if err = releaseservice.UpdateRelease(ctx, ctx.Doer, ctx.Repo.GitRepo, rel, attachmentUUIDs, nil, nil); err != nil { + if err = release_service.UpdateRelease(ctx, ctx.Doer, ctx.Repo.GitRepo, rel, attachmentUUIDs, nil, nil); err != nil { ctx.Data["Err_TagName"] = true ctx.ServerError("UpdateRelease", err) return @@ -610,7 +609,7 @@ func EditReleasePost(ctx *context.Context) { rel.Note = form.Content rel.IsDraft = len(form.Draft) > 0 rel.IsPrerelease = form.Prerelease - if err = releaseservice.UpdateRelease(ctx, ctx.Doer, ctx.Repo.GitRepo, + if err = release_service.UpdateRelease(ctx, ctx.Doer, ctx.Repo.GitRepo, rel, addAttachmentUUIDs, delAttachmentUUIDs, editAttachments); err != nil { ctx.ServerError("UpdateRelease", err) return @@ -649,8 +648,8 @@ func deleteReleaseOrTag(ctx *context.Context, isDelTag bool) { return } - if err := releaseservice.DeleteReleaseByID(ctx, ctx.Repo.Repository, rel, ctx.Doer, isDelTag); err != nil { - if models.IsErrProtectedTagName(err) { + if err := release_service.DeleteReleaseByID(ctx, ctx.Repo.Repository, rel, ctx.Doer, isDelTag); err != nil { + if release_service.IsErrProtectedTagName(err) { ctx.Flash.Error(ctx.Tr("repo.release.tag_name_protected")) } else { ctx.Flash.Error("DeleteReleaseByID: " + err.Error()) diff --git a/routers/web/repo/setting/setting.go b/routers/web/repo/setting/setting.go index f2169d8a79..1c7f9441f8 100644 --- a/routers/web/repo/setting/setting.go +++ b/routers/web/repo/setting/setting.go @@ -11,7 +11,6 @@ import ( "strings" "time" - "code.gitea.io/gitea/models" actions_model "code.gitea.io/gitea/models/actions" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" @@ -223,7 +222,7 @@ func SettingsPost(ctx *context.Context) { form.MirrorPassword, _ = u.User.Password() } - address, err := forms.ParseRemoteAddr(form.MirrorAddress, form.MirrorUsername, form.MirrorPassword) + address, err := git.ParseRemoteAddr(form.MirrorAddress, form.MirrorUsername, form.MirrorPassword) if err == nil { err = migrations.IsMigrateURLAllowed(address, ctx.Doer) } @@ -385,7 +384,7 @@ func SettingsPost(ctx *context.Context) { return } - address, err := forms.ParseRemoteAddr(form.PushMirrorAddress, form.PushMirrorUsername, form.PushMirrorPassword) + address, err := git.ParseRemoteAddr(form.PushMirrorAddress, form.PushMirrorUsername, form.PushMirrorPassword) if err == nil { err = migrations.IsMigrateURLAllowed(address, ctx.Doer) } @@ -980,8 +979,8 @@ func SettingsPost(ctx *context.Context) { } func handleSettingRemoteAddrError(ctx *context.Context, err error, form *forms.RepoSettingForm) { - if models.IsErrInvalidCloneAddr(err) { - addrErr := err.(*models.ErrInvalidCloneAddr) + if git.IsErrInvalidCloneAddr(err) { + addrErr := err.(*git.ErrInvalidCloneAddr) switch { case addrErr.IsProtocolInvalid: ctx.RenderWithErr(ctx.Tr("repo.mirror_address_protocol_invalid"), tplSettingsOptions, form) diff --git a/routers/web/user/setting/account.go b/routers/web/user/setting/account.go index 7f2dece416..00fe02c886 100644 --- a/routers/web/user/setting/account.go +++ b/routers/web/user/setting/account.go @@ -10,7 +10,9 @@ import ( "net/http" "time" - "code.gitea.io/gitea/models" + org_model "code.gitea.io/gitea/models/organization" + packages_model "code.gitea.io/gitea/models/packages" + repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/auth/password" "code.gitea.io/gitea/modules/base" @@ -301,16 +303,16 @@ func DeleteAccount(ctx *context.Context) { if err := user.DeleteUser(ctx, ctx.Doer, false); err != nil { switch { - case models.IsErrUserOwnRepos(err): + case repo_model.IsErrUserOwnRepos(err): ctx.Flash.Error(ctx.Tr("form.still_own_repo")) ctx.Redirect(setting.AppSubURL + "/user/settings/account") - case models.IsErrUserHasOrgs(err): + case org_model.IsErrUserHasOrgs(err): ctx.Flash.Error(ctx.Tr("form.still_has_org")) ctx.Redirect(setting.AppSubURL + "/user/settings/account") - case models.IsErrUserOwnPackages(err): + case packages_model.IsErrUserOwnPackages(err): ctx.Flash.Error(ctx.Tr("form.still_own_packages")) ctx.Redirect(setting.AppSubURL + "/user/settings/account") - case models.IsErrDeleteLastAdminUser(err): + case user_model.IsErrDeleteLastAdminUser(err): ctx.Flash.Error(ctx.Tr("auth.last_admin")) ctx.Redirect(setting.AppSubURL + "/user/settings/account") default: diff --git a/routers/web/web.go b/routers/web/web.go index 72ee47bb4c..aa37d4dc10 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -1020,14 +1020,15 @@ func registerRoutes(m *web.Router) { m.Get("/new", org.RenderNewProject) m.Post("/new", web.Bind(forms.CreateProjectForm{}), org.NewProjectPost) m.Group("/{id}", func() { - m.Post("", web.Bind(forms.EditProjectColumnForm{}), org.AddColumnToProjectPost) - m.Post("/move", project.MoveColumns) m.Post("/delete", org.DeleteProject) m.Get("/edit", org.RenderEditProject) m.Post("/edit", web.Bind(forms.CreateProjectForm{}), org.EditProjectPost) m.Post("/{action:open|close}", org.ChangeProjectStatus) + // TODO: improper name. Others are "delete project", "edit project", but this one is "move columns" + m.Post("/move", project.MoveColumns) + m.Post("/columns/new", web.Bind(forms.EditProjectColumnForm{}), org.AddColumnToProjectPost) m.Group("/{columnID}", func() { m.Put("", web.Bind(forms.EditProjectColumnForm{}), org.EditProjectColumn) m.Delete("", org.DeleteProjectColumn) @@ -1387,14 +1388,15 @@ func registerRoutes(m *web.Router) { m.Get("/new", repo.RenderNewProject) m.Post("/new", web.Bind(forms.CreateProjectForm{}), repo.NewProjectPost) m.Group("/{id}", func() { - m.Post("", web.Bind(forms.EditProjectColumnForm{}), repo.AddColumnToProjectPost) - m.Post("/move", project.MoveColumns) m.Post("/delete", repo.DeleteProject) m.Get("/edit", repo.RenderEditProject) m.Post("/edit", web.Bind(forms.CreateProjectForm{}), repo.EditProjectPost) m.Post("/{action:open|close}", repo.ChangeProjectStatus) + // TODO: improper name. Others are "delete project", "edit project", but this one is "move columns" + m.Post("/move", project.MoveColumns) + m.Post("/columns/new", web.Bind(forms.EditProjectColumnForm{}), repo.AddColumnToProjectPost) m.Group("/{columnID}", func() { m.Put("", web.Bind(forms.EditProjectColumnForm{}), repo.EditProjectColumn) m.Delete("", repo.DeleteProjectColumn) diff --git a/services/forms/repo_form.go b/services/forms/repo_form.go index 7647c74e46..b14171787e 100644 --- a/services/forms/repo_form.go +++ b/services/forms/repo_form.go @@ -6,10 +6,8 @@ package forms import ( "net/http" - "net/url" "strings" - "code.gitea.io/gitea/models" issues_model "code.gitea.io/gitea/models/issues" project_model "code.gitea.io/gitea/models/project" "code.gitea.io/gitea/modules/setting" @@ -90,27 +88,6 @@ func (f *MigrateRepoForm) Validate(req *http.Request, errs binding.Errors) bindi return middleware.Validate(errs, ctx.Data, f, ctx.Locale) } -// ParseRemoteAddr checks if given remote address is valid, -// and returns composed URL with needed username and password. -func ParseRemoteAddr(remoteAddr, authUsername, authPassword string) (string, error) { - remoteAddr = strings.TrimSpace(remoteAddr) - // Remote address can be HTTP/HTTPS/Git URL or local path. - if strings.HasPrefix(remoteAddr, "http://") || - strings.HasPrefix(remoteAddr, "https://") || - strings.HasPrefix(remoteAddr, "git://") { - u, err := url.Parse(remoteAddr) - if err != nil { - return "", &models.ErrInvalidCloneAddr{IsURLError: true, Host: remoteAddr} - } - if len(authUsername)+len(authPassword) > 0 { - u.User = url.UserPassword(authUsername, authPassword) - } - remoteAddr = u.String() - } - - return remoteAddr, nil -} - // RepoSettingForm form for changing repository settings type RepoSettingForm struct { RepoName string `binding:"Required;AlphaDashDot;MaxSize(100)"` diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index bb1722039e..0b5a855d42 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -1156,7 +1156,6 @@ func GetDiff(ctx context.Context, gitRepo *git.Repository, opts *DiffOptions, fi go func() { stderr := &bytes.Buffer{} - cmdDiff.SetDescription(fmt.Sprintf("GetDiffRange [repo_path: %s]", repoPath)) if err := cmdDiff.Run(&git.RunOpts{ Timeout: time.Duration(setting.Git.Timeout.Default) * time.Second, Dir: repoPath, diff --git a/services/migrations/migrate.go b/services/migrations/migrate.go index d0ad6d0139..51b22d6111 100644 --- a/services/migrations/migrate.go +++ b/services/migrations/migrate.go @@ -12,10 +12,10 @@ import ( "path/filepath" "strings" - "code.gitea.io/gitea/models" repo_model "code.gitea.io/gitea/models/repo" system_model "code.gitea.io/gitea/models/system" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/hostmatcher" "code.gitea.io/gitea/modules/log" base "code.gitea.io/gitea/modules/migration" @@ -43,16 +43,16 @@ func IsMigrateURLAllowed(remoteURL string, doer *user_model.User) error { // Remote address can be HTTP/HTTPS/Git URL or local path. u, err := url.Parse(remoteURL) if err != nil { - return &models.ErrInvalidCloneAddr{IsURLError: true, Host: remoteURL} + return &git.ErrInvalidCloneAddr{IsURLError: true, Host: remoteURL} } if u.Scheme == "file" || u.Scheme == "" { if !doer.CanImportLocal() { - return &models.ErrInvalidCloneAddr{Host: "", IsPermissionDenied: true, LocalPath: true} + return &git.ErrInvalidCloneAddr{Host: "", IsPermissionDenied: true, LocalPath: true} } isAbs := filepath.IsAbs(u.Host + u.Path) if !isAbs { - return &models.ErrInvalidCloneAddr{Host: "", IsInvalidPath: true, LocalPath: true} + return &git.ErrInvalidCloneAddr{Host: "", IsInvalidPath: true, LocalPath: true} } isDir, err := util.IsDir(u.Host + u.Path) if err != nil { @@ -60,18 +60,18 @@ func IsMigrateURLAllowed(remoteURL string, doer *user_model.User) error { return err } if !isDir { - return &models.ErrInvalidCloneAddr{Host: "", IsInvalidPath: true, LocalPath: true} + return &git.ErrInvalidCloneAddr{Host: "", IsInvalidPath: true, LocalPath: true} } return nil } if u.Scheme == "git" && u.Port() != "" && (strings.Contains(remoteURL, "%0d") || strings.Contains(remoteURL, "%0a")) { - return &models.ErrInvalidCloneAddr{Host: u.Host, IsURLError: true} + return &git.ErrInvalidCloneAddr{Host: u.Host, IsURLError: true} } if u.Opaque != "" || u.Scheme != "" && u.Scheme != "http" && u.Scheme != "https" && u.Scheme != "git" { - return &models.ErrInvalidCloneAddr{Host: u.Host, IsProtocolInvalid: true, IsPermissionDenied: true, IsURLError: true} + return &git.ErrInvalidCloneAddr{Host: u.Host, IsProtocolInvalid: true, IsPermissionDenied: true, IsURLError: true} } hostName, _, err := net.SplitHostPort(u.Host) @@ -95,12 +95,12 @@ func checkByAllowBlockList(hostName string, addrList []net.IP) error { } var blockedError error if blockList.MatchHostName(hostName) || ipBlocked { - blockedError = &models.ErrInvalidCloneAddr{Host: hostName, IsPermissionDenied: true} + blockedError = &git.ErrInvalidCloneAddr{Host: hostName, IsPermissionDenied: true} } // if we have an allow-list, check the allow-list before return to get the more accurate error if !allowList.IsEmpty() { if !allowList.MatchHostName(hostName) && !ipAllowed { - return &models.ErrInvalidCloneAddr{Host: hostName, IsPermissionDenied: true} + return &git.ErrInvalidCloneAddr{Host: hostName, IsPermissionDenied: true} } } // otherwise, we always follow the blocked list diff --git a/services/mirror/mirror_pull.go b/services/mirror/mirror_pull.go index a81fe6e9bd..22d380e8e6 100644 --- a/services/mirror/mirror_pull.go +++ b/services/mirror/mirror_pull.go @@ -46,11 +46,6 @@ func UpdateAddress(ctx context.Context, m *repo_model.Mirror, addr string) error } cmd := git.NewCommand(ctx, "remote", "add").AddDynamicArguments(remoteName).AddArguments("--mirror=fetch").AddDynamicArguments(addr) - if strings.Contains(addr, "://") && strings.Contains(addr, "@") { - cmd.SetDescription(fmt.Sprintf("remote add %s --mirror=fetch %s [repo_path: %s]", remoteName, util.SanitizeCredentialURLs(addr), repoPath)) - } else { - cmd.SetDescription(fmt.Sprintf("remote add %s --mirror=fetch %s [repo_path: %s]", remoteName, addr, repoPath)) - } _, _, err = cmd.RunStdString(&git.RunOpts{Dir: repoPath}) if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") { return err @@ -66,11 +61,6 @@ func UpdateAddress(ctx context.Context, m *repo_model.Mirror, addr string) error } cmd = git.NewCommand(ctx, "remote", "add").AddDynamicArguments(remoteName).AddArguments("--mirror=fetch").AddDynamicArguments(wikiRemotePath) - if strings.Contains(wikiRemotePath, "://") && strings.Contains(wikiRemotePath, "@") { - cmd.SetDescription(fmt.Sprintf("remote add %s --mirror=fetch %s [repo_path: %s]", remoteName, util.SanitizeCredentialURLs(wikiRemotePath), wikiPath)) - } else { - cmd.SetDescription(fmt.Sprintf("remote add %s --mirror=fetch %s [repo_path: %s]", remoteName, wikiRemotePath, wikiPath)) - } _, _, err = cmd.RunStdString(&git.RunOpts{Dir: wikiPath}) if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") { return err @@ -197,7 +187,6 @@ func pruneBrokenReferences(ctx context.Context, stderrBuilder.Reset() stdoutBuilder.Reset() pruneErr := git.NewCommand(ctx, "remote", "prune").AddDynamicArguments(m.GetRemoteName()). - SetDescription(fmt.Sprintf("Mirror.runSync %ssPrune references: %s ", wiki, m.Repo.FullName())). Run(&git.RunOpts{ Timeout: timeout, Dir: repoPath, @@ -248,15 +237,13 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo stdoutBuilder := strings.Builder{} stderrBuilder := strings.Builder{} - if err := cmd. - SetDescription(fmt.Sprintf("Mirror.runSync: %s", m.Repo.FullName())). - Run(&git.RunOpts{ - Timeout: timeout, - Dir: repoPath, - Env: envs, - Stdout: &stdoutBuilder, - Stderr: &stderrBuilder, - }); err != nil { + if err := cmd.Run(&git.RunOpts{ + Timeout: timeout, + Dir: repoPath, + Env: envs, + Stdout: &stdoutBuilder, + Stderr: &stderrBuilder, + }); err != nil { stdout := stdoutBuilder.String() stderr := stderrBuilder.String() @@ -275,14 +262,12 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo // Successful prune - reattempt mirror stderrBuilder.Reset() stdoutBuilder.Reset() - if err = cmd. - SetDescription(fmt.Sprintf("Mirror.runSync: %s", m.Repo.FullName())). - Run(&git.RunOpts{ - Timeout: timeout, - Dir: repoPath, - Stdout: &stdoutBuilder, - Stderr: &stderrBuilder, - }); err != nil { + if err = cmd.Run(&git.RunOpts{ + Timeout: timeout, + Dir: repoPath, + Stdout: &stdoutBuilder, + Stderr: &stderrBuilder, + }); err != nil { stdout := stdoutBuilder.String() stderr := stderrBuilder.String() @@ -346,7 +331,6 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo stderrBuilder.Reset() stdoutBuilder.Reset() if err := git.NewCommand(ctx, "remote", "update", "--prune").AddDynamicArguments(m.GetRemoteName()). - SetDescription(fmt.Sprintf("Mirror.runSync Wiki: %s ", m.Repo.FullName())). Run(&git.RunOpts{ Timeout: timeout, Dir: wikiPath, @@ -373,7 +357,6 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo stdoutBuilder.Reset() if err = git.NewCommand(ctx, "remote", "update", "--prune").AddDynamicArguments(m.GetRemoteName()). - SetDescription(fmt.Sprintf("Mirror.runSync Wiki: %s ", m.Repo.FullName())). Run(&git.RunOpts{ Timeout: timeout, Dir: wikiPath, diff --git a/services/mirror/mirror_push.go b/services/mirror/mirror_push.go index 21ba0afeff..02ff97b1f0 100644 --- a/services/mirror/mirror_push.go +++ b/services/mirror/mirror_push.go @@ -9,7 +9,6 @@ import ( "fmt" "io" "regexp" - "strings" "time" "code.gitea.io/gitea/models/db" @@ -31,11 +30,6 @@ var stripExitStatus = regexp.MustCompile(`exit status \d+ - `) func AddPushMirrorRemote(ctx context.Context, m *repo_model.PushMirror, addr string) error { addRemoteAndConfig := func(addr, path string) error { cmd := git.NewCommand(ctx, "remote", "add", "--mirror=push").AddDynamicArguments(m.RemoteName, addr) - if strings.Contains(addr, "://") && strings.Contains(addr, "@") { - cmd.SetDescription(fmt.Sprintf("remote add %s --mirror=push %s [repo_path: %s]", m.RemoteName, util.SanitizeCredentialURLs(addr), path)) - } else { - cmd.SetDescription(fmt.Sprintf("remote add %s --mirror=push %s [repo_path: %s]", m.RemoteName, addr, path)) - } if _, _, err := cmd.RunStdString(&git.RunOpts{Dir: path}); err != nil { return err } diff --git a/services/org/org.go b/services/org/org.go index 471e6fcaf1..3d30ae21a3 100644 --- a/services/org/org.go +++ b/services/org/org.go @@ -7,7 +7,6 @@ import ( "context" "fmt" - "code.gitea.io/gitea/models" actions_model "code.gitea.io/gitea/models/actions" "code.gitea.io/gitea/models/db" org_model "code.gitea.io/gitea/models/organization" @@ -67,14 +66,14 @@ func DeleteOrganization(ctx context.Context, org *org_model.Organization, purge if err != nil { return fmt.Errorf("GetRepositoryCount: %w", err) } else if count > 0 { - return models.ErrUserOwnRepos{UID: org.ID} + return repo_model.ErrUserOwnRepos{UID: org.ID} } // Check ownership of packages. if ownsPackages, err := packages_model.HasOwnerPackages(ctx, org.ID); err != nil { return fmt.Errorf("HasOwnerPackages: %w", err) } else if ownsPackages { - return models.ErrUserOwnPackages{UID: org.ID} + return packages_model.ErrUserOwnPackages{UID: org.ID} } if err := deleteOrganization(ctx, org); err != nil { diff --git a/services/org/org_test.go b/services/org/org_test.go index e7d2a18ea9..791404c5c8 100644 --- a/services/org/org_test.go +++ b/services/org/org_test.go @@ -6,9 +6,9 @@ package org import ( "testing" - "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -30,7 +30,7 @@ func TestDeleteOrganization(t *testing.T) { org = unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) err := DeleteOrganization(db.DefaultContext, org, false) assert.Error(t, err) - assert.True(t, models.IsErrUserOwnRepos(err)) + assert.True(t, repo_model.IsErrUserOwnRepos(err)) user := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 5}) assert.Error(t, DeleteOrganization(db.DefaultContext, user, false)) diff --git a/services/pull/check.go b/services/pull/check.go index 736be4611b..bffca394a8 100644 --- a/services/pull/check.go +++ b/services/pull/check.go @@ -11,7 +11,6 @@ import ( "strconv" "strings" - "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" git_model "code.gitea.io/gitea/models/git" issues_model "code.gitea.io/gitea/models/issues" @@ -36,7 +35,7 @@ var prPatchCheckerQueue *queue.WorkerPoolQueue[string] var ( ErrIsClosed = errors.New("pull is closed") - ErrUserNotAllowedToMerge = models.ErrDisallowedToMerge{} + ErrUserNotAllowedToMerge = ErrDisallowedToMerge{} ErrHasMerged = errors.New("has already been merged") ErrIsWorkInProgress = errors.New("work in progress PRs cannot be merged") ErrIsChecking = errors.New("cannot merge while conflict checking is in progress") @@ -106,7 +105,7 @@ func CheckPullMergeable(stdCtx context.Context, doer *user_model.User, perm *acc } if err := CheckPullBranchProtections(ctx, pr, false); err != nil { - if !models.IsErrDisallowedToMerge(err) { + if !IsErrDisallowedToMerge(err) { log.Error("Error whilst checking pull branch protection for %-v: %v", pr, err) return err } diff --git a/services/pull/merge.go b/services/pull/merge.go index a3fbe4f627..fba85f1e51 100644 --- a/services/pull/merge.go +++ b/services/pull/merge.go @@ -13,7 +13,6 @@ import ( "strconv" "strings" - "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" git_model "code.gitea.io/gitea/models/git" issues_model "code.gitea.io/gitea/models/issues" @@ -30,6 +29,7 @@ import ( repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" issue_service "code.gitea.io/gitea/services/issue" notify_service "code.gitea.io/gitea/services/notify" ) @@ -159,6 +159,27 @@ func GetDefaultMergeMessage(ctx context.Context, baseGitRepo *git.Repository, pr return getMergeMessage(ctx, baseGitRepo, pr, mergeStyle, nil) } +// ErrInvalidMergeStyle represents an error if merging with disabled merge strategy +type ErrInvalidMergeStyle struct { + ID int64 + Style repo_model.MergeStyle +} + +// IsErrInvalidMergeStyle checks if an error is a ErrInvalidMergeStyle. +func IsErrInvalidMergeStyle(err error) bool { + _, ok := err.(ErrInvalidMergeStyle) + return ok +} + +func (err ErrInvalidMergeStyle) Error() string { + return fmt.Sprintf("merge strategy is not allowed or is invalid [repo_id: %d, strategy: %s]", + err.ID, err.Style) +} + +func (err ErrInvalidMergeStyle) Unwrap() error { + return util.ErrInvalidArgument +} + // Merge merges pull request to base repository. // Caller should check PR is ready to be merged (review and status checks) func Merge(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.User, baseGitRepo *git.Repository, mergeStyle repo_model.MergeStyle, expectedHeadCommitID, message string, wasAutoMerged bool) error { @@ -179,7 +200,7 @@ func Merge(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.U // Check if merge style is correct and allowed if !prConfig.IsMergeStyleAllowed(mergeStyle) { - return models.ErrInvalidMergeStyle{ID: pr.BaseRepo.ID, Style: mergeStyle} + return ErrInvalidMergeStyle{ID: pr.BaseRepo.ID, Style: mergeStyle} } releaser, err := globallock.Lock(ctx, getPullWorkingLockKey(pr.ID)) @@ -283,7 +304,7 @@ func doMergeAndPush(ctx context.Context, pr *issues_model.PullRequest, doer *use return "", err } default: - return "", models.ErrInvalidMergeStyle{ID: pr.BaseRepo.ID, Style: mergeStyle} + return "", ErrInvalidMergeStyle{ID: pr.BaseRepo.ID, Style: mergeStyle} } // OK we should cache our current head and origin/headbranch @@ -374,13 +395,66 @@ func commitAndSignNoAuthor(ctx *mergeContext, message string) error { return nil } +// ErrMergeConflicts represents an error if merging fails with a conflict +type ErrMergeConflicts struct { + Style repo_model.MergeStyle + StdOut string + StdErr string + Err error +} + +// IsErrMergeConflicts checks if an error is a ErrMergeConflicts. +func IsErrMergeConflicts(err error) bool { + _, ok := err.(ErrMergeConflicts) + return ok +} + +func (err ErrMergeConflicts) Error() string { + return fmt.Sprintf("Merge Conflict Error: %v: %s\n%s", err.Err, err.StdErr, err.StdOut) +} + +// ErrMergeUnrelatedHistories represents an error if merging fails due to unrelated histories +type ErrMergeUnrelatedHistories struct { + Style repo_model.MergeStyle + StdOut string + StdErr string + Err error +} + +// IsErrMergeUnrelatedHistories checks if an error is a ErrMergeUnrelatedHistories. +func IsErrMergeUnrelatedHistories(err error) bool { + _, ok := err.(ErrMergeUnrelatedHistories) + return ok +} + +func (err ErrMergeUnrelatedHistories) Error() string { + return fmt.Sprintf("Merge UnrelatedHistories Error: %v: %s\n%s", err.Err, err.StdErr, err.StdOut) +} + +// ErrMergeDivergingFastForwardOnly represents an error if a fast-forward-only merge fails because the branches diverge +type ErrMergeDivergingFastForwardOnly struct { + StdOut string + StdErr string + Err error +} + +// IsErrMergeDivergingFastForwardOnly checks if an error is a ErrMergeDivergingFastForwardOnly. +func IsErrMergeDivergingFastForwardOnly(err error) bool { + _, ok := err.(ErrMergeDivergingFastForwardOnly) + return ok +} + +func (err ErrMergeDivergingFastForwardOnly) Error() string { + return fmt.Sprintf("Merge DivergingFastForwardOnly Error: %v: %s\n%s", err.Err, err.StdErr, err.StdOut) +} + func runMergeCommand(ctx *mergeContext, mergeStyle repo_model.MergeStyle, cmd *git.Command) error { if err := cmd.Run(ctx.RunOpts()); err != nil { // Merge will leave a MERGE_HEAD file in the .git folder if there is a conflict if _, statErr := os.Stat(filepath.Join(ctx.tmpBasePath, ".git", "MERGE_HEAD")); statErr == nil { // We have a merge conflict error log.Debug("MergeConflict %-v: %v\n%s\n%s", ctx.pr, err, ctx.outbuf.String(), ctx.errbuf.String()) - return models.ErrMergeConflicts{ + return ErrMergeConflicts{ Style: mergeStyle, StdOut: ctx.outbuf.String(), StdErr: ctx.errbuf.String(), @@ -388,7 +462,7 @@ func runMergeCommand(ctx *mergeContext, mergeStyle repo_model.MergeStyle, cmd *g } } else if strings.Contains(ctx.errbuf.String(), "refusing to merge unrelated histories") { log.Debug("MergeUnrelatedHistories %-v: %v\n%s\n%s", ctx.pr, err, ctx.outbuf.String(), ctx.errbuf.String()) - return models.ErrMergeUnrelatedHistories{ + return ErrMergeUnrelatedHistories{ Style: mergeStyle, StdOut: ctx.outbuf.String(), StdErr: ctx.errbuf.String(), @@ -396,7 +470,7 @@ func runMergeCommand(ctx *mergeContext, mergeStyle repo_model.MergeStyle, cmd *g } } else if mergeStyle == repo_model.MergeStyleFastForwardOnly && strings.Contains(ctx.errbuf.String(), "Not possible to fast-forward, aborting") { log.Debug("MergeDivergingFastForwardOnly %-v: %v\n%s\n%s", ctx.pr, err, ctx.outbuf.String(), ctx.errbuf.String()) - return models.ErrMergeDivergingFastForwardOnly{ + return ErrMergeDivergingFastForwardOnly{ StdOut: ctx.outbuf.String(), StdErr: ctx.errbuf.String(), Err: err, @@ -431,6 +505,25 @@ func IsUserAllowedToMerge(ctx context.Context, pr *issues_model.PullRequest, p a return false, nil } +// ErrDisallowedToMerge represents an error that a branch is protected and the current user is not allowed to modify it. +type ErrDisallowedToMerge struct { + Reason string +} + +// IsErrDisallowedToMerge checks if an error is an ErrDisallowedToMerge. +func IsErrDisallowedToMerge(err error) bool { + _, ok := err.(ErrDisallowedToMerge) + return ok +} + +func (err ErrDisallowedToMerge) Error() string { + return fmt.Sprintf("not allowed to merge [reason: %s]", err.Reason) +} + +func (err ErrDisallowedToMerge) Unwrap() error { + return util.ErrPermissionDenied +} + // CheckPullBranchProtections checks whether the PR is ready to be merged (reviews and status checks) func CheckPullBranchProtections(ctx context.Context, pr *issues_model.PullRequest, skipProtectedFilesCheck bool) (err error) { if err = pr.LoadBaseRepo(ctx); err != nil { @@ -450,29 +543,29 @@ func CheckPullBranchProtections(ctx context.Context, pr *issues_model.PullReques return err } if !isPass { - return models.ErrDisallowedToMerge{ + return ErrDisallowedToMerge{ Reason: "Not all required status checks successful", } } if !issues_model.HasEnoughApprovals(ctx, pb, pr) { - return models.ErrDisallowedToMerge{ + return ErrDisallowedToMerge{ Reason: "Does not have enough approvals", } } if issues_model.MergeBlockedByRejectedReview(ctx, pb, pr) { - return models.ErrDisallowedToMerge{ + return ErrDisallowedToMerge{ Reason: "There are requested changes", } } if issues_model.MergeBlockedByOfficialReviewRequests(ctx, pb, pr) { - return models.ErrDisallowedToMerge{ + return ErrDisallowedToMerge{ Reason: "There are official review requests", } } if issues_model.MergeBlockedByOutdatedBranch(pb, pr) { - return models.ErrDisallowedToMerge{ + return ErrDisallowedToMerge{ Reason: "The head branch is behind the base branch", } } @@ -482,7 +575,7 @@ func CheckPullBranchProtections(ctx context.Context, pr *issues_model.PullReques } if pb.MergeBlockedByProtectedFiles(pr.ChangedProtectedFiles) { - return models.ErrDisallowedToMerge{ + return ErrDisallowedToMerge{ Reason: "Changed protected files", } } @@ -511,7 +604,7 @@ func MergedManually(ctx context.Context, pr *issues_model.PullRequest, doer *use // Check if merge style is correct and allowed if !prConfig.IsMergeStyleAllowed(repo_model.MergeStyleManuallyMerged) { - return models.ErrInvalidMergeStyle{ID: pr.BaseRepo.ID, Style: repo_model.MergeStyleManuallyMerged} + return ErrInvalidMergeStyle{ID: pr.BaseRepo.ID, Style: repo_model.MergeStyleManuallyMerged} } objectFormat := git.ObjectFormatFromName(pr.BaseRepo.ObjectFormatName) diff --git a/services/pull/merge_prepare.go b/services/pull/merge_prepare.go index 88f6c037eb..2e1cc8cf85 100644 --- a/services/pull/merge_prepare.go +++ b/services/pull/merge_prepare.go @@ -14,7 +14,6 @@ import ( "strings" "time" - "code.gitea.io/gitea/models" issues_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" @@ -43,6 +42,23 @@ func (ctx *mergeContext) RunOpts() *git.RunOpts { } } +// ErrSHADoesNotMatch represents a "SHADoesNotMatch" kind of error. +type ErrSHADoesNotMatch struct { + Path string + GivenSHA string + CurrentSHA string +} + +// IsErrSHADoesNotMatch checks if an error is a ErrSHADoesNotMatch. +func IsErrSHADoesNotMatch(err error) bool { + _, ok := err.(ErrSHADoesNotMatch) + return ok +} + +func (err ErrSHADoesNotMatch) Error() string { + return fmt.Sprintf("sha does not match [given: %s, expected: %s]", err.GivenSHA, err.CurrentSHA) +} + func createTemporaryRepoForMerge(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.User, expectedHeadCommitID string) (mergeCtx *mergeContext, cancel context.CancelFunc, err error) { // Clone base repo. prCtx, cancel, err := createTemporaryRepoForPR(ctx, pr) @@ -65,7 +81,7 @@ func createTemporaryRepoForMerge(ctx context.Context, pr *issues_model.PullReque } if strings.TrimSpace(trackingCommitID) != expectedHeadCommitID { defer cancel() - return nil, nil, models.ErrSHADoesNotMatch{ + return nil, nil, ErrSHADoesNotMatch{ GivenSHA: expectedHeadCommitID, CurrentSHA: trackingCommitID, } @@ -233,8 +249,27 @@ func getDiffTree(ctx context.Context, repoPath, baseBranch, headBranch string, o return err } +// ErrRebaseConflicts represents an error if rebase fails with a conflict +type ErrRebaseConflicts struct { + Style repo_model.MergeStyle + CommitSHA string + StdOut string + StdErr string + Err error +} + +// IsErrRebaseConflicts checks if an error is a ErrRebaseConflicts. +func IsErrRebaseConflicts(err error) bool { + _, ok := err.(ErrRebaseConflicts) + return ok +} + +func (err ErrRebaseConflicts) Error() string { + return fmt.Sprintf("Rebase Error: %v: Whilst Rebasing: %s\n%s\n%s", err.Err, err.CommitSHA, err.StdErr, err.StdOut) +} + // rebaseTrackingOnToBase checks out the tracking branch as staging and rebases it on to the base branch -// if there is a conflict it will return a models.ErrRebaseConflicts +// if there is a conflict it will return an ErrRebaseConflicts func rebaseTrackingOnToBase(ctx *mergeContext, mergeStyle repo_model.MergeStyle) error { // Checkout head branch if err := git.NewCommand(ctx, "checkout", "-b").AddDynamicArguments(stagingBranch, trackingBranch). @@ -268,11 +303,11 @@ func rebaseTrackingOnToBase(ctx *mergeContext, mergeStyle repo_model.MergeStyle) } } if !ok { - log.Error("Unable to determine failing commit sha for failing rebase in temp repo for %-v. Cannot cast as models.ErrRebaseConflicts.", ctx.pr) + log.Error("Unable to determine failing commit sha for failing rebase in temp repo for %-v. Cannot cast as ErrRebaseConflicts.", ctx.pr) return fmt.Errorf("unable to git rebase staging on to base in temp repo for %v: %w\n%s\n%s", ctx.pr, err, ctx.outbuf.String(), ctx.errbuf.String()) } log.Debug("Conflict when rebasing staging on to base in %-v at %s: %v\n%s\n%s", ctx.pr, commitSha, err, ctx.outbuf.String(), ctx.errbuf.String()) - return models.ErrRebaseConflicts{ + return ErrRebaseConflicts{ CommitSHA: commitSha, Style: mergeStyle, StdOut: ctx.outbuf.String(), diff --git a/services/pull/patch.go b/services/pull/patch.go index 0934a86c89..36ca9dbdb6 100644 --- a/services/pull/patch.go +++ b/services/pull/patch.go @@ -13,7 +13,6 @@ import ( "path/filepath" "strings" - "code.gitea.io/gitea/models" git_model "code.gitea.io/gitea/models/git" issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/unit" @@ -502,6 +501,29 @@ func checkConflicts(ctx context.Context, pr *issues_model.PullRequest, gitRepo * return false, nil } +// ErrFilePathProtected represents a "FilePathProtected" kind of error. +type ErrFilePathProtected struct { + Message string + Path string +} + +// IsErrFilePathProtected checks if an error is an ErrFilePathProtected. +func IsErrFilePathProtected(err error) bool { + _, ok := err.(ErrFilePathProtected) + return ok +} + +func (err ErrFilePathProtected) Error() string { + if err.Message != "" { + return err.Message + } + return fmt.Sprintf("path is protected and can not be changed [path: %s]", err.Path) +} + +func (err ErrFilePathProtected) Unwrap() error { + return util.ErrPermissionDenied +} + // CheckFileProtection check file Protection func CheckFileProtection(repo *git.Repository, branchName, oldCommitID, newCommitID string, patterns []glob.Glob, limit int, env []string) ([]string, error) { if len(patterns) == 0 { @@ -525,7 +547,7 @@ func CheckFileProtection(repo *git.Repository, branchName, oldCommitID, newCommi } } if len(changedProtectedFiles) > 0 { - err = models.ErrFilePathProtected{ + err = ErrFilePathProtected{ Path: changedProtectedFiles[0], } } @@ -575,7 +597,7 @@ func checkPullFilesProtection(ctx context.Context, pr *issues_model.PullRequest, } pr.ChangedProtectedFiles, err = CheckFileProtection(gitRepo, pr.HeadBranch, pr.MergeBase, "tracking", pb.GetProtectedFilePatterns(), 10, os.Environ()) - if err != nil && !models.IsErrFilePathProtected(err) { + if err != nil && !IsErrFilePathProtected(err) { return err } return nil diff --git a/services/pull/pull.go b/services/pull/pull.go index 3362cb97ff..0256c2c3f6 100644 --- a/services/pull/pull.go +++ b/services/pull/pull.go @@ -13,7 +13,6 @@ import ( "strings" "time" - "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" git_model "code.gitea.io/gitea/models/git" issues_model "code.gitea.io/gitea/models/issues" @@ -224,6 +223,28 @@ func NewPullRequest(ctx context.Context, opts *NewPullRequestOptions) error { return nil } +// ErrPullRequestHasMerged represents a "PullRequestHasMerged"-error +type ErrPullRequestHasMerged struct { + ID int64 + IssueID int64 + HeadRepoID int64 + BaseRepoID int64 + HeadBranch string + BaseBranch string +} + +// IsErrPullRequestHasMerged checks if an error is a ErrPullRequestHasMerged. +func IsErrPullRequestHasMerged(err error) bool { + _, ok := err.(ErrPullRequestHasMerged) + return ok +} + +// Error does pretty-printing :D +func (err ErrPullRequestHasMerged) Error() string { + return fmt.Sprintf("pull request has merged [id: %d, issue_id: %d, head_repo_id: %d, base_repo_id: %d, head_branch: %s, base_branch: %s]", + err.ID, err.IssueID, err.HeadRepoID, err.BaseRepoID, err.HeadBranch, err.BaseBranch) +} + // ChangeTargetBranch changes the target branch of this pull request, as the given user. func ChangeTargetBranch(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.User, targetBranch string) (err error) { releaser, err := globallock.Lock(ctx, getPullWorkingLockKey(pr.ID)) @@ -247,7 +268,7 @@ func ChangeTargetBranch(ctx context.Context, pr *issues_model.PullRequest, doer } if pr.HasMerged { - return models.ErrPullRequestHasMerged{ + return ErrPullRequestHasMerged{ ID: pr.ID, IssueID: pr.Index, HeadRepoID: pr.HeadRepoID, @@ -654,7 +675,7 @@ func RetargetBranchPulls(ctx context.Context, doer *user_model.User, repoID int6 if err = pr.Issue.LoadRepo(ctx); err != nil { errs = append(errs, err) } else if err = ChangeTargetBranch(ctx, pr, doer, targetBranch); err != nil && - !issues_model.IsErrIssueIsClosed(err) && !models.IsErrPullRequestHasMerged(err) && + !issues_model.IsErrIssueIsClosed(err) && !IsErrPullRequestHasMerged(err) && !issues_model.IsErrPullRequestAlreadyExists(err) { errs = append(errs, err) } diff --git a/services/release/release.go b/services/release/release.go index 980a5e98e7..84c60a105a 100644 --- a/services/release/release.go +++ b/services/release/release.go @@ -9,7 +9,6 @@ import ( "fmt" "strings" - "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" git_model "code.gitea.io/gitea/models/git" repo_model "code.gitea.io/gitea/models/repo" @@ -26,6 +25,44 @@ import ( notify_service "code.gitea.io/gitea/services/notify" ) +// ErrInvalidTagName represents a "InvalidTagName" kind of error. +type ErrInvalidTagName struct { + TagName string +} + +// IsErrInvalidTagName checks if an error is a ErrInvalidTagName. +func IsErrInvalidTagName(err error) bool { + _, ok := err.(ErrInvalidTagName) + return ok +} + +func (err ErrInvalidTagName) Error() string { + return fmt.Sprintf("release tag name is not valid [tag_name: %s]", err.TagName) +} + +func (err ErrInvalidTagName) Unwrap() error { + return util.ErrInvalidArgument +} + +// ErrProtectedTagName represents a "ProtectedTagName" kind of error. +type ErrProtectedTagName struct { + TagName string +} + +// IsErrProtectedTagName checks if an error is a ErrProtectedTagName. +func IsErrProtectedTagName(err error) bool { + _, ok := err.(ErrProtectedTagName) + return ok +} + +func (err ErrProtectedTagName) Error() string { + return fmt.Sprintf("release tag name is protected [tag_name: %s]", err.TagName) +} + +func (err ErrProtectedTagName) Unwrap() error { + return util.ErrPermissionDenied +} + func createTag(ctx context.Context, gitRepo *git.Repository, rel *repo_model.Release, msg string) (bool, error) { err := rel.LoadAttributes(ctx) if err != nil { @@ -58,7 +95,7 @@ func createTag(ctx context.Context, gitRepo *git.Repository, rel *repo_model.Rel return false, err } if !isAllowed { - return false, models.ErrProtectedTagName{ + return false, ErrProtectedTagName{ TagName: rel.TagName, } } @@ -71,7 +108,7 @@ func createTag(ctx context.Context, gitRepo *git.Repository, rel *repo_model.Rel if len(msg) > 0 { if err = gitRepo.CreateAnnotatedTag(rel.TagName, msg, commit.ID.String()); err != nil { if strings.Contains(err.Error(), "is not a valid tag name") { - return false, models.ErrInvalidTagName{ + return false, ErrInvalidTagName{ TagName: rel.TagName, } } @@ -79,7 +116,7 @@ func createTag(ctx context.Context, gitRepo *git.Repository, rel *repo_model.Rel } } else if err = gitRepo.CreateTag(rel.TagName, commit.ID.String()); err != nil { if strings.Contains(err.Error(), "is not a valid tag name") { - return false, models.ErrInvalidTagName{ + return false, ErrInvalidTagName{ TagName: rel.TagName, } } @@ -159,13 +196,32 @@ func CreateRelease(gitRepo *git.Repository, rel *repo_model.Release, attachmentU return nil } +// ErrTagAlreadyExists represents an error that tag with such name already exists. +type ErrTagAlreadyExists struct { + TagName string +} + +// IsErrTagAlreadyExists checks if an error is an ErrTagAlreadyExists. +func IsErrTagAlreadyExists(err error) bool { + _, ok := err.(ErrTagAlreadyExists) + return ok +} + +func (err ErrTagAlreadyExists) Error() string { + return fmt.Sprintf("tag already exists [name: %s]", err.TagName) +} + +func (err ErrTagAlreadyExists) Unwrap() error { + return util.ErrAlreadyExist +} + // CreateNewTag creates a new repository tag func CreateNewTag(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, commit, tagName, msg string) error { has, err := repo_model.IsReleaseExist(ctx, repo.ID, tagName) if err != nil { return err } else if has { - return models.ErrTagAlreadyExists{ + return ErrTagAlreadyExists{ TagName: tagName, } } @@ -320,13 +376,12 @@ func DeleteReleaseByID(ctx context.Context, repo *repo_model.Repository, rel *re return err } if !isAllowed { - return models.ErrProtectedTagName{ + return ErrProtectedTagName{ TagName: rel.TagName, } } if stdout, _, err := git.NewCommand(ctx, "tag", "-d").AddDashesAndList(rel.TagName). - SetDescription(fmt.Sprintf("DeleteReleaseByID (git tag -d): %d", rel.ID)). RunStdString(&git.RunOpts{Dir: repo.RepoPath()}); err != nil && !strings.Contains(err.Error(), "not found") { log.Error("DeleteReleaseByID (git tag -d): %d in %v Failed:\nStdout: %s\nError: %v", rel.ID, repo, stdout, err) return fmt.Errorf("git tag -d: %w", err) diff --git a/services/repository/adopt.go b/services/repository/adopt.go index 615f4d482c..e37909e7ab 100644 --- a/services/repository/adopt.go +++ b/services/repository/adopt.go @@ -92,7 +92,6 @@ func AdoptRepository(ctx context.Context, doer, u *user_model.User, opts CreateR } if stdout, _, err := git.NewCommand(ctx, "update-server-info"). - SetDescription(fmt.Sprintf("CreateRepository(git update-server-info): %s", repoPath)). RunStdString(&git.RunOpts{Dir: repoPath}); err != nil { log.Error("CreateRepository(git update-server-info) in %v: Stdout: %s\nError: %v", repo, stdout, err) return fmt.Errorf("CreateRepository(git update-server-info): %w", err) diff --git a/services/repository/branch.go b/services/repository/branch.go index 3a95aab264..fc476298ca 100644 --- a/services/repository/branch.go +++ b/services/repository/branch.go @@ -9,7 +9,6 @@ import ( "fmt" "strings" - "code.gitea.io/gitea/models" actions_model "code.gitea.io/gitea/models/actions" "code.gitea.io/gitea/models/db" git_model "code.gitea.io/gitea/models/git" @@ -31,6 +30,7 @@ import ( "code.gitea.io/gitea/modules/util" webhook_module "code.gitea.io/gitea/modules/webhook" notify_service "code.gitea.io/gitea/services/notify" + release_service "code.gitea.io/gitea/services/release" files_service "code.gitea.io/gitea/services/repository/files" "xorm.io/builder" @@ -274,7 +274,7 @@ func checkBranchName(ctx context.Context, repo *repo_model.Repository, name stri BranchName: branchRefName, } case refName == git.TagPrefix+name: - return models.ErrTagAlreadyExists{ + return release_service.ErrTagAlreadyExists{ TagName: name, } } diff --git a/services/repository/check.go b/services/repository/check.go index 5cdcc14679..acca15daf2 100644 --- a/services/repository/check.go +++ b/services/repository/check.go @@ -86,8 +86,7 @@ func GitGcRepos(ctx context.Context, timeout time.Duration, args git.TrustedCmdA // GitGcRepo calls 'git gc' to remove unnecessary files and optimize the local repository func GitGcRepo(ctx context.Context, repo *repo_model.Repository, timeout time.Duration, args git.TrustedCmdArgs) error { log.Trace("Running git gc on %-v", repo) - command := git.NewCommand(ctx, "gc").AddArguments(args...). - SetDescription(fmt.Sprintf("Repository Garbage Collection: %s", repo.FullName())) + command := git.NewCommand(ctx, "gc").AddArguments(args...) var stdout string var err error stdout, _, err = command.RunStdString(&git.RunOpts{Timeout: timeout, Dir: repo.RepoPath()}) diff --git a/services/repository/create.go b/services/repository/create.go index 14e625d962..a3199f2a40 100644 --- a/services/repository/create.go +++ b/services/repository/create.go @@ -68,7 +68,6 @@ func prepareRepoCommit(ctx context.Context, repo *repo_model.Repository, tmpDir, // Clone to temporary path and do the init commit. if stdout, _, err := git.NewCommand(ctx, "clone").AddDynamicArguments(repoPath, tmpDir). - SetDescription(fmt.Sprintf("prepareRepoCommit (git clone): %s to %s", repoPath, tmpDir)). RunStdString(&git.RunOpts{Dir: "", Env: env}); err != nil { log.Error("Failed to clone from %v into %s: stdout: %s\nError: %v", repo, tmpDir, stdout, err) return fmt.Errorf("git clone: %w", err) @@ -301,7 +300,6 @@ func CreateRepositoryDirectly(ctx context.Context, doer, u *user_model.User, opt } if stdout, _, err := git.NewCommand(ctx, "update-server-info"). - SetDescription(fmt.Sprintf("CreateRepository(git update-server-info): %s", repoPath)). RunStdString(&git.RunOpts{Dir: repoPath}); err != nil { log.Error("CreateRepository(git update-server-info) in %v: Stdout: %s\nError: %v", repo, stdout, err) rollbackRepo = repo @@ -314,9 +312,7 @@ func CreateRepositoryDirectly(ctx context.Context, doer, u *user_model.User, opt if len(opts.License) > 0 { licenses = append(licenses, ConvertLicenseName(opts.License)) - stdout, _, err := git.NewCommand(ctx, "rev-parse", "HEAD"). - SetDescription(fmt.Sprintf("CreateRepository(git rev-parse HEAD): %s", repoPath)). - RunStdString(&git.RunOpts{Dir: repoPath}) + stdout, _, err := git.NewCommand(ctx, "rev-parse", "HEAD").RunStdString(&git.RunOpts{Dir: repoPath}) if err != nil { log.Error("CreateRepository(git rev-parse HEAD) in %v: Stdout: %s\nError: %v", repo, stdout, err) rollbackRepo = repo diff --git a/services/repository/files/cherry_pick.go b/services/repository/files/cherry_pick.go index 451a182155..10545e9e03 100644 --- a/services/repository/files/cherry_pick.go +++ b/services/repository/files/cherry_pick.go @@ -8,7 +8,6 @@ import ( "fmt" "strings" - "code.gitea.io/gitea/models" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/git" @@ -17,6 +16,22 @@ import ( "code.gitea.io/gitea/services/pull" ) +// ErrCommitIDDoesNotMatch represents a "CommitIDDoesNotMatch" kind of error. +type ErrCommitIDDoesNotMatch struct { + GivenCommitID string + CurrentCommitID string +} + +// IsErrCommitIDDoesNotMatch checks if an error is a ErrCommitIDDoesNotMatch. +func IsErrCommitIDDoesNotMatch(err error) bool { + _, ok := err.(ErrCommitIDDoesNotMatch) + return ok +} + +func (err ErrCommitIDDoesNotMatch) Error() string { + return fmt.Sprintf("file CommitID does not match [given: %s, expected: %s]", err.GivenCommitID, err.CurrentCommitID) +} + // CherryPick cherrypicks or reverts a commit to the given repository func CherryPick(ctx context.Context, repo *repo_model.Repository, doer *user_model.User, revert bool, opts *ApplyDiffPatchOptions) (*structs.FileResponse, error) { if err := opts.Validate(ctx, repo, doer); err != nil { @@ -57,7 +72,7 @@ func CherryPick(ctx context.Context, repo *repo_model.Repository, doer *user_mod } opts.LastCommitID = lastCommitID.String() if commit.ID.String() != opts.LastCommitID { - return nil, models.ErrCommitIDDoesNotMatch{ + return nil, ErrCommitIDDoesNotMatch{ GivenCommitID: opts.LastCommitID, CurrentCommitID: opts.LastCommitID, } diff --git a/services/repository/files/content.go b/services/repository/files/content.go index 95e7c7087c..0ab7422ce2 100644 --- a/services/repository/files/content.go +++ b/services/repository/files/content.go @@ -10,7 +10,6 @@ import ( "path" "strings" - "code.gitea.io/gitea/models" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" @@ -53,7 +52,7 @@ func GetContentsOrList(ctx context.Context, repo *repo_model.Repository, treePat // Check that the path given in opts.treePath is valid (not a git path) cleanTreePath := CleanUploadFileName(treePath) if cleanTreePath == "" && treePath != "" { - return nil, models.ErrFilenameInvalid{ + return nil, ErrFilenameInvalid{ Path: treePath, } } @@ -128,7 +127,7 @@ func GetContents(ctx context.Context, repo *repo_model.Repository, treePath, ref // Check that the path given in opts.treePath is valid (not a git path) cleanTreePath := CleanUploadFileName(treePath) if cleanTreePath == "" && treePath != "" { - return nil, models.ErrFilenameInvalid{ + return nil, ErrFilenameInvalid{ Path: treePath, } } diff --git a/services/repository/files/file.go b/services/repository/files/file.go index 16783f5b5f..d7ca8e79e5 100644 --- a/services/repository/files/file.go +++ b/services/repository/files/file.go @@ -156,6 +156,25 @@ func GetAuthorAndCommitterUsers(author, committer *IdentityOptions, doer *user_m return authorUser, committerUser } +// ErrFilenameInvalid represents a "FilenameInvalid" kind of error. +type ErrFilenameInvalid struct { + Path string +} + +// IsErrFilenameInvalid checks if an error is an ErrFilenameInvalid. +func IsErrFilenameInvalid(err error) bool { + _, ok := err.(ErrFilenameInvalid) + return ok +} + +func (err ErrFilenameInvalid) Error() string { + return fmt.Sprintf("path contains a malformed path component [path: %s]", err.Path) +} + +func (err ErrFilenameInvalid) Unwrap() error { + return util.ErrInvalidArgument +} + // CleanUploadFileName Trims a filename and returns empty string if it is a .git directory func CleanUploadFileName(name string) string { // Rebase the filename diff --git a/services/repository/files/patch.go b/services/repository/files/patch.go index ab0e7ffd36..38c17b4073 100644 --- a/services/repository/files/patch.go +++ b/services/repository/files/patch.go @@ -8,7 +8,6 @@ import ( "fmt" "strings" - "code.gitea.io/gitea/models" git_model "code.gitea.io/gitea/models/git" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" @@ -16,9 +15,29 @@ import ( "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/util" asymkey_service "code.gitea.io/gitea/services/asymkey" ) +// ErrUserCannotCommit represents "UserCannotCommit" kind of error. +type ErrUserCannotCommit struct { + UserName string +} + +// IsErrUserCannotCommit checks if an error is an ErrUserCannotCommit. +func IsErrUserCannotCommit(err error) bool { + _, ok := err.(ErrUserCannotCommit) + return ok +} + +func (err ErrUserCannotCommit) Error() string { + return fmt.Sprintf("user cannot commit to repo [user: %s]", err.UserName) +} + +func (err ErrUserCannotCommit) Unwrap() error { + return util.ErrPermissionDenied +} + // ApplyDiffPatchOptions holds the repository diff patch update options type ApplyDiffPatchOptions struct { LastCommitID string @@ -74,7 +93,7 @@ func (opts *ApplyDiffPatchOptions) Validate(ctx context.Context, repo *repo_mode if protectedBranch != nil { protectedBranch.Repo = repo if !protectedBranch.CanUserPush(ctx, doer) { - return models.ErrUserCannotCommit{ + return ErrUserCannotCommit{ UserName: doer.LowerName, } } @@ -85,7 +104,7 @@ func (opts *ApplyDiffPatchOptions) Validate(ctx context.Context, repo *repo_mode if !asymkey_service.IsErrWontSign(err) { return err } - return models.ErrUserCannotCommit{ + return ErrUserCannotCommit{ UserName: doer.LowerName, } } @@ -137,7 +156,7 @@ func ApplyDiffPatch(ctx context.Context, repo *repo_model.Repository, doer *user } opts.LastCommitID = lastCommitID.String() if commit.ID.String() != opts.LastCommitID { - return nil, models.ErrCommitIDDoesNotMatch{ + return nil, ErrCommitIDDoesNotMatch{ GivenCommitID: opts.LastCommitID, CurrentCommitID: opts.LastCommitID, } diff --git a/services/repository/files/temp_repo.go b/services/repository/files/temp_repo.go index 30ab22db1e..138af991f9 100644 --- a/services/repository/files/temp_repo.go +++ b/services/repository/files/temp_repo.go @@ -13,7 +13,6 @@ import ( "strings" "time" - "code.gitea.io/gitea/models" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/git" @@ -187,7 +186,7 @@ func (t *TemporaryUploadRepository) AddObjectToIndex(mode, objectHash, objectPat if _, _, err := git.NewCommand(t.ctx, "update-index", "--add", "--replace", "--cacheinfo").AddDynamicArguments(mode, objectHash, objectPath).RunStdString(&git.RunOpts{Dir: t.basePath}); err != nil { stderr := err.Error() if matched, _ := regexp.MatchString(".*Invalid path '.*", stderr); matched { - return models.ErrFilePathInvalid{ + return ErrFilePathInvalid{ Message: objectPath, Path: objectPath, } diff --git a/services/repository/files/tree.go b/services/repository/files/tree.go index e3a7f3b8b0..6775186afd 100644 --- a/services/repository/files/tree.go +++ b/services/repository/files/tree.go @@ -8,18 +8,37 @@ import ( "fmt" "net/url" - "code.gitea.io/gitea/models" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/util" ) +// ErrSHANotFound represents a "SHADoesNotMatch" kind of error. +type ErrSHANotFound struct { + SHA string +} + +// IsErrSHANotFound checks if an error is a ErrSHANotFound. +func IsErrSHANotFound(err error) bool { + _, ok := err.(ErrSHANotFound) + return ok +} + +func (err ErrSHANotFound) Error() string { + return fmt.Sprintf("sha not found [%s]", err.SHA) +} + +func (err ErrSHANotFound) Unwrap() error { + return util.ErrNotExist +} + // GetTreeBySHA get the GitTreeResponse of a repository using a sha hash. func GetTreeBySHA(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, sha string, page, perPage int, recursive bool) (*api.GitTreeResponse, error) { gitTree, err := gitRepo.GetTree(sha) if err != nil || gitTree == nil { - return nil, models.ErrSHANotFound{ + return nil, ErrSHANotFound{ // TODO: this error has never been catch outside of this function SHA: sha, } } diff --git a/services/repository/files/update.go b/services/repository/files/update.go index b1b64bacd9..a2763105b0 100644 --- a/services/repository/files/update.go +++ b/services/repository/files/update.go @@ -11,7 +11,6 @@ import ( "strings" "time" - "code.gitea.io/gitea/models" git_model "code.gitea.io/gitea/models/git" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" @@ -21,7 +20,9 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/util" asymkey_service "code.gitea.io/gitea/services/asymkey" + pull_service "code.gitea.io/gitea/services/pull" ) // IdentityOptions for a person's identity like an author or committer @@ -64,6 +65,26 @@ type RepoFileOptions struct { executable bool } +// ErrRepoFileDoesNotExist represents a "RepoFileDoesNotExist" kind of error. +type ErrRepoFileDoesNotExist struct { + Path string + Name string +} + +// IsErrRepoFileDoesNotExist checks if an error is a ErrRepoDoesNotExist. +func IsErrRepoFileDoesNotExist(err error) bool { + _, ok := err.(ErrRepoFileDoesNotExist) + return ok +} + +func (err ErrRepoFileDoesNotExist) Error() string { + return fmt.Sprintf("repository file does not exist [path: %s]", err.Path) +} + +func (err ErrRepoFileDoesNotExist) Unwrap() error { + return util.ErrNotExist +} + // ChangeRepoFiles adds, updates or removes multiple files in the given repository func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *user_model.User, opts *ChangeRepoFilesOptions) (*structs.FilesResponse, error) { err := repo.MustNotBeArchived() @@ -100,14 +121,14 @@ func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use // Check that the path given in opts.treePath is valid (not a git path) treePath := CleanUploadFileName(file.TreePath) if treePath == "" { - return nil, models.ErrFilenameInvalid{ + return nil, ErrFilenameInvalid{ Path: file.TreePath, } } // If there is a fromTreePath (we are copying it), also clean it up fromTreePath := CleanUploadFileName(file.FromTreePath) if fromTreePath == "" && file.FromTreePath != "" { - return nil, models.ErrFilenameInvalid{ + return nil, ErrFilenameInvalid{ Path: file.FromTreePath, } } @@ -185,7 +206,7 @@ func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use } } if !inFilelist { - return nil, models.ErrRepoFileDoesNotExist{ + return nil, ErrRepoFileDoesNotExist{ Path: file.TreePath, } } @@ -276,6 +297,63 @@ func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use return filesResponse, nil } +// ErrRepoFileAlreadyExists represents a "RepoFileAlreadyExist" kind of error. +type ErrRepoFileAlreadyExists struct { + Path string +} + +// IsErrRepoFileAlreadyExists checks if an error is a ErrRepoFileAlreadyExists. +func IsErrRepoFileAlreadyExists(err error) bool { + _, ok := err.(ErrRepoFileAlreadyExists) + return ok +} + +func (err ErrRepoFileAlreadyExists) Error() string { + return fmt.Sprintf("repository file already exists [path: %s]", err.Path) +} + +func (err ErrRepoFileAlreadyExists) Unwrap() error { + return util.ErrAlreadyExist +} + +// ErrFilePathInvalid represents a "FilePathInvalid" kind of error. +type ErrFilePathInvalid struct { + Message string + Path string + Name string + Type git.EntryMode +} + +// IsErrFilePathInvalid checks if an error is an ErrFilePathInvalid. +func IsErrFilePathInvalid(err error) bool { + _, ok := err.(ErrFilePathInvalid) + return ok +} + +func (err ErrFilePathInvalid) Error() string { + if err.Message != "" { + return err.Message + } + return fmt.Sprintf("path is invalid [path: %s]", err.Path) +} + +func (err ErrFilePathInvalid) Unwrap() error { + return util.ErrInvalidArgument +} + +// ErrSHAOrCommitIDNotProvided represents a "SHAOrCommitIDNotProvided" kind of error. +type ErrSHAOrCommitIDNotProvided struct{} + +// IsErrSHAOrCommitIDNotProvided checks if an error is a ErrSHAOrCommitIDNotProvided. +func IsErrSHAOrCommitIDNotProvided(err error) bool { + _, ok := err.(ErrSHAOrCommitIDNotProvided) + return ok +} + +func (err ErrSHAOrCommitIDNotProvided) Error() string { + return "a SHA or commit ID must be proved when updating a file" +} + // handles the check for various issues for ChangeRepoFiles func handleCheckErrors(file *ChangeRepoFile, commit *git.Commit, opts *ChangeRepoFilesOptions) error { if file.Operation == "update" || file.Operation == "delete" { @@ -286,7 +364,7 @@ func handleCheckErrors(file *ChangeRepoFile, commit *git.Commit, opts *ChangeRep if file.SHA != "" { // If a SHA was given and the SHA given doesn't match the SHA of the fromTreePath, throw error if file.SHA != fromEntry.ID.String() { - return models.ErrSHADoesNotMatch{ + return pull_service.ErrSHADoesNotMatch{ Path: file.Options.treePath, GivenSHA: file.SHA, CurrentSHA: fromEntry.ID.String(), @@ -299,7 +377,7 @@ func handleCheckErrors(file *ChangeRepoFile, commit *git.Commit, opts *ChangeRep if changed, err := commit.FileChangedSinceCommit(file.Options.treePath, opts.LastCommitID); err != nil { return err } else if changed { - return models.ErrCommitIDDoesNotMatch{ + return ErrCommitIDDoesNotMatch{ GivenCommitID: opts.LastCommitID, CurrentCommitID: opts.LastCommitID, } @@ -309,7 +387,7 @@ func handleCheckErrors(file *ChangeRepoFile, commit *git.Commit, opts *ChangeRep } else { // When updating a file, a lastCommitID or SHA needs to be given to make sure other commits // haven't been made. We throw an error if one wasn't provided. - return models.ErrSHAOrCommitIDNotProvided{} + return ErrSHAOrCommitIDNotProvided{} } file.Options.executable = fromEntry.IsExecutable() } @@ -332,7 +410,7 @@ func handleCheckErrors(file *ChangeRepoFile, commit *git.Commit, opts *ChangeRep } if index < len(treePathParts)-1 { if !entry.IsDir() { - return models.ErrFilePathInvalid{ + return ErrFilePathInvalid{ Message: fmt.Sprintf("a file exists where you’re trying to create a subdirectory [path: %s]", subTreePath), Path: subTreePath, Name: part, @@ -340,14 +418,14 @@ func handleCheckErrors(file *ChangeRepoFile, commit *git.Commit, opts *ChangeRep } } } else if entry.IsLink() { - return models.ErrFilePathInvalid{ + return ErrFilePathInvalid{ Message: fmt.Sprintf("a symbolic link exists where you’re trying to create a subdirectory [path: %s]", subTreePath), Path: subTreePath, Name: part, Type: git.EntryModeSymlink, } } else if entry.IsDir() { - return models.ErrFilePathInvalid{ + return ErrFilePathInvalid{ Message: fmt.Sprintf("a directory exists where you’re trying to create a file [path: %s]", subTreePath), Path: subTreePath, Name: part, @@ -355,7 +433,7 @@ func handleCheckErrors(file *ChangeRepoFile, commit *git.Commit, opts *ChangeRep } } else if file.Options.fromTreePath != file.Options.treePath || file.Operation == "create" { // The entry shouldn't exist if we are creating new file or moving to a new path - return models.ErrRepoFileAlreadyExists{ + return ErrRepoFileAlreadyExists{ Path: file.Options.treePath, } } @@ -376,7 +454,7 @@ func CreateOrUpdateFile(ctx context.Context, t *TemporaryUploadRepository, file if file.Operation == "create" { for _, indexFile := range filesInIndex { if indexFile == file.TreePath { - return models.ErrRepoFileAlreadyExists{ + return ErrRepoFileAlreadyExists{ Path: file.TreePath, } } @@ -479,12 +557,12 @@ func VerifyBranchProtection(ctx context.Context, repo *repo_model.Repository, do isUnprotectedFile = protectedBranch.IsUnprotectedFile(globUnprotected, treePath) } if !canUserPush && !isUnprotectedFile { - return models.ErrUserCannotCommit{ + return ErrUserCannotCommit{ UserName: doer.LowerName, } } if protectedBranch.IsProtectedFile(globProtected, treePath) { - return models.ErrFilePathProtected{ + return pull_service.ErrFilePathProtected{ Path: treePath, } } @@ -495,7 +573,7 @@ func VerifyBranchProtection(ctx context.Context, repo *repo_model.Repository, do if !asymkey_service.IsErrWontSign(err) { return err } - return models.ErrUserCannotCommit{ + return ErrUserCannotCommit{ UserName: doer.LowerName, } } diff --git a/services/repository/fork.go b/services/repository/fork.go index bc4fdf8562..cff0b1a403 100644 --- a/services/repository/fork.go +++ b/services/repository/fork.go @@ -158,7 +158,6 @@ func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts Fork } repoPath := repo_model.RepoPath(owner.Name, repo.Name) if stdout, _, err := cloneCmd.AddDynamicArguments(oldRepoPath, repoPath). - SetDescription(fmt.Sprintf("ForkRepository(git clone): %s to %s", opts.BaseRepo.FullName(), repo.FullName())). RunStdBytes(&git.RunOpts{Timeout: 10 * time.Minute}); err != nil { log.Error("Fork Repository (git clone) Failed for %v (from %v):\nStdout: %s\nError: %v", repo, opts.BaseRepo, stdout, err) return fmt.Errorf("git clone: %w", err) @@ -169,7 +168,6 @@ func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts Fork } if stdout, _, err := git.NewCommand(txCtx, "update-server-info"). - SetDescription(fmt.Sprintf("ForkRepository(git update-server-info): %s", repo.FullName())). RunStdString(&git.RunOpts{Dir: repoPath}); err != nil { log.Error("Fork Repository (git update-server-info) failed for %v:\nStdout: %s\nError: %v", repo, stdout, err) return fmt.Errorf("git update-server-info: %w", err) diff --git a/services/repository/generate.go b/services/repository/generate.go index f2280de8b2..24cf9d1b9b 100644 --- a/services/repository/generate.go +++ b/services/repository/generate.go @@ -237,7 +237,6 @@ func generateRepoCommit(ctx context.Context, repo, templateRepo, generateRepo *r repoPath := repo.RepoPath() if stdout, _, err := git.NewCommand(ctx, "remote", "add", "origin").AddDynamicArguments(repoPath). - SetDescription(fmt.Sprintf("generateRepoCommit (git remote add): %s to %s", templateRepoPath, tmpDir)). RunStdString(&git.RunOpts{Dir: tmpDir, Env: env}); err != nil { log.Error("Unable to add %v as remote origin to temporary repo to %s: stdout %s\nError: %v", repo, tmpDir, stdout, err) return fmt.Errorf("git remote add: %w", err) @@ -369,7 +368,6 @@ func generateRepository(ctx context.Context, doer, owner *user_model.User, templ } if stdout, _, err := git.NewCommand(ctx, "update-server-info"). - SetDescription(fmt.Sprintf("GenerateRepository(git update-server-info): %s", repoPath)). RunStdString(&git.RunOpts{Dir: repoPath}); err != nil { log.Error("GenerateRepository(git update-server-info) in %v: Stdout: %s\nError: %v", generateRepo, stdout, err) return generateRepo, fmt.Errorf("error in GenerateRepository(git update-server-info): %w", err) diff --git a/services/repository/init.go b/services/repository/init.go index 817fa4abd7..c719e11786 100644 --- a/services/repository/init.go +++ b/services/repository/init.go @@ -34,7 +34,6 @@ func initRepoCommit(ctx context.Context, tmpPath string, repo *repo_model.Reposi committerEmail := sig.Email if stdout, _, err := git.NewCommand(ctx, "add", "--all"). - SetDescription(fmt.Sprintf("initRepoCommit (git add): %s", tmpPath)). RunStdString(&git.RunOpts{Dir: tmpPath}); err != nil { log.Error("git add --all failed: Stdout: %s\nError: %v", stdout, err) return fmt.Errorf("git add --all: %w", err) @@ -62,9 +61,8 @@ func initRepoCommit(ctx context.Context, tmpPath string, repo *repo_model.Reposi ) if stdout, _, err := cmd. - SetDescription(fmt.Sprintf("initRepoCommit (git commit): %s", tmpPath)). RunStdString(&git.RunOpts{Dir: tmpPath, Env: env}); err != nil { - log.Error("Failed to commit: %v: Stdout: %s\nError: %v", cmd.String(), stdout, err) + log.Error("Failed to commit: %v: Stdout: %s\nError: %v", cmd.LogString(), stdout, err) return fmt.Errorf("git commit: %w", err) } @@ -73,7 +71,6 @@ func initRepoCommit(ctx context.Context, tmpPath string, repo *repo_model.Reposi } if stdout, _, err := git.NewCommand(ctx, "push", "origin").AddDynamicArguments("HEAD:" + defaultBranch). - SetDescription(fmt.Sprintf("initRepoCommit (git push): %s", tmpPath)). RunStdString(&git.RunOpts{Dir: tmpPath, Env: repo_module.InternalPushingEnvironment(u, repo)}); err != nil { log.Error("Failed to push back to HEAD: Stdout: %s\nError: %v", stdout, err) return fmt.Errorf("git push: %w", err) diff --git a/services/repository/migrate.go b/services/repository/migrate.go index c627b46fab..7fe63eb5ca 100644 --- a/services/repository/migrate.go +++ b/services/repository/migrate.go @@ -122,7 +122,6 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User, } if stdout, _, err := git.NewCommand(ctx, "update-server-info"). - SetDescription(fmt.Sprintf("MigrateRepositoryGitData(git update-server-info): %s", repoPath)). RunStdString(&git.RunOpts{Dir: repoPath}); err != nil { log.Error("MigrateRepositoryGitData(git update-server-info) in %v: Stdout: %s\nError: %v", repo, stdout, err) return repo, fmt.Errorf("error in MigrateRepositoryGitData(git update-server-info): %w", err) diff --git a/services/user/update.go b/services/user/update.go index cbaf90053a..4a39f4f783 100644 --- a/services/user/update.go +++ b/services/user/update.go @@ -7,7 +7,6 @@ import ( "context" "fmt" - "code.gitea.io/gitea/models" auth_model "code.gitea.io/gitea/models/auth" user_model "code.gitea.io/gitea/models/user" password_module "code.gitea.io/gitea/modules/auth/password" @@ -113,7 +112,7 @@ func UpdateUser(ctx context.Context, u *user_model.User, opts *UpdateOptions) er } if opts.IsAdmin.Has() { if !opts.IsAdmin.Value() && user_model.IsLastAdminUser(ctx, u) { - return models.ErrDeleteLastAdminUser{UID: u.ID} + return user_model.ErrDeleteLastAdminUser{UID: u.ID} } u.IsAdmin = opts.IsAdmin.Value() diff --git a/services/user/user.go b/services/user/user.go index 7bde642412..1aeebff142 100644 --- a/services/user/user.go +++ b/services/user/user.go @@ -10,7 +10,6 @@ import ( "strings" "time" - "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" packages_model "code.gitea.io/gitea/models/packages" @@ -127,7 +126,7 @@ func DeleteUser(ctx context.Context, u *user_model.User, purge bool) error { } if u.IsActive && user_model.IsLastAdminUser(ctx, u) { - return models.ErrDeleteLastAdminUser{UID: u.ID} + return user_model.ErrDeleteLastAdminUser{UID: u.ID} } if purge { @@ -225,7 +224,7 @@ func DeleteUser(ctx context.Context, u *user_model.User, purge bool) error { if err != nil { return fmt.Errorf("GetRepositoryCount: %w", err) } else if count > 0 { - return models.ErrUserOwnRepos{UID: u.ID} + return repo_model.ErrUserOwnRepos{UID: u.ID} } // Check membership of organization. @@ -233,14 +232,14 @@ func DeleteUser(ctx context.Context, u *user_model.User, purge bool) error { if err != nil { return fmt.Errorf("GetOrganizationCount: %w", err) } else if count > 0 { - return models.ErrUserHasOrgs{UID: u.ID} + return organization.ErrUserHasOrgs{UID: u.ID} } // Check ownership of packages. if ownsPackages, err := packages_model.HasOwnerPackages(ctx, u.ID); err != nil { return fmt.Errorf("HasOwnerPackages: %w", err) } else if ownsPackages { - return models.ErrUserOwnPackages{UID: u.ID} + return packages_model.ErrUserOwnPackages{UID: u.ID} } if err := deleteUser(ctx, u, purge); err != nil { @@ -288,7 +287,7 @@ func DeleteInactiveUsers(ctx context.Context, olderThan time.Duration) error { for _, u := range inactiveUsers { if err = DeleteUser(ctx, u, false); err != nil { // Ignore inactive users that were ever active but then were set inactive by admin - if models.IsErrUserOwnRepos(err) || models.IsErrUserHasOrgs(err) || models.IsErrUserOwnPackages(err) { + if repo_model.IsErrUserOwnRepos(err) || organization.IsErrUserHasOrgs(err) || packages_model.IsErrUserOwnPackages(err) { log.Warn("Inactive user %q has repositories, organizations or packages, skipping deletion: %v", u.Name, err) continue } diff --git a/services/user/user_test.go b/services/user/user_test.go index c668b005c5..162a735cd4 100644 --- a/services/user/user_test.go +++ b/services/user/user_test.go @@ -9,7 +9,6 @@ import ( "testing" "time" - "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" @@ -37,7 +36,7 @@ func TestDeleteUser(t *testing.T) { if len(ownedRepos) > 0 { err := DeleteUser(db.DefaultContext, user, false) assert.Error(t, err) - assert.True(t, models.IsErrUserOwnRepos(err)) + assert.True(t, repo_model.IsErrUserOwnRepos(err)) return } diff --git a/templates/base/head_navbar.tmpl b/templates/base/head_navbar.tmpl index 951ee590d1..ed7a8d6f24 100644 --- a/templates/base/head_navbar.tmpl +++ b/templates/base/head_navbar.tmpl @@ -11,9 +11,9 @@ -