From f6067a8465e7762aea1561106cfee291409a0fd6 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 24 Jan 2020 01:28:15 +0800 Subject: Migrate reviews when migrating repository from github (#9463) * fix typo * Migrate reviews when migrating repository from github * fix lint * Added test and migration when external user login * fix test * fix commented state * Some improvements * fix bug when get pull request and ref original author on code comments * Fix migrated line; Added comment for review * Don't load all pull requests attributes * Fix typo * wrong change copy head * fix tests * fix reactions * Fix test * fix fmt * fix review comment reactions --- modules/migrations/gitea.go | 120 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) (limited to 'modules/migrations/gitea.go') diff --git a/modules/migrations/gitea.go b/modules/migrations/gitea.go index 82664d0d1a..96d47dc527 100644 --- a/modules/migrations/gitea.go +++ b/modules/migrations/gitea.go @@ -6,6 +6,7 @@ package migrations import ( + "bytes" "context" "fmt" "io" @@ -27,6 +28,7 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/services/gitdiff" gouuid "github.com/satori/go.uuid" ) @@ -48,6 +50,7 @@ type GiteaLocalUploader struct { gitRepo *git.Repository prHeadCache map[string]struct{} userMap map[int64]int64 // external user id mapping to user id + prCache map[int64]*models.PullRequest gitServiceType structs.GitServiceType } @@ -60,6 +63,7 @@ func NewGiteaLocalUploader(ctx context.Context, doer *models.User, repoOwner, re repoName: repoName, prHeadCache: make(map[string]struct{}), userMap: make(map[int64]int64), + prCache: make(map[int64]*models.PullRequest), } } @@ -706,6 +710,122 @@ func (g *GiteaLocalUploader) newPullRequest(pr *base.PullRequest) (*models.PullR return &pullRequest, nil } +func convertReviewState(state string) models.ReviewType { + switch state { + case base.ReviewStatePending: + return models.ReviewTypePending + case base.ReviewStateApproved: + return models.ReviewTypeApprove + case base.ReviewStateChangesRequested: + return models.ReviewTypeReject + case base.ReviewStateCommented: + return models.ReviewTypeComment + default: + return models.ReviewTypePending + } +} + +// CreateReviews create pull request reviews +func (g *GiteaLocalUploader) CreateReviews(reviews ...*base.Review) error { + var cms = make([]*models.Review, 0, len(reviews)) + for _, review := range reviews { + var issueID int64 + if issueIDStr, ok := g.issues.Load(review.IssueIndex); !ok { + issue, err := models.GetIssueByIndex(g.repo.ID, review.IssueIndex) + if err != nil { + return err + } + issueID = issue.ID + g.issues.Store(review.IssueIndex, issueID) + } else { + issueID = issueIDStr.(int64) + } + + userid, ok := g.userMap[review.ReviewerID] + tp := g.gitServiceType.Name() + if !ok && tp != "" { + var err error + userid, err = models.GetUserIDByExternalUserID(tp, fmt.Sprintf("%v", review.ReviewerID)) + if err != nil { + log.Error("GetUserIDByExternalUserID: %v", err) + } + if userid > 0 { + g.userMap[review.ReviewerID] = userid + } + } + + var cm = models.Review{ + Type: convertReviewState(review.State), + IssueID: issueID, + Content: review.Content, + Official: review.Official, + CreatedUnix: timeutil.TimeStamp(review.CreatedAt.Unix()), + UpdatedUnix: timeutil.TimeStamp(review.CreatedAt.Unix()), + } + + if userid > 0 { + cm.ReviewerID = userid + } else { + cm.ReviewerID = g.doer.ID + cm.OriginalAuthor = review.ReviewerName + cm.OriginalAuthorID = review.ReviewerID + } + + // get pr + pr, ok := g.prCache[issueID] + if !ok { + var err error + pr, err = models.GetPullRequestByIssueIDWithNoAttributes(issueID) + if err != nil { + return err + } + g.prCache[issueID] = pr + } + + for _, comment := range review.Comments { + headCommitID, err := g.gitRepo.GetRefCommitID(pr.GetGitRefName()) + if err != nil { + return fmt.Errorf("GetRefCommitID[%s]: %v", pr.GetGitRefName(), err) + } + patchBuf := new(bytes.Buffer) + if err := gitdiff.GetRawDiffForFile(g.gitRepo.Path, pr.MergeBase, headCommitID, gitdiff.RawDiffNormal, comment.TreePath, patchBuf); err != nil { + return fmt.Errorf("GetRawDiffForLine[%s, %s, %s, %s]: %v", g.gitRepo.Path, pr.MergeBase, headCommitID, comment.TreePath, err) + } + + _, _, line, _ := gitdiff.ParseDiffHunkString(comment.DiffHunk) + + patch := gitdiff.CutDiffAroundLine(patchBuf, int64((&models.Comment{Line: int64(line + comment.Position - 1)}).UnsignedLine()), line < 0, setting.UI.CodeCommentLines) + + var c = models.Comment{ + Type: models.CommentTypeCode, + PosterID: comment.PosterID, + IssueID: issueID, + Content: comment.Content, + Line: int64(line + comment.Position - 1), + TreePath: comment.TreePath, + CommitSHA: comment.CommitID, + Patch: patch, + CreatedUnix: timeutil.TimeStamp(comment.CreatedAt.Unix()), + UpdatedUnix: timeutil.TimeStamp(comment.UpdatedAt.Unix()), + } + + if userid > 0 { + c.PosterID = userid + } else { + c.PosterID = g.doer.ID + c.OriginalAuthor = review.ReviewerName + c.OriginalAuthorID = review.ReviewerID + } + + cm.Comments = append(cm.Comments, &c) + } + + cms = append(cms, &cm) + } + + return models.InsertReviews(cms) +} + // Rollback when migrating failed, this will rollback all the changes. func (g *GiteaLocalUploader) Rollback() error { if g.repo != nil && g.repo.ID > 0 { -- cgit v1.2.3