* Fix broken merge base migration v128 for merged PR * Allow PRs with deleted base branches to still show diff * as per @lunny Co-authored-by: Lauris BH <lauris@nix.lv>tags/v1.21.12.1
| @@ -200,6 +200,8 @@ var migrations = []Migration{ | |||
| NewMigration("Add Branch Protection Protected Files Column", addBranchProtectionProtectedFilesColumn), | |||
| // v133 -> v134 | |||
| NewMigration("Add EmailHash Table", addEmailHashTable), | |||
| // v134 -> v135 | |||
| NewMigration("Refix merge base for merged pull requests", refixMergeBase), | |||
| } | |||
| // Migrate database to current version | |||
| @@ -53,7 +53,7 @@ func fixMergeBase(x *xorm.Engine) error { | |||
| break | |||
| } | |||
| i += 50 | |||
| i += len(prs) | |||
| for _, pr := range prs { | |||
| baseRepo := &Repository{ID: pr.BaseRepoID} | |||
| has, err := x.Table("repository").Get(baseRepo) | |||
| @@ -81,10 +81,22 @@ func fixMergeBase(x *xorm.Engine) error { | |||
| } | |||
| } | |||
| } else { | |||
| var err error | |||
| pr.MergeBase, err = git.NewCommand("merge-base", "--", pr.MergedCommitID+"^", gitRefName).RunInDir(repoPath) | |||
| parentsString, err := git.NewCommand("rev-list", "--parents", "-n", "1", pr.MergedCommitID).RunInDir(repoPath) | |||
| if err != nil { | |||
| log.Error("Unable to get parents for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err) | |||
| continue | |||
| } | |||
| parents := strings.Split(strings.TrimSpace(parentsString), " ") | |||
| if len(parents) < 2 { | |||
| continue | |||
| } | |||
| args := append([]string{"merge-base", "--"}, parents[1:]...) | |||
| args = append(args, gitRefName) | |||
| pr.MergeBase, err = git.NewCommand(args...).RunInDir(repoPath) | |||
| if err != nil { | |||
| log.Error("Unable to get merge base for merged PR ID %d, Index %d in %s/%s. Error: %", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err) | |||
| log.Error("Unable to get merge base for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err) | |||
| continue | |||
| } | |||
| } | |||
| @@ -0,0 +1,96 @@ | |||
| // Copyright 2020 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "path/filepath" | |||
| "strings" | |||
| "code.gitea.io/gitea/modules/git" | |||
| "code.gitea.io/gitea/modules/log" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func refixMergeBase(x *xorm.Engine) error { | |||
| type Repository struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| OwnerID int64 `xorm:"UNIQUE(s) index"` | |||
| OwnerName string | |||
| LowerName string `xorm:"UNIQUE(s) INDEX NOT NULL"` | |||
| Name string `xorm:"INDEX NOT NULL"` | |||
| } | |||
| type PullRequest struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| Index int64 | |||
| HeadRepoID int64 `xorm:"INDEX"` | |||
| BaseRepoID int64 `xorm:"INDEX"` | |||
| HeadBranch string | |||
| BaseBranch string | |||
| MergeBase string `xorm:"VARCHAR(40)"` | |||
| HasMerged bool `xorm:"INDEX"` | |||
| MergedCommitID string `xorm:"VARCHAR(40)"` | |||
| } | |||
| var limit = setting.Database.IterateBufferSize | |||
| if limit <= 0 { | |||
| limit = 50 | |||
| } | |||
| i := 0 | |||
| for { | |||
| prs := make([]PullRequest, 0, 50) | |||
| if err := x.Limit(limit, i).Asc("id").Where("has_merged = ?", true).Find(&prs); err != nil { | |||
| return fmt.Errorf("Find: %v", err) | |||
| } | |||
| if len(prs) == 0 { | |||
| break | |||
| } | |||
| i += len(prs) | |||
| for _, pr := range prs { | |||
| baseRepo := &Repository{ID: pr.BaseRepoID} | |||
| has, err := x.Table("repository").Get(baseRepo) | |||
| if err != nil { | |||
| return fmt.Errorf("Unable to get base repo %d %v", pr.BaseRepoID, err) | |||
| } | |||
| if !has { | |||
| log.Error("Missing base repo with id %d for PR ID %d", pr.BaseRepoID, pr.ID) | |||
| continue | |||
| } | |||
| userPath := filepath.Join(setting.RepoRootPath, strings.ToLower(baseRepo.OwnerName)) | |||
| repoPath := filepath.Join(userPath, strings.ToLower(baseRepo.Name)+".git") | |||
| gitRefName := fmt.Sprintf("refs/pull/%d/head", pr.Index) | |||
| parentsString, err := git.NewCommand("rev-list", "--parents", "-n", "1", pr.MergedCommitID).RunInDir(repoPath) | |||
| if err != nil { | |||
| log.Error("Unable to get parents for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err) | |||
| continue | |||
| } | |||
| parents := strings.Split(strings.TrimSpace(parentsString), " ") | |||
| if len(parents) < 3 { | |||
| continue | |||
| } | |||
| // we should recalculate | |||
| args := append([]string{"merge-base", "--"}, parents[1:]...) | |||
| args = append(args, gitRefName) | |||
| pr.MergeBase, err = git.NewCommand(args...).RunInDir(repoPath) | |||
| if err != nil { | |||
| log.Error("Unable to get merge base for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err) | |||
| continue | |||
| } | |||
| pr.MergeBase = strings.TrimSpace(pr.MergeBase) | |||
| x.ID(pr.ID).Cols("merge_base").Update(pr) | |||
| } | |||
| } | |||
| return nil | |||
| } | |||
| @@ -308,7 +308,6 @@ func PrepareMergedViewPullInfo(ctx *context.Context, issue *models.Issue) *git.C | |||
| compareInfo, err := ctx.Repo.GitRepo.GetCompareInfo(ctx.Repo.Repository.RepoPath(), | |||
| pull.MergeBase, pull.GetGitRefName()) | |||
| if err != nil { | |||
| if strings.Contains(err.Error(), "fatal: Not a valid object name") { | |||
| ctx.Data["IsPullRequestBroken"] = true | |||
| @@ -360,9 +359,40 @@ func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.Compare | |||
| ctx.Data["IsPullRequestBroken"] = true | |||
| ctx.Data["BaseTarget"] = pull.BaseBranch | |||
| ctx.Data["HeadTarget"] = pull.HeadBranch | |||
| ctx.Data["NumCommits"] = 0 | |||
| ctx.Data["NumFiles"] = 0 | |||
| return nil | |||
| sha, err := baseGitRepo.GetRefCommitID(pull.GetGitRefName()) | |||
| if err != nil { | |||
| ctx.ServerError(fmt.Sprintf("GetRefCommitID(%s)", pull.GetGitRefName()), err) | |||
| return nil | |||
| } | |||
| commitStatuses, err := models.GetLatestCommitStatus(repo, sha, 0) | |||
| if err != nil { | |||
| ctx.ServerError("GetLatestCommitStatus", err) | |||
| return nil | |||
| } | |||
| if len(commitStatuses) > 0 { | |||
| ctx.Data["LatestCommitStatuses"] = commitStatuses | |||
| ctx.Data["LatestCommitStatus"] = models.CalcCommitStatus(commitStatuses) | |||
| } | |||
| compareInfo, err := baseGitRepo.GetCompareInfo(pull.BaseRepo.RepoPath(), | |||
| pull.MergeBase, pull.GetGitRefName()) | |||
| if err != nil { | |||
| if strings.Contains(err.Error(), "fatal: Not a valid object name") { | |||
| ctx.Data["IsPullRequestBroken"] = true | |||
| ctx.Data["BaseTarget"] = pull.BaseBranch | |||
| ctx.Data["NumCommits"] = 0 | |||
| ctx.Data["NumFiles"] = 0 | |||
| return nil | |||
| } | |||
| ctx.ServerError("GetCompareInfo", err) | |||
| return nil | |||
| } | |||
| ctx.Data["NumCommits"] = compareInfo.Commits.Len() | |||
| ctx.Data["NumFiles"] = compareInfo.NumFiles | |||
| return compareInfo | |||
| } | |||
| var headBranchExist bool | |||