From ebc77a5f65200eab99526ba9c786dcc0dac5b60a Mon Sep 17 00:00:00 2001 From: ZheNing Hu Date: Wed, 1 Mar 2023 16:58:55 +0800 Subject: [PATCH] Skip push update when tag to blob/tree Because git ref may reference to blob/tree, but push update logic will treate the object as a commit. Therefore, an error occurred when parsing the commit object, resulting in the loss of the webhook notification of this ref and other refs. So we ignore the wrong type error here to let other common refs can do webhook normally. Hope to fix #23213. Signed-off-by: ZheNing Hu --- modules/git/error.go | 16 ++++++++ modules/git/repo_commit_gogit.go | 61 +++++++++++++++++++++++------- modules/git/repo_commit_nogogit.go | 9 +++++ services/repository/push.go | 4 ++ 4 files changed, 76 insertions(+), 14 deletions(-) diff --git a/modules/git/error.go b/modules/git/error.go index dc10d451b3bbf..eda8d479c0e2e 100644 --- a/modules/git/error.go +++ b/modules/git/error.go @@ -46,6 +46,22 @@ func (err ErrNotExist) Unwrap() error { return util.ErrNotExist } +// ErrWrongType git object with wrong type +type ErrWrongType struct { + ID string + Type string +} + +// IsErrWrongType if some error is ErrWrongType +func IsErrWrongType(err error) bool { + _, ok := err.(ErrWrongType) + return ok +} + +func (err ErrWrongType) Error() string { + return fmt.Sprintf("git object type is invalid [id: %s, type: %s]", err.ID, err.Type) +} + // ErrBadLink entry.FollowLink error type ErrBadLink struct { Name string diff --git a/modules/git/repo_commit_gogit.go b/modules/git/repo_commit_gogit.go index ce0af936140db..2a9a547fe0e93 100644 --- a/modules/git/repo_commit_gogit.go +++ b/modules/git/repo_commit_gogit.go @@ -9,6 +9,8 @@ package git import ( "strings" + "code.gitea.io/gitea/modules/log" + "github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing/object" ) @@ -66,26 +68,57 @@ func (repo *Repository) IsCommitExist(name string) bool { return err == nil } -func (repo *Repository) getCommit(id SHA1) (*Commit, error) { - var tagObject *object.Tag - - gogitCommit, err := repo.gogitRepo.CommitObject(id) - if err == plumbing.ErrObjectNotFound { - tagObject, err = repo.gogitRepo.TagObject(id) - if err == plumbing.ErrObjectNotFound { - return nil, ErrNotExist{ - ID: id.String(), - } - } - if err == nil { - gogitCommit, err = repo.gogitRepo.CommitObject(tagObject.Target) +func (repo *Repository) getGoGitTagDeepestObject(tag *object.Tag) (object.Object, error) { + obj, err := tag.Object() + if err != nil { + return nil, err + } + if subTag, ok := obj.(*object.Tag); ok { + obj, err = repo.getGoGitTagDeepestObject(subTag) + if err != nil { + return nil, err } - // if we get a plumbing.ErrObjectNotFound here then the repository is broken and it should be 500 } + return obj, nil +} + +func (repo *Repository) getCommit(id SHA1) (*Commit, error) { + var gogitCommit *object.Commit + + obj, err := repo.gogitRepo.Object(plumbing.AnyObject, id) if err != nil { return nil, err } + switch o := obj.(type) { + case *object.Commit: + gogitCommit = o + case *object.Tag: + var ok bool + + obj, err := repo.getGoGitTagDeepestObject(o) + if err != nil { + return nil, err + } + if gogitCommit, ok = obj.(*object.Commit); !ok { + return nil, ErrWrongType{ + ID: obj.ID().String(), + Type: obj.Type().String(), + } + } + + case *object.Blob, *object.Tree: + return nil, ErrWrongType{ + ID: id.String(), + Type: o.Type().String(), + } + default: + log.Debug("Unknown typ: %s", o.Type()) + return nil, ErrNotExist{ + ID: id.String(), + } + } + commit := convertCommit(gogitCommit) commit.repo = repo diff --git a/modules/git/repo_commit_nogogit.go b/modules/git/repo_commit_nogogit.go index d5eb723100a73..fe6951b1b800f 100644 --- a/modules/git/repo_commit_nogogit.go +++ b/modules/git/repo_commit_nogogit.go @@ -119,6 +119,15 @@ func (repo *Repository) getCommitFromBatchReader(rd *bufio.Reader, id SHA1) (*Co } return commit, nil + case "blob", "tree": + _, err = rd.Discard(int(size) + 1) + if err != nil { + return nil, err + } + return nil, ErrWrongType{ + ID: id.String(), + Type: typ, + } default: log.Debug("Unknown typ: %s", typ) _, err = rd.Discard(int(size) + 1) diff --git a/services/repository/push.go b/services/repository/push.go index 355c2878113fd..f818c86a0bfed 100644 --- a/services/repository/push.go +++ b/services/repository/push.go @@ -135,6 +135,10 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { } else { // is new tag newCommit, err := gitRepo.GetCommit(opts.NewCommitID) if err != nil { + if git.IsErrWrongType(err) { + log.Info("ignore special ref push update: %v", err) + continue + } return fmt.Errorf("gitRepo.GetCommit(%s) in %s/%s[%d]: %w", opts.NewCommitID, repo.OwnerName, repo.Name, repo.ID, err) }