From 716fcfcf72be6af854d800f3e2c885b9806577e6 Mon Sep 17 00:00:00 2001 From: zeripath Date: Tue, 18 Oct 2022 06:50:37 +0100 Subject: [PATCH] Make every not exist error unwrappable to a fs.ErrNotExist (#20891) A lot of our code is repeatedly testing if individual errors are specific types of Not Exist errors. This is repetitative and unnecesary. `Unwrap() error` provides a common way of labelling an error as a NotExist error and we can/should use this. This PR has chosen to use the common `io/fs` errors e.g. `fs.ErrNotExist` for our errors. This is in some ways not completely correct as these are not filesystem errors but it seems like a reasonable thing to do and would allow us to simplify a lot of our code to `errors.Is(err, fs.ErrNotExist)` instead of `package.IsErr...NotExist(err)` I am open to suggestions to use a different base error - perhaps `models/db.ErrNotExist` if that would be felt to be better. Signed-off-by: Andrew Thornton Co-authored-by: delvh --- models/activities/notification.go | 2 +- models/admin/task.go | 4 ++ models/asymkey/error.go | 54 ++++++++++++++++++- models/auth/oauth2.go | 12 ++++- models/auth/source.go | 11 ++++ models/auth/token.go | 8 +++ models/auth/twofactor.go | 5 ++ models/auth/webauthn.go | 6 +++ models/db/engine.go | 2 +- models/db/error.go | 20 ++++++- models/db/name.go | 22 ++++++-- models/error.go | 85 +++++++++++++++++++++++++++++- models/foreignreference/error.go | 10 ++++ models/git/lfs.go | 20 ++++++- models/issues/comment.go | 5 ++ models/issues/content_history.go | 5 ++ models/issues/dependency.go | 13 +++++ models/issues/issue.go | 4 ++ models/issues/label.go | 12 +++++ models/issues/milestone.go | 5 ++ models/issues/pull.go | 8 +++ models/issues/reaction.go | 9 ++++ models/issues/review.go | 8 +++ models/issues/stopwatch.go | 8 +++ models/issues/tracked_time.go | 6 +-- models/organization/org.go | 9 ++++ models/organization/team.go | 9 ++++ models/project/project.go | 8 +++ models/pull/automerge.go | 2 +- models/repo/attachment.go | 5 ++ models/repo/redirect.go | 5 ++ models/repo/release.go | 8 +++ models/repo/repo.go | 9 ++++ models/repo/repo_unit.go | 5 ++ models/repo/topic.go | 5 ++ models/repo/update.go | 12 +++++ models/repo/upload.go | 4 ++ models/repo/wiki.go | 12 +++++ models/user/email_address.go | 20 +++++++ models/user/error.go | 22 ++++++++ models/user/external_login_user.go | 9 ++++ models/user/openid.go | 5 ++ models/user/redirect.go | 5 ++ models/webhook/webhook.go | 8 +++ modules/git/error.go | 10 ++++ modules/translation/i18n/errors.go | 8 +-- modules/util/error.go | 37 +++++++++++++ services/repository/fork.go | 4 ++ 48 files changed, 545 insertions(+), 20 deletions(-) create mode 100644 modules/util/error.go diff --git a/models/activities/notification.go b/models/activities/notification.go index 2f21dc74d1..0a61088167 100644 --- a/models/activities/notification.go +++ b/models/activities/notification.go @@ -806,7 +806,7 @@ func getNotificationByID(ctx context.Context, notificationID int64) (*Notificati } if !ok { - return nil, db.ErrNotExist{ID: notificationID} + return nil, db.ErrNotExist{Resource: "notification", ID: notificationID} } return notification, nil diff --git a/models/admin/task.go b/models/admin/task.go index 07eb61decc..4fa0f10394 100644 --- a/models/admin/task.go +++ b/models/admin/task.go @@ -167,6 +167,10 @@ func (err ErrTaskDoesNotExist) Error() string { err.ID, err.RepoID, err.Type) } +func (err ErrTaskDoesNotExist) Unwrap() error { + return util.ErrNotExist +} + // GetMigratingTask returns the migrating task by repo's id func GetMigratingTask(repoID int64) (*Task, error) { task := Task{ diff --git a/models/asymkey/error.go b/models/asymkey/error.go index 5d2be1f289..3ddeb0498a 100644 --- a/models/asymkey/error.go +++ b/models/asymkey/error.go @@ -4,7 +4,11 @@ package asymkey -import "fmt" +import ( + "fmt" + + "code.gitea.io/gitea/modules/util" +) // ErrKeyUnableVerify represents a "KeyUnableVerify" kind of error. type ErrKeyUnableVerify struct { @@ -36,6 +40,10 @@ func (err ErrKeyNotExist) Error() string { return fmt.Sprintf("public key does not exist [id: %d]", err.ID) } +func (err ErrKeyNotExist) Unwrap() error { + return util.ErrNotExist +} + // ErrKeyAlreadyExist represents a "KeyAlreadyExist" kind of error. type ErrKeyAlreadyExist struct { OwnerID int64 @@ -54,6 +62,10 @@ func (err ErrKeyAlreadyExist) Error() string { err.OwnerID, err.Fingerprint, err.Content) } +func (err ErrKeyAlreadyExist) Unwrap() error { + return util.ErrAlreadyExist +} + // ErrKeyNameAlreadyUsed represents a "KeyNameAlreadyUsed" kind of error. type ErrKeyNameAlreadyUsed struct { OwnerID int64 @@ -70,6 +82,10 @@ func (err ErrKeyNameAlreadyUsed) Error() string { return fmt.Sprintf("public key already exists [owner_id: %d, name: %s]", err.OwnerID, err.Name) } +func (err ErrKeyNameAlreadyUsed) Unwrap() error { + return util.ErrAlreadyExist +} + // ErrGPGNoEmailFound represents a "ErrGPGNoEmailFound" kind of error. type ErrGPGNoEmailFound struct { FailedEmails []string @@ -132,6 +148,10 @@ func (err ErrGPGKeyNotExist) Error() string { return fmt.Sprintf("public gpg key does not exist [id: %d]", err.ID) } +func (err ErrGPGKeyNotExist) Unwrap() error { + return util.ErrNotExist +} + // ErrGPGKeyImportNotExist represents a "GPGKeyImportNotExist" kind of error. type ErrGPGKeyImportNotExist struct { ID string @@ -147,6 +167,10 @@ func (err ErrGPGKeyImportNotExist) Error() string { return fmt.Sprintf("public gpg key import does not exist [id: %s]", err.ID) } +func (err ErrGPGKeyImportNotExist) Unwrap() error { + return util.ErrNotExist +} + // ErrGPGKeyIDAlreadyUsed represents a "GPGKeyIDAlreadyUsed" kind of error. type ErrGPGKeyIDAlreadyUsed struct { KeyID string @@ -162,6 +186,10 @@ func (err ErrGPGKeyIDAlreadyUsed) Error() string { return fmt.Sprintf("public key already exists [key_id: %s]", err.KeyID) } +func (err ErrGPGKeyIDAlreadyUsed) Unwrap() error { + return util.ErrAlreadyExist +} + // ErrGPGKeyAccessDenied represents a "GPGKeyAccessDenied" kind of Error. type ErrGPGKeyAccessDenied struct { UserID int64 @@ -180,6 +208,10 @@ func (err ErrGPGKeyAccessDenied) Error() string { err.UserID, err.KeyID) } +func (err ErrGPGKeyAccessDenied) Unwrap() error { + return util.ErrPermissionDenied +} + // ErrKeyAccessDenied represents a "KeyAccessDenied" kind of error. type ErrKeyAccessDenied struct { UserID int64 @@ -198,6 +230,10 @@ func (err ErrKeyAccessDenied) Error() string { err.UserID, err.KeyID, err.Note) } +func (err ErrKeyAccessDenied) Unwrap() error { + return util.ErrPermissionDenied +} + // ErrDeployKeyNotExist represents a "DeployKeyNotExist" kind of error. type ErrDeployKeyNotExist struct { ID int64 @@ -215,6 +251,10 @@ func (err ErrDeployKeyNotExist) Error() string { return fmt.Sprintf("Deploy key does not exist [id: %d, key_id: %d, repo_id: %d]", err.ID, err.KeyID, err.RepoID) } +func (err ErrDeployKeyNotExist) Unwrap() error { + return util.ErrNotExist +} + // ErrDeployKeyAlreadyExist represents a "DeployKeyAlreadyExist" kind of error. type ErrDeployKeyAlreadyExist struct { KeyID int64 @@ -231,6 +271,10 @@ func (err ErrDeployKeyAlreadyExist) Error() string { return fmt.Sprintf("public key already exists [key_id: %d, repo_id: %d]", err.KeyID, err.RepoID) } +func (err ErrDeployKeyAlreadyExist) Unwrap() error { + return util.ErrAlreadyExist +} + // ErrDeployKeyNameAlreadyUsed represents a "DeployKeyNameAlreadyUsed" kind of error. type ErrDeployKeyNameAlreadyUsed struct { RepoID int64 @@ -247,6 +291,10 @@ func (err ErrDeployKeyNameAlreadyUsed) Error() string { return fmt.Sprintf("public key with name already exists [repo_id: %d, name: %s]", err.RepoID, err.Name) } +func (err ErrDeployKeyNameAlreadyUsed) Unwrap() error { + return util.ErrNotExist +} + // ErrSSHInvalidTokenSignature represents a "ErrSSHInvalidTokenSignature" kind of error. type ErrSSHInvalidTokenSignature struct { Wrapped error @@ -262,3 +310,7 @@ func IsErrSSHInvalidTokenSignature(err error) bool { func (err ErrSSHInvalidTokenSignature) Error() string { return "the provided signature does not sign the token with the provided key" } + +func (err ErrSSHInvalidTokenSignature) Unwrap() error { + return util.ErrInvalidArgument +} diff --git a/models/auth/oauth2.go b/models/auth/oauth2.go index abcd9e1ca6..9fdce24253 100644 --- a/models/auth/oauth2.go +++ b/models/auth/oauth2.go @@ -486,7 +486,7 @@ type ErrOAuthClientIDInvalid struct { ClientID string } -// IsErrOauthClientIDInvalid checks if an error is a ErrReviewNotExist. +// IsErrOauthClientIDInvalid checks if an error is a ErrOAuthClientIDInvalid. func IsErrOauthClientIDInvalid(err error) bool { _, ok := err.(ErrOAuthClientIDInvalid) return ok @@ -497,6 +497,11 @@ func (err ErrOAuthClientIDInvalid) Error() string { return fmt.Sprintf("Client ID invalid [Client ID: %s]", err.ClientID) } +// Unwrap unwraps this as a ErrNotExist err +func (err ErrOAuthClientIDInvalid) Unwrap() error { + return util.ErrNotExist +} + // ErrOAuthApplicationNotFound will be thrown if id cannot be found type ErrOAuthApplicationNotFound struct { ID int64 @@ -513,6 +518,11 @@ func (err ErrOAuthApplicationNotFound) Error() string { return fmt.Sprintf("OAuth application not found [ID: %d]", err.ID) } +// Unwrap unwraps this as a ErrNotExist err +func (err ErrOAuthApplicationNotFound) Unwrap() error { + return util.ErrNotExist +} + // GetActiveOAuth2ProviderSources returns all actived LoginOAuth2 sources func GetActiveOAuth2ProviderSources() ([]*Source, error) { sources := make([]*Source, 0, 1) diff --git a/models/auth/source.go b/models/auth/source.go index 6f4f5addcb..f8be5398ae 100644 --- a/models/auth/source.go +++ b/models/auth/source.go @@ -12,6 +12,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" "xorm.io/xorm" "xorm.io/xorm/convert" @@ -366,6 +367,11 @@ func (err ErrSourceNotExist) Error() string { return fmt.Sprintf("login source does not exist [id: %d]", err.ID) } +// Unwrap unwraps this as a ErrNotExist err +func (err ErrSourceNotExist) Unwrap() error { + return util.ErrNotExist +} + // ErrSourceAlreadyExist represents a "SourceAlreadyExist" kind of error. type ErrSourceAlreadyExist struct { Name string @@ -381,6 +387,11 @@ func (err ErrSourceAlreadyExist) Error() string { return fmt.Sprintf("login source already exists [name: %s]", err.Name) } +// Unwrap unwraps this as a ErrExist err +func (err ErrSourceAlreadyExist) Unwrap() error { + return util.ErrAlreadyExist +} + // ErrSourceInUse represents a "SourceInUse" kind of error. type ErrSourceInUse struct { ID int64 diff --git a/models/auth/token.go b/models/auth/token.go index 01654f2901..3afef832da 100644 --- a/models/auth/token.go +++ b/models/auth/token.go @@ -35,6 +35,10 @@ func (err ErrAccessTokenNotExist) Error() string { return fmt.Sprintf("access token does not exist [sha: %s]", err.Token) } +func (err ErrAccessTokenNotExist) Unwrap() error { + return util.ErrNotExist +} + // ErrAccessTokenEmpty represents a "AccessTokenEmpty" kind of error. type ErrAccessTokenEmpty struct{} @@ -48,6 +52,10 @@ func (err ErrAccessTokenEmpty) Error() string { return "access token is empty" } +func (err ErrAccessTokenEmpty) Unwrap() error { + return util.ErrInvalidArgument +} + var successfulAccessTokenCache *lru.Cache // AccessToken represents a personal access token. diff --git a/models/auth/twofactor.go b/models/auth/twofactor.go index c5bd972f91..736d4c340c 100644 --- a/models/auth/twofactor.go +++ b/models/auth/twofactor.go @@ -41,6 +41,11 @@ func (err ErrTwoFactorNotEnrolled) Error() string { return fmt.Sprintf("user not enrolled in 2FA [uid: %d]", err.UID) } +// Unwrap unwraps this as a ErrNotExist err +func (err ErrTwoFactorNotEnrolled) Unwrap() error { + return util.ErrNotExist +} + // TwoFactor represents a two-factor authentication token. type TwoFactor struct { ID int64 `xorm:"pk autoincr"` diff --git a/models/auth/webauthn.go b/models/auth/webauthn.go index d3062342f5..1575b6cbab 100644 --- a/models/auth/webauthn.go +++ b/models/auth/webauthn.go @@ -11,6 +11,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" "github.com/duo-labs/webauthn/webauthn" "xorm.io/xorm" @@ -29,6 +30,11 @@ func (err ErrWebAuthnCredentialNotExist) Error() string { return fmt.Sprintf("WebAuthn credential does not exist [credential_id: %x]", err.CredentialID) } +// Unwrap unwraps this as a ErrNotExist err +func (err ErrWebAuthnCredentialNotExist) Unwrap() error { + return util.ErrNotExist +} + // IsErrWebAuthnCredentialNotExist checks if an error is a ErrWebAuthnCredentialNotExist. func IsErrWebAuthnCredentialNotExist(err error) bool { _, ok := err.(ErrWebAuthnCredentialNotExist) diff --git a/models/db/engine.go b/models/db/engine.go index 2c329300e3..f0c9ec46e9 100755 --- a/models/db/engine.go +++ b/models/db/engine.go @@ -225,7 +225,7 @@ func NamesToBean(names ...string) ([]interface{}, error) { for _, name := range names { bean, ok := beanMap[strings.ToLower(strings.TrimSpace(name))] if !ok { - return nil, fmt.Errorf("No table found that matches: %s", name) + return nil, fmt.Errorf("no table found that matches: %s", name) } if !gotBean[bean] { beans = append(beans, bean) diff --git a/models/db/error.go b/models/db/error.go index 6557229943..9577fa55db 100644 --- a/models/db/error.go +++ b/models/db/error.go @@ -6,6 +6,8 @@ package db import ( "fmt" + + "code.gitea.io/gitea/modules/util" ) // ErrCancelled represents an error due to context cancellation @@ -45,7 +47,8 @@ func (err ErrSSHDisabled) Error() string { // ErrNotExist represents a non-exist error. type ErrNotExist struct { - ID int64 + Resource string + ID int64 } // IsErrNotExist checks if an error is an ErrNotExist @@ -55,5 +58,18 @@ func IsErrNotExist(err error) bool { } func (err ErrNotExist) Error() string { - return fmt.Sprintf("record does not exist [id: %d]", err.ID) + name := "record" + if err.Resource != "" { + name = err.Resource + } + + if err.ID != 0 { + return fmt.Sprintf("%s does not exist [id: %d]", name, err.ID) + } + return fmt.Sprintf("%s does not exist", name) +} + +// Unwrap unwraps this as a ErrNotExist err +func (err ErrNotExist) Unwrap() error { + return util.ErrNotExist } diff --git a/models/db/name.go b/models/db/name.go index 9c9d18f184..a05d1a789b 100644 --- a/models/db/name.go +++ b/models/db/name.go @@ -5,16 +5,17 @@ package db import ( - "errors" "fmt" "regexp" "strings" "unicode/utf8" + + "code.gitea.io/gitea/modules/util" ) var ( // ErrNameEmpty name is empty error - ErrNameEmpty = errors.New("Name is empty") + ErrNameEmpty = util.SilentWrap{Message: "name is empty", Err: util.ErrInvalidArgument} // AlphaDashDotPattern characters prohibited in a user name (anything except A-Za-z0-9_.-) AlphaDashDotPattern = regexp.MustCompile(`[^\w-\.]`) @@ -35,6 +36,11 @@ func (err ErrNameReserved) Error() string { return fmt.Sprintf("name is reserved [name: %s]", err.Name) } +// Unwrap unwraps this as a ErrInvalid err +func (err ErrNameReserved) Unwrap() error { + return util.ErrInvalidArgument +} + // ErrNamePatternNotAllowed represents a "pattern not allowed" error. type ErrNamePatternNotAllowed struct { Pattern string @@ -50,6 +56,11 @@ func (err ErrNamePatternNotAllowed) Error() string { return fmt.Sprintf("name pattern is not allowed [pattern: %s]", err.Pattern) } +// Unwrap unwraps this as a ErrInvalid err +func (err ErrNamePatternNotAllowed) Unwrap() error { + return util.ErrInvalidArgument +} + // ErrNameCharsNotAllowed represents a "character not allowed in name" error. type ErrNameCharsNotAllowed struct { Name string @@ -62,7 +73,12 @@ func IsErrNameCharsNotAllowed(err error) bool { } func (err ErrNameCharsNotAllowed) Error() string { - return fmt.Sprintf("User name is invalid [%s]: must be valid alpha or numeric or dash(-_) or dot characters", err.Name) + return fmt.Sprintf("name is invalid [%s]: must be valid alpha or numeric or dash(-_) or dot characters", err.Name) +} + +// Unwrap unwraps this as a ErrInvalid err +func (err ErrNameCharsNotAllowed) Unwrap() error { + return util.ErrInvalidArgument } // IsUsableName checks if name is reserved or pattern of name is not allowed diff --git a/models/error.go b/models/error.go index 873ed0ceaa..f4c4bc8f67 100644 --- a/models/error.go +++ b/models/error.go @@ -10,6 +10,7 @@ import ( 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. @@ -63,8 +64,8 @@ type ErrNoPendingRepoTransfer struct { RepoID int64 } -func (e ErrNoPendingRepoTransfer) Error() string { - return fmt.Sprintf("repository doesn't have a pending transfer [repo_id: %d]", e.RepoID) +func (err ErrNoPendingRepoTransfer) Error() string { + return fmt.Sprintf("repository doesn't have a pending transfer [repo_id: %d]", err.RepoID) } // IsErrNoPendingTransfer is an error type when a repository has no pending @@ -74,6 +75,10 @@ func IsErrNoPendingTransfer(err error) bool { return ok } +func (err ErrNoPendingRepoTransfer) Unwrap() error { + return util.ErrNotExist +} + // ErrRepoTransferInProgress represents the state of a repository that has an // ongoing transfer type ErrRepoTransferInProgress struct { @@ -91,6 +96,10 @@ func (err ErrRepoTransferInProgress) Error() string { return fmt.Sprintf("repository is already being transferred [uname: %s, name: %s]", err.Uname, err.Name) } +func (err ErrRepoTransferInProgress) Unwrap() error { + return util.ErrAlreadyExist +} + // ErrInvalidCloneAddr represents a "InvalidCloneAddr" kind of error. type ErrInvalidCloneAddr struct { Host string @@ -124,6 +133,10 @@ func (err *ErrInvalidCloneAddr) Error() string { 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 @@ -139,6 +152,10 @@ 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 @@ -154,6 +171,10 @@ 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 @@ -169,6 +190,10 @@ 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 @@ -184,6 +209,10 @@ 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 @@ -200,6 +229,10 @@ 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 @@ -215,6 +248,10 @@ 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 @@ -230,6 +267,10 @@ 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 @@ -251,6 +292,10 @@ func (err ErrFilePathInvalid) Error() string { 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 @@ -270,6 +315,10 @@ func (err ErrFilePathProtected) Error() string { return fmt.Sprintf("path is protected and can not be changed [path: %s]", err.Path) } +func (err ErrFilePathProtected) Unwrap() error { + return util.ErrPermissionDenied +} + // __________ .__ // \______ \____________ ____ ____ | |__ // | | _/\_ __ \__ \ / \_/ ___\| | \ @@ -292,6 +341,10 @@ func (err ErrBranchDoesNotExist) Error() string { return fmt.Sprintf("branch does not exist [name: %s]", err.BranchName) } +func (err ErrBranchDoesNotExist) Unwrap() error { + return util.ErrNotExist +} + // ErrBranchAlreadyExists represents an error that branch with such name already exists. type ErrBranchAlreadyExists struct { BranchName string @@ -307,6 +360,10 @@ func (err ErrBranchAlreadyExists) Error() string { return fmt.Sprintf("branch already exists [name: %s]", err.BranchName) } +func (err ErrBranchAlreadyExists) Unwrap() error { + return util.ErrAlreadyExist +} + // ErrBranchNameConflict represents an error that branch name conflicts with other branch. type ErrBranchNameConflict struct { BranchName string @@ -322,6 +379,10 @@ func (err ErrBranchNameConflict) Error() string { return fmt.Sprintf("branch conflicts with existing branch [name: %s]", err.BranchName) } +func (err ErrBranchNameConflict) Unwrap() error { + return util.ErrAlreadyExist +} + // ErrBranchesEqual represents an error that branch name conflicts with other branch. type ErrBranchesEqual struct { BaseBranchName string @@ -338,6 +399,10 @@ func (err ErrBranchesEqual) Error() string { return fmt.Sprintf("branches are equal [head: %sm base: %s]", err.HeadBranchName, err.BaseBranchName) } +func (err ErrBranchesEqual) Unwrap() error { + return util.ErrInvalidArgument +} + // ErrDisallowedToMerge represents an error that a branch is protected and the current user is not allowed to modify it. type ErrDisallowedToMerge struct { Reason string @@ -353,6 +418,10 @@ 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 @@ -368,6 +437,10 @@ 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 @@ -400,6 +473,10 @@ 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 @@ -446,6 +523,10 @@ func (err ErrInvalidMergeStyle) Error() string { 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 diff --git a/models/foreignreference/error.go b/models/foreignreference/error.go index d783a08730..a1db773cd2 100644 --- a/models/foreignreference/error.go +++ b/models/foreignreference/error.go @@ -6,6 +6,8 @@ package foreignreference import ( "fmt" + + "code.gitea.io/gitea/modules/util" ) // ErrLocalIndexNotExist represents a "LocalIndexNotExist" kind of error. @@ -25,6 +27,10 @@ func (err ErrLocalIndexNotExist) Error() string { return fmt.Sprintf("repository %d has no LocalIndex for ForeignIndex %d of type %s", err.RepoID, err.ForeignIndex, err.Type) } +func (err ErrLocalIndexNotExist) Unwrap() error { + return util.ErrNotExist +} + // ErrForeignIndexNotExist represents a "ForeignIndexNotExist" kind of error. type ErrForeignIndexNotExist struct { RepoID int64 @@ -41,3 +47,7 @@ func IsErrForeignIndexNotExist(err error) bool { func (err ErrForeignIndexNotExist) Error() string { return fmt.Sprintf("repository %d has no ForeignIndex for LocalIndex %d of type %s", err.RepoID, err.LocalIndex, err.Type) } + +func (err ErrForeignIndexNotExist) Unwrap() error { + return util.ErrNotExist +} diff --git a/models/git/lfs.go b/models/git/lfs.go index 179da3120a..1dab31d5f9 100644 --- a/models/git/lfs.go +++ b/models/git/lfs.go @@ -6,7 +6,6 @@ package git import ( "context" - "errors" "fmt" "code.gitea.io/gitea/models/db" @@ -17,6 +16,7 @@ import ( "code.gitea.io/gitea/modules/lfs" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" "xorm.io/builder" ) @@ -38,6 +38,10 @@ func (err ErrLFSLockNotExist) Error() string { return fmt.Sprintf("lfs lock does not exist [id: %d, rid: %d, path: %s]", err.ID, err.RepoID, err.Path) } +func (err ErrLFSLockNotExist) Unwrap() error { + return util.ErrNotExist +} + // ErrLFSUnauthorizedAction represents a "LFSUnauthorizedAction" kind of error. type ErrLFSUnauthorizedAction struct { RepoID int64 @@ -58,6 +62,10 @@ func (err ErrLFSUnauthorizedAction) Error() string { return fmt.Sprintf("User %s doesn't have read access for lfs lock [rid: %d]", err.UserName, err.RepoID) } +func (err ErrLFSUnauthorizedAction) Unwrap() error { + return util.ErrPermissionDenied +} + // ErrLFSLockAlreadyExist represents a "LFSLockAlreadyExist" kind of error. type ErrLFSLockAlreadyExist struct { RepoID int64 @@ -74,6 +82,10 @@ func (err ErrLFSLockAlreadyExist) Error() string { return fmt.Sprintf("lfs lock already exists [rid: %d, path: %s]", err.RepoID, err.Path) } +func (err ErrLFSLockAlreadyExist) Unwrap() error { + return util.ErrAlreadyExist +} + // ErrLFSFileLocked represents a "LFSFileLocked" kind of error. type ErrLFSFileLocked struct { RepoID int64 @@ -91,6 +103,10 @@ func (err ErrLFSFileLocked) Error() string { return fmt.Sprintf("File is lfs locked [repo: %d, locked by: %s, path: %s]", err.RepoID, err.UserName, err.Path) } +func (err ErrLFSFileLocked) Unwrap() error { + return util.ErrPermissionDenied +} + // LFSMetaObject stores metadata for LFS tracked files. type LFSMetaObject struct { ID int64 `xorm:"pk autoincr"` @@ -114,7 +130,7 @@ type LFSTokenResponse struct { // ErrLFSObjectNotExist is returned from lfs models functions in order // to differentiate between database and missing object errors. -var ErrLFSObjectNotExist = errors.New("LFS Meta object does not exist") +var ErrLFSObjectNotExist = db.ErrNotExist{Resource: "LFS Meta object"} // NewLFSMetaObject stores a given populated LFSMetaObject structure in the database // if it is not already present. diff --git a/models/issues/comment.go b/models/issues/comment.go index a71afda9e0..9ab6cab7d0 100644 --- a/models/issues/comment.go +++ b/models/issues/comment.go @@ -28,6 +28,7 @@ import ( "code.gitea.io/gitea/modules/references" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" "xorm.io/builder" "xorm.io/xorm" @@ -49,6 +50,10 @@ func (err ErrCommentNotExist) Error() string { return fmt.Sprintf("comment does not exist [id: %d, issue_id: %d]", err.ID, err.IssueID) } +func (err ErrCommentNotExist) Unwrap() error { + return util.ErrNotExist +} + // CommentType defines whether a comment is just a simple comment, an action (like close) or a reference. type CommentType int diff --git a/models/issues/content_history.go b/models/issues/content_history.go index 3e321784bd..f5cfa65b8f 100644 --- a/models/issues/content_history.go +++ b/models/issues/content_history.go @@ -12,6 +12,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" "xorm.io/builder" ) @@ -201,6 +202,10 @@ func (err ErrIssueContentHistoryNotExist) Error() string { return fmt.Sprintf("issue content history does not exist [id: %d]", err.ID) } +func (err ErrIssueContentHistoryNotExist) Unwrap() error { + return util.ErrNotExist +} + // GetIssueContentHistoryByID get issue content history func GetIssueContentHistoryByID(dbCtx context.Context, id int64) (*ContentHistory, error) { h := &ContentHistory{} diff --git a/models/issues/dependency.go b/models/issues/dependency.go index d664c0758e..4754ed0f5f 100644 --- a/models/issues/dependency.go +++ b/models/issues/dependency.go @@ -11,6 +11,7 @@ import ( "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" ) // ErrDependencyExists represents a "DependencyAlreadyExists" kind of error. @@ -29,6 +30,10 @@ func (err ErrDependencyExists) Error() string { return fmt.Sprintf("issue dependency does already exist [issue id: %d, dependency id: %d]", err.IssueID, err.DependencyID) } +func (err ErrDependencyExists) Unwrap() error { + return util.ErrAlreadyExist +} + // ErrDependencyNotExists represents a "DependencyAlreadyExists" kind of error. type ErrDependencyNotExists struct { IssueID int64 @@ -45,6 +50,10 @@ func (err ErrDependencyNotExists) Error() string { return fmt.Sprintf("issue dependency does not exist [issue id: %d, dependency id: %d]", err.IssueID, err.DependencyID) } +func (err ErrDependencyNotExists) Unwrap() error { + return util.ErrNotExist +} + // ErrCircularDependency represents a "DependencyCircular" kind of error. type ErrCircularDependency struct { IssueID int64 @@ -91,6 +100,10 @@ func (err ErrUnknownDependencyType) Error() string { return fmt.Sprintf("unknown dependency type [type: %d]", err.Type) } +func (err ErrUnknownDependencyType) Unwrap() error { + return util.ErrInvalidArgument +} + // IssueDependency represents an issue dependency type IssueDependency struct { ID int64 `xorm:"pk autoincr"` diff --git a/models/issues/issue.go b/models/issues/issue.go index 786c969522..e56e43bd1a 100644 --- a/models/issues/issue.go +++ b/models/issues/issue.go @@ -52,6 +52,10 @@ func (err ErrIssueNotExist) Error() string { return fmt.Sprintf("issue does not exist [id: %d, repo_id: %d, index: %d]", err.ID, err.RepoID, err.Index) } +func (err ErrIssueNotExist) Unwrap() error { + return util.ErrNotExist +} + // ErrIssueIsClosed represents a "IssueIsClosed" kind of error. type ErrIssueIsClosed struct { ID int64 diff --git a/models/issues/label.go b/models/issues/label.go index 667a608687..be97454e26 100644 --- a/models/issues/label.go +++ b/models/issues/label.go @@ -38,6 +38,10 @@ func (err ErrRepoLabelNotExist) Error() string { return fmt.Sprintf("label does not exist [label_id: %d, repo_id: %d]", err.LabelID, err.RepoID) } +func (err ErrRepoLabelNotExist) Unwrap() error { + return util.ErrNotExist +} + // ErrOrgLabelNotExist represents a "OrgLabelNotExist" kind of error. type ErrOrgLabelNotExist struct { LabelID int64 @@ -54,6 +58,10 @@ func (err ErrOrgLabelNotExist) Error() string { return fmt.Sprintf("label does not exist [label_id: %d, org_id: %d]", err.LabelID, err.OrgID) } +func (err ErrOrgLabelNotExist) Unwrap() error { + return util.ErrNotExist +} + // ErrLabelNotExist represents a "LabelNotExist" kind of error. type ErrLabelNotExist struct { LabelID int64 @@ -69,6 +77,10 @@ func (err ErrLabelNotExist) Error() string { return fmt.Sprintf("label does not exist [label_id: %d]", err.LabelID) } +func (err ErrLabelNotExist) Unwrap() error { + return util.ErrNotExist +} + // LabelColorPattern is a regexp witch can validate LabelColor var LabelColorPattern = regexp.MustCompile("^#?(?:[0-9a-fA-F]{6}|[0-9a-fA-F]{3})$") diff --git a/models/issues/milestone.go b/models/issues/milestone.go index 1021938b20..3ccade7411 100644 --- a/models/issues/milestone.go +++ b/models/issues/milestone.go @@ -15,6 +15,7 @@ import ( "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" "xorm.io/builder" ) @@ -39,6 +40,10 @@ func (err ErrMilestoneNotExist) Error() string { return fmt.Sprintf("milestone does not exist [id: %d, repo_id: %d]", err.ID, err.RepoID) } +func (err ErrMilestoneNotExist) Unwrap() error { + return util.ErrNotExist +} + // Milestone represents a milestone of repository. type Milestone struct { ID int64 `xorm:"pk autoincr"` diff --git a/models/issues/pull.go b/models/issues/pull.go index 69259c269f..18b67eb305 100644 --- a/models/issues/pull.go +++ b/models/issues/pull.go @@ -46,6 +46,10 @@ func (err ErrPullRequestNotExist) Error() string { err.ID, err.IssueID, err.HeadRepoID, err.BaseRepoID, err.HeadBranch, err.BaseBranch) } +func (err ErrPullRequestNotExist) Unwrap() error { + return util.ErrNotExist +} + // ErrPullRequestAlreadyExists represents a "PullRequestAlreadyExists"-error type ErrPullRequestAlreadyExists struct { ID int64 @@ -68,6 +72,10 @@ func (err ErrPullRequestAlreadyExists) Error() string { err.ID, err.IssueID, err.HeadRepoID, err.BaseRepoID, err.HeadBranch, err.BaseBranch) } +func (err ErrPullRequestAlreadyExists) Unwrap() error { + return util.ErrAlreadyExist +} + // ErrPullRequestHeadRepoMissing represents a "ErrPullRequestHeadRepoMissing" error type ErrPullRequestHeadRepoMissing struct { ID int64 diff --git a/models/issues/reaction.go b/models/issues/reaction.go index ccda10be2c..02cffad3ba 100644 --- a/models/issues/reaction.go +++ b/models/issues/reaction.go @@ -15,6 +15,7 @@ import ( "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" "xorm.io/builder" ) @@ -34,6 +35,10 @@ func (err ErrForbiddenIssueReaction) Error() string { return fmt.Sprintf("'%s' is not an allowed reaction", err.Reaction) } +func (err ErrForbiddenIssueReaction) Unwrap() error { + return util.ErrPermissionDenied +} + // ErrReactionAlreadyExist is used when a existing reaction was try to created type ErrReactionAlreadyExist struct { Reaction string @@ -49,6 +54,10 @@ func (err ErrReactionAlreadyExist) Error() string { return fmt.Sprintf("reaction '%s' already exists", err.Reaction) } +func (err ErrReactionAlreadyExist) Unwrap() error { + return util.ErrAlreadyExist +} + // Reaction represents a reactions on issues and comments. type Reaction struct { ID int64 `xorm:"pk autoincr"` diff --git a/models/issues/review.go b/models/issues/review.go index 5835900801..26fcea9eef 100644 --- a/models/issues/review.go +++ b/models/issues/review.go @@ -39,6 +39,10 @@ func (err ErrReviewNotExist) Error() string { return fmt.Sprintf("review does not exist [id: %d]", err.ID) } +func (err ErrReviewNotExist) Unwrap() error { + return util.ErrNotExist +} + // ErrNotValidReviewRequest an not allowed review request modify type ErrNotValidReviewRequest struct { Reason string @@ -59,6 +63,10 @@ func (err ErrNotValidReviewRequest) Error() string { err.RepoID) } +func (err ErrNotValidReviewRequest) Unwrap() error { + return util.ErrInvalidArgument +} + // ReviewType defines the sort of feedback a review gives type ReviewType int diff --git a/models/issues/stopwatch.go b/models/issues/stopwatch.go index 0a7ad41f9c..a87fbfafa2 100644 --- a/models/issues/stopwatch.go +++ b/models/issues/stopwatch.go @@ -25,6 +25,10 @@ func (err ErrIssueStopwatchNotExist) Error() string { return fmt.Sprintf("issue stopwatch doesn't exist[uid: %d, issue_id: %d", err.UserID, err.IssueID) } +func (err ErrIssueStopwatchNotExist) Unwrap() error { + return util.ErrNotExist +} + // ErrIssueStopwatchAlreadyExist represents an error that stopwatch is already exist type ErrIssueStopwatchAlreadyExist struct { UserID int64 @@ -35,6 +39,10 @@ func (err ErrIssueStopwatchAlreadyExist) Error() string { return fmt.Sprintf("issue stopwatch already exists[uid: %d, issue_id: %d", err.UserID, err.IssueID) } +func (err ErrIssueStopwatchAlreadyExist) Unwrap() error { + return util.ErrAlreadyExist +} + // Stopwatch represents a stopwatch for time tracking. type Stopwatch struct { ID int64 `xorm:"pk autoincr"` diff --git a/models/issues/tracked_time.go b/models/issues/tracked_time.go index 9f8767362f..ca21eb5149 100644 --- a/models/issues/tracked_time.go +++ b/models/issues/tracked_time.go @@ -236,7 +236,7 @@ func DeleteIssueUserTimes(issue *Issue, user *user_model.User) error { return err } if removedTime == 0 { - return db.ErrNotExist{} + return db.ErrNotExist{Resource: "tracked_time"} } if err := issue.LoadRepo(ctx); err != nil { @@ -296,7 +296,7 @@ func deleteTimes(ctx context.Context, opts FindTrackedTimesOptions) (removedTime func deleteTime(ctx context.Context, t *TrackedTime) error { if t.Deleted { - return db.ErrNotExist{ID: t.ID} + return db.ErrNotExist{Resource: "tracked_time", ID: t.ID} } t.Deleted = true _, err := db.GetEngine(ctx).ID(t.ID).Cols("deleted").Update(t) @@ -310,7 +310,7 @@ func GetTrackedTimeByID(id int64) (*TrackedTime, error) { if err != nil { return nil, err } else if !has { - return nil, db.ErrNotExist{ID: id} + return nil, db.ErrNotExist{Resource: "tracked_time", ID: id} } return time, nil } diff --git a/models/organization/org.go b/models/organization/org.go index 044ea06563..fbbf6d04fa 100644 --- a/models/organization/org.go +++ b/models/organization/org.go @@ -18,6 +18,7 @@ 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" "xorm.io/builder" ) @@ -45,6 +46,10 @@ func (err ErrOrgNotExist) Error() string { return fmt.Sprintf("org does not exist [id: %d, name: %s]", err.ID, err.Name) } +func (err ErrOrgNotExist) Unwrap() error { + return util.ErrNotExist +} + // ErrLastOrgOwner represents a "LastOrgOwner" kind of error. type ErrLastOrgOwner struct { UID int64 @@ -73,6 +78,10 @@ func (err ErrUserNotAllowedCreateOrg) Error() string { return "user is not allowed to create organizations" } +func (err ErrUserNotAllowedCreateOrg) Unwrap() error { + return util.ErrPermissionDenied +} + // Organization represents an organization type Organization user_model.User diff --git a/models/organization/team.go b/models/organization/team.go index bd80b1a8c7..83e5bd6fe1 100644 --- a/models/organization/team.go +++ b/models/organization/team.go @@ -16,6 +16,7 @@ import ( "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/util" "xorm.io/builder" ) @@ -43,6 +44,10 @@ func (err ErrTeamAlreadyExist) Error() string { return fmt.Sprintf("team already exists [org_id: %d, name: %s]", err.OrgID, err.Name) } +func (err ErrTeamAlreadyExist) Unwrap() error { + return util.ErrAlreadyExist +} + // ErrTeamNotExist represents a "TeamNotExist" error type ErrTeamNotExist struct { OrgID int64 @@ -60,6 +65,10 @@ func (err ErrTeamNotExist) Error() string { return fmt.Sprintf("team does not exist [org_id %d, team_id %d, name: %s]", err.OrgID, err.TeamID, err.Name) } +func (err ErrTeamNotExist) Unwrap() error { + return util.ErrNotExist +} + // OwnerTeamName return the owner team name const OwnerTeamName = "Owners" diff --git a/models/project/project.go b/models/project/project.go index 86a77947d8..af2c8ac2af 100644 --- a/models/project/project.go +++ b/models/project/project.go @@ -55,6 +55,10 @@ func (err ErrProjectNotExist) Error() string { return fmt.Sprintf("projects does not exist [id: %d]", err.ID) } +func (err ErrProjectNotExist) Unwrap() error { + return util.ErrNotExist +} + // ErrProjectBoardNotExist represents a "ProjectBoardNotExist" kind of error. type ErrProjectBoardNotExist struct { BoardID int64 @@ -70,6 +74,10 @@ func (err ErrProjectBoardNotExist) Error() string { return fmt.Sprintf("project board does not exist [id: %d]", err.BoardID) } +func (err ErrProjectBoardNotExist) Unwrap() error { + return util.ErrNotExist +} + // Project represents a project board type Project struct { ID int64 `xorm:"pk autoincr"` diff --git a/models/pull/automerge.go b/models/pull/automerge.go index d0aca2e85f..16ab5af093 100644 --- a/models/pull/automerge.go +++ b/models/pull/automerge.go @@ -90,7 +90,7 @@ func DeleteScheduledAutoMerge(ctx context.Context, pullID int64) error { if err != nil { return err } else if !exist { - return db.ErrNotExist{ID: pullID} + return db.ErrNotExist{Resource: "auto_merge", ID: pullID} } _, err = db.GetEngine(ctx).ID(scheduledPRM.ID).Delete(&AutoMerge{}) diff --git a/models/repo/attachment.go b/models/repo/attachment.go index afec78a425..5d4e11ae72 100644 --- a/models/repo/attachment.go +++ b/models/repo/attachment.go @@ -14,6 +14,7 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" ) // Attachment represent a attachment of issue/comment/release. @@ -83,6 +84,10 @@ func (err ErrAttachmentNotExist) Error() string { return fmt.Sprintf("attachment does not exist [id: %d, uuid: %s]", err.ID, err.UUID) } +func (err ErrAttachmentNotExist) Unwrap() error { + return util.ErrNotExist +} + // GetAttachmentByID returns attachment by given id func GetAttachmentByID(ctx context.Context, id int64) (*Attachment, error) { attach := &Attachment{} diff --git a/models/repo/redirect.go b/models/repo/redirect.go index 88fad6f3e3..f28220c2af 100644 --- a/models/repo/redirect.go +++ b/models/repo/redirect.go @@ -10,6 +10,7 @@ import ( "strings" "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/util" ) // ErrRedirectNotExist represents a "RedirectNotExist" kind of error. @@ -28,6 +29,10 @@ func (err ErrRedirectNotExist) Error() string { return fmt.Sprintf("repository redirect does not exist [uid: %d, name: %s]", err.OwnerID, err.RepoName) } +func (err ErrRedirectNotExist) Unwrap() error { + return util.ErrNotExist +} + // Redirect represents that a repo name should be redirected to another type Redirect struct { ID int64 `xorm:"pk autoincr"` diff --git a/models/repo/release.go b/models/repo/release.go index 2b484c9b84..2e7bc6d322 100644 --- a/models/repo/release.go +++ b/models/repo/release.go @@ -37,6 +37,10 @@ func (err ErrReleaseAlreadyExist) Error() string { return fmt.Sprintf("release tag already exist [tag_name: %s]", err.TagName) } +func (err ErrReleaseAlreadyExist) Unwrap() error { + return util.ErrAlreadyExist +} + // ErrReleaseNotExist represents a "ReleaseNotExist" kind of error. type ErrReleaseNotExist struct { ID int64 @@ -53,6 +57,10 @@ func (err ErrReleaseNotExist) Error() string { return fmt.Sprintf("release tag does not exist [id: %d, tag_name: %s]", err.ID, err.TagName) } +func (err ErrReleaseNotExist) Unwrap() error { + return util.ErrNotExist +} + // Release represents a release of repository. type Release struct { ID int64 `xorm:"pk autoincr"` diff --git a/models/repo/repo.go b/models/repo/repo.go index 4fd97dcd1b..ce698baaef 100644 --- a/models/repo/repo.go +++ b/models/repo/repo.go @@ -43,6 +43,10 @@ func (err ErrUserDoesNotHaveAccessToRepo) Error() string { return fmt.Sprintf("user doesn't have access to repo [user_id: %d, repo_name: %s]", err.UserID, err.RepoName) } +func (err ErrUserDoesNotHaveAccessToRepo) Unwrap() error { + return util.ErrPermissionDenied +} + var ( reservedRepoNames = []string{".", "..", "-"} reservedRepoPatterns = []string{"*.git", "*.wiki", "*.rss", "*.atom"} @@ -643,6 +647,11 @@ func (err ErrRepoNotExist) Error() string { err.ID, err.UID, err.OwnerName, err.Name) } +// Unwrap unwraps this error as a ErrNotExist error +func (err ErrRepoNotExist) Unwrap() error { + return util.ErrNotExist +} + // GetRepositoryByOwnerAndNameCtx returns the repository by given owner name and repo name func GetRepositoryByOwnerAndNameCtx(ctx context.Context, ownerName, repoName string) (*Repository, error) { var repo Repository diff --git a/models/repo/repo_unit.go b/models/repo/repo_unit.go index da3e19dece..dd85ca9186 100644 --- a/models/repo/repo_unit.go +++ b/models/repo/repo_unit.go @@ -13,6 +13,7 @@ import ( "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" "xorm.io/xorm" "xorm.io/xorm/convert" @@ -33,6 +34,10 @@ func (err ErrUnitTypeNotExist) Error() string { return fmt.Sprintf("Unit type does not exist: %s", err.UT.String()) } +func (err ErrUnitTypeNotExist) Unwrap() error { + return util.ErrNotExist +} + // RepoUnit describes all units of a repository type RepoUnit struct { //revive:disable-line:exported ID int64 diff --git a/models/repo/topic.go b/models/repo/topic.go index 7ba9a49e89..33bbb05af9 100644 --- a/models/repo/topic.go +++ b/models/repo/topic.go @@ -13,6 +13,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" "xorm.io/builder" ) @@ -55,6 +56,10 @@ func (err ErrTopicNotExist) Error() string { return fmt.Sprintf("topic is not exist [name: %s]", err.Name) } +func (err ErrTopicNotExist) Unwrap() error { + return util.ErrNotExist +} + // ValidateTopic checks a topic by length and match pattern rules func ValidateTopic(topic string) bool { return len(topic) <= 35 && topicPattern.MatchString(topic) diff --git a/models/repo/update.go b/models/repo/update.go index 07776ebc01..64a225d2f5 100644 --- a/models/repo/update.go +++ b/models/repo/update.go @@ -63,6 +63,10 @@ func (err ErrReachLimitOfRepo) Error() string { return fmt.Sprintf("user has reached maximum limit of repositories [limit: %d]", err.Limit) } +func (err ErrReachLimitOfRepo) Unwrap() error { + return util.ErrPermissionDenied +} + // ErrRepoAlreadyExist represents a "RepoAlreadyExist" kind of error. type ErrRepoAlreadyExist struct { Uname string @@ -79,6 +83,10 @@ func (err ErrRepoAlreadyExist) Error() string { return fmt.Sprintf("repository already exists [uname: %s, name: %s]", err.Uname, err.Name) } +func (err ErrRepoAlreadyExist) Unwrap() error { + return util.ErrAlreadyExist +} + // ErrRepoFilesAlreadyExist represents a "RepoFilesAlreadyExist" kind of error. type ErrRepoFilesAlreadyExist struct { Uname string @@ -95,6 +103,10 @@ func (err ErrRepoFilesAlreadyExist) Error() string { return fmt.Sprintf("repository files already exist [uname: %s, name: %s]", err.Uname, err.Name) } +func (err ErrRepoFilesAlreadyExist) Unwrap() error { + return util.ErrAlreadyExist +} + // CheckCreateRepository check if could created a repository func CheckCreateRepository(doer, u *user_model.User, name string, overwriteOrAdopt bool) error { if !doer.CanCreateRepo() { diff --git a/models/repo/upload.go b/models/repo/upload.go index 24544910b1..e3ce7e458f 100644 --- a/models/repo/upload.go +++ b/models/repo/upload.go @@ -36,6 +36,10 @@ func (err ErrUploadNotExist) Error() string { return fmt.Sprintf("attachment does not exist [id: %d, uuid: %s]", err.ID, err.UUID) } +func (err ErrUploadNotExist) Unwrap() error { + return util.ErrNotExist +} + // Upload represent a uploaded file to a repo to be deleted when moved type Upload struct { ID int64 `xorm:"pk autoincr"` diff --git a/models/repo/wiki.go b/models/repo/wiki.go index 72ec7c394b..c8886eaa34 100644 --- a/models/repo/wiki.go +++ b/models/repo/wiki.go @@ -30,6 +30,10 @@ func (err ErrWikiAlreadyExist) Error() string { return fmt.Sprintf("wiki page already exists [title: %s]", err.Title) } +func (err ErrWikiAlreadyExist) Unwrap() error { + return util.ErrAlreadyExist +} + // ErrWikiReservedName represents a reserved name error. type ErrWikiReservedName struct { Title string @@ -45,6 +49,10 @@ func (err ErrWikiReservedName) Error() string { return fmt.Sprintf("wiki title is reserved: %s", err.Title) } +func (err ErrWikiReservedName) Unwrap() error { + return util.ErrInvalidArgument +} + // ErrWikiInvalidFileName represents an invalid wiki file name. type ErrWikiInvalidFileName struct { FileName string @@ -60,6 +68,10 @@ func (err ErrWikiInvalidFileName) Error() string { return fmt.Sprintf("Invalid wiki filename: %s", err.FileName) } +func (err ErrWikiInvalidFileName) Unwrap() error { + return util.ErrInvalidArgument +} + // WikiCloneLink returns clone URLs of repository wiki. func (repo *Repository) WikiCloneLink() *CloneLink { return repo.cloneLink(true) diff --git a/models/user/email_address.go b/models/user/email_address.go index d87b945706..964e7ae08c 100644 --- a/models/user/email_address.go +++ b/models/user/email_address.go @@ -40,6 +40,10 @@ func (err ErrEmailCharIsNotSupported) Error() string { return fmt.Sprintf("e-mail address contains unsupported character [email: %s]", err.Email) } +func (err ErrEmailCharIsNotSupported) Unwrap() error { + return util.ErrInvalidArgument +} + // ErrEmailInvalid represents an error where the email address does not comply with RFC 5322 // or has a leading '-' character type ErrEmailInvalid struct { @@ -56,6 +60,10 @@ func (err ErrEmailInvalid) Error() string { return fmt.Sprintf("e-mail invalid [email: %s]", err.Email) } +func (err ErrEmailInvalid) Unwrap() error { + return util.ErrInvalidArgument +} + // ErrEmailAlreadyUsed represents a "EmailAlreadyUsed" kind of error. type ErrEmailAlreadyUsed struct { Email string @@ -71,6 +79,10 @@ func (err ErrEmailAlreadyUsed) Error() string { return fmt.Sprintf("e-mail already in use [email: %s]", err.Email) } +func (err ErrEmailAlreadyUsed) Unwrap() error { + return util.ErrAlreadyExist +} + // ErrEmailAddressNotExist email address not exist type ErrEmailAddressNotExist struct { Email string @@ -86,6 +98,10 @@ func (err ErrEmailAddressNotExist) Error() string { return fmt.Sprintf("Email address does not exist [email: %s]", err.Email) } +func (err ErrEmailAddressNotExist) Unwrap() error { + return util.ErrNotExist +} + // ErrPrimaryEmailCannotDelete primary email address cannot be deleted type ErrPrimaryEmailCannotDelete struct { Email string @@ -101,6 +117,10 @@ func (err ErrPrimaryEmailCannotDelete) Error() string { return fmt.Sprintf("Primary email address cannot be deleted [email: %s]", err.Email) } +func (err ErrPrimaryEmailCannotDelete) Unwrap() error { + return util.ErrInvalidArgument +} + // EmailAddress is the list of all email addresses of a user. It also contains the // primary email address which is saved in user table. type EmailAddress struct { diff --git a/models/user/error.go b/models/user/error.go index 25e0d8ea8a..3fe4ee6657 100644 --- a/models/user/error.go +++ b/models/user/error.go @@ -6,6 +6,8 @@ package user import ( "fmt" + + "code.gitea.io/gitea/modules/util" ) // ____ ___ @@ -30,6 +32,11 @@ func (err ErrUserAlreadyExist) Error() string { return fmt.Sprintf("user already exists [name: %s]", err.Name) } +// Unwrap unwraps this error as a ErrExist error +func (err ErrUserAlreadyExist) Unwrap() error { + return util.ErrAlreadyExist +} + // ErrUserNotExist represents a "UserNotExist" kind of error. type ErrUserNotExist struct { UID int64 @@ -47,6 +54,11 @@ func (err ErrUserNotExist) Error() string { return fmt.Sprintf("user does not exist [uid: %d, name: %s, keyid: %d]", err.UID, err.Name, err.KeyID) } +// Unwrap unwraps this error as a ErrNotExist error +func (err ErrUserNotExist) Unwrap() error { + return util.ErrNotExist +} + // ErrUserProhibitLogin represents a "ErrUserProhibitLogin" kind of error. type ErrUserProhibitLogin struct { UID int64 @@ -63,6 +75,11 @@ func (err ErrUserProhibitLogin) Error() string { return fmt.Sprintf("user is not allowed login [uid: %d, name: %s]", err.UID, err.Name) } +// Unwrap unwraps this error as a ErrPermission error +func (err ErrUserProhibitLogin) Unwrap() error { + return util.ErrPermissionDenied +} + // ErrUserInactive represents a "ErrUserInactive" kind of error. type ErrUserInactive struct { UID int64 @@ -78,3 +95,8 @@ func IsErrUserInactive(err error) bool { func (err ErrUserInactive) Error() string { return fmt.Sprintf("user is inactive [uid: %d, name: %s]", err.UID, err.Name) } + +// Unwrap unwraps this error as a ErrPermission error +func (err ErrUserInactive) Unwrap() error { + return util.ErrPermissionDenied +} diff --git a/models/user/external_login_user.go b/models/user/external_login_user.go index 422823b89c..496717c57b 100644 --- a/models/user/external_login_user.go +++ b/models/user/external_login_user.go @@ -10,6 +10,7 @@ import ( "time" "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/util" "xorm.io/builder" ) @@ -31,6 +32,10 @@ func (err ErrExternalLoginUserAlreadyExist) Error() string { return fmt.Sprintf("external login user already exists [externalID: %s, userID: %d, loginSourceID: %d]", err.ExternalID, err.UserID, err.LoginSourceID) } +func (err ErrExternalLoginUserAlreadyExist) Unwrap() error { + return util.ErrAlreadyExist +} + // ErrExternalLoginUserNotExist represents a "ExternalLoginUserNotExist" kind of error. type ErrExternalLoginUserNotExist struct { UserID int64 @@ -47,6 +52,10 @@ func (err ErrExternalLoginUserNotExist) Error() string { return fmt.Sprintf("external login user link does not exists [userID: %d, loginSourceID: %d]", err.UserID, err.LoginSourceID) } +func (err ErrExternalLoginUserNotExist) Unwrap() error { + return util.ErrNotExist +} + // ExternalLoginUser makes the connecting between some existing user and additional external login sources type ExternalLoginUser struct { ExternalID string `xorm:"pk NOT NULL"` diff --git a/models/user/openid.go b/models/user/openid.go index 8ef0ce5ed7..f8e8a787e6 100644 --- a/models/user/openid.go +++ b/models/user/openid.go @@ -10,6 +10,7 @@ import ( "fmt" "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/util" ) // ErrOpenIDNotExist openid is not known @@ -65,6 +66,10 @@ func (err ErrOpenIDAlreadyUsed) Error() string { return fmt.Sprintf("OpenID already in use [oid: %s]", err.OpenID) } +func (err ErrOpenIDAlreadyUsed) Unwrap() error { + return util.ErrAlreadyExist +} + // AddUserOpenID adds an pre-verified/normalized OpenID URI to given user. // NOTE: make sure openid.URI is normalized already func AddUserOpenID(ctx context.Context, openid *UserOpenID) error { diff --git a/models/user/redirect.go b/models/user/redirect.go index 49370218db..af8d6439ad 100644 --- a/models/user/redirect.go +++ b/models/user/redirect.go @@ -10,6 +10,7 @@ import ( "strings" "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/util" ) // ErrUserRedirectNotExist represents a "UserRedirectNotExist" kind of error. @@ -27,6 +28,10 @@ func (err ErrUserRedirectNotExist) Error() string { return fmt.Sprintf("user redirect does not exist [name: %s]", err.Name) } +func (err ErrUserRedirectNotExist) Unwrap() error { + return util.ErrNotExist +} + // Redirect represents that a user name should be redirected to another type Redirect struct { ID int64 `xorm:"pk autoincr"` diff --git a/models/webhook/webhook.go b/models/webhook/webhook.go index ac09220630..83200a3d1c 100644 --- a/models/webhook/webhook.go +++ b/models/webhook/webhook.go @@ -41,6 +41,10 @@ func (err ErrWebhookNotExist) Error() string { return fmt.Sprintf("webhook does not exist [id: %d]", err.ID) } +func (err ErrWebhookNotExist) Unwrap() error { + return util.ErrNotExist +} + // ErrHookTaskNotExist represents a "HookTaskNotExist" kind of error. type ErrHookTaskNotExist struct { HookID int64 @@ -57,6 +61,10 @@ func (err ErrHookTaskNotExist) Error() string { return fmt.Sprintf("hook task does not exist [hook: %d, uuid: %s]", err.HookID, err.UUID) } +func (err ErrHookTaskNotExist) Unwrap() error { + return util.ErrNotExist +} + // HookContentType is the content type of a web hook type HookContentType int diff --git a/modules/git/error.go b/modules/git/error.go index 387dd724e5..40c4106414 100644 --- a/modules/git/error.go +++ b/modules/git/error.go @@ -8,6 +8,8 @@ import ( "fmt" "strings" "time" + + "code.gitea.io/gitea/modules/util" ) // ErrExecTimeout error when exec timed out @@ -41,6 +43,10 @@ func (err ErrNotExist) Error() string { return fmt.Sprintf("object does not exist [id: %s, rel_path: %s]", err.ID, err.RelPath) } +func (err ErrNotExist) Unwrap() error { + return util.ErrNotExist +} + // ErrBadLink entry.FollowLink error type ErrBadLink struct { Name string @@ -87,6 +93,10 @@ func (err ErrBranchNotExist) Error() string { return fmt.Sprintf("branch does not exist [name: %s]", err.Name) } +func (err ErrBranchNotExist) Unwrap() error { + return util.ErrNotExist +} + // ErrPushOutOfDate represents an error if merging fails due to unrelated histories type ErrPushOutOfDate struct { StdOut string diff --git a/modules/translation/i18n/errors.go b/modules/translation/i18n/errors.go index b485badd1d..a81b0bc1ac 100644 --- a/modules/translation/i18n/errors.go +++ b/modules/translation/i18n/errors.go @@ -4,9 +4,11 @@ package i18n -import "errors" +import ( + "code.gitea.io/gitea/modules/util" +) var ( - ErrLocaleAlreadyExist = errors.New("lang already exists") - ErrUncertainArguments = errors.New("arguments to i18n should not contain uncertain slices") + ErrLocaleAlreadyExist = util.SilentWrap{Message: "lang already exists", Err: util.ErrAlreadyExist} + ErrUncertainArguments = util.SilentWrap{Message: "arguments to i18n should not contain uncertain slices", Err: util.ErrInvalidArgument} ) diff --git a/modules/util/error.go b/modules/util/error.go new file mode 100644 index 0000000000..08e491dbaf --- /dev/null +++ b/modules/util/error.go @@ -0,0 +1,37 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package util + +import ( + "errors" +) + +// Common Errors forming the base of our error system +// +// Many Errors returned by Gitea can be tested against these errors +// using errors.Is. +var ( + ErrInvalidArgument = errors.New("invalid argument") + ErrPermissionDenied = errors.New("permission denied") + ErrAlreadyExist = errors.New("resource already exists") + ErrNotExist = errors.New("resource does not exist") +) + +// SilentWrap provides a simple wrapper for a wrapped error where the wrapped error message plays no part in the error message +// Especially useful for "untyped" errors created with "errors.New(…)" that can be classified as 'invalid argument', 'permission denied', 'exists already', or 'does not exist' +type SilentWrap struct { + Message string + Err error +} + +// Error returns the message +func (w SilentWrap) Error() string { + return w.Message +} + +// Unwrap returns the underlying error +func (w SilentWrap) Unwrap() error { + return w.Err +} diff --git a/services/repository/fork.go b/services/repository/fork.go index 96c391e715..32a516b79f 100644 --- a/services/repository/fork.go +++ b/services/repository/fork.go @@ -39,6 +39,10 @@ func (err ErrForkAlreadyExist) Error() string { return fmt.Sprintf("repository is already forked by user [uname: %s, repo path: %s, fork path: %s]", err.Uname, err.RepoName, err.ForkName) } +func (err ErrForkAlreadyExist) Unwrap() error { + return util.ErrAlreadyExist +} + // ForkRepoOptions contains the fork repository options type ForkRepoOptions struct { BaseRepo *repo_model.Repository