Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Display pull request head branch even the branch deleted or repository deleted #10413

Merged
merged 7 commits into from
Mar 2, 2020
101 changes: 47 additions & 54 deletions models/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ type PullRequest struct {
MergerID int64 `xorm:"INDEX"`
Merger *User `xorm:"-"`
MergedUnix timeutil.TimeStamp `xorm:"updated INDEX"`

isHeadRepoLoaded bool `xorm:"-"`
}

// MustHeadUserName returns the HeadRepo's username if failed return blank
Expand Down Expand Up @@ -97,38 +99,55 @@ func (pr *PullRequest) LoadAttributes() error {
return pr.loadAttributes(x)
}

// LoadBaseRepo loads pull request base repository from database
func (pr *PullRequest) LoadBaseRepo() error {
if pr.BaseRepo == nil {
if pr.HeadRepoID == pr.BaseRepoID && pr.HeadRepo != nil {
pr.BaseRepo = pr.HeadRepo
return nil
func (pr *PullRequest) loadHeadRepo(e Engine) (err error) {
if !pr.isHeadRepoLoaded && pr.HeadRepo == nil && pr.HeadRepoID > 0 {
if pr.HeadRepoID == pr.BaseRepoID {
if pr.BaseRepo != nil {
pr.HeadRepo = pr.BaseRepo
return nil
} else if pr.Issue != nil && pr.Issue.Repo != nil {
pr.HeadRepo = pr.Issue.Repo
return nil
}
}
var repo Repository
if has, err := x.ID(pr.BaseRepoID).Get(&repo); err != nil {
return err
} else if !has {
return ErrRepoNotExist{ID: pr.BaseRepoID}

pr.HeadRepo, err = getRepositoryByID(e, pr.HeadRepoID)
if err != nil && !IsErrRepoNotExist(err) { // Head repo maybe deleted, but it should still work
return fmt.Errorf("getRepositoryByID(head): %v", err)
}
pr.BaseRepo = &repo
pr.isHeadRepoLoaded = true
}
return nil
}

// LoadHeadRepo loads pull request head repository from database
// LoadHeadRepo loads the head repository
func (pr *PullRequest) LoadHeadRepo() error {
if pr.HeadRepo == nil {
if pr.HeadRepoID == pr.BaseRepoID && pr.BaseRepo != nil {
pr.HeadRepo = pr.BaseRepo
return nil
}
var repo Repository
if has, err := x.ID(pr.HeadRepoID).Get(&repo); err != nil {
return err
} else if !has {
return ErrRepoNotExist{ID: pr.HeadRepoID}
}
pr.HeadRepo = &repo
return pr.loadHeadRepo(x)
}

// LoadBaseRepo loads the target repository
func (pr *PullRequest) LoadBaseRepo() error {
return pr.loadBaseRepo(x)
}

func (pr *PullRequest) loadBaseRepo(e Engine) (err error) {
if pr.BaseRepo != nil {
return nil
}

if pr.HeadRepoID == pr.BaseRepoID && pr.HeadRepo != nil {
pr.BaseRepo = pr.HeadRepo
return nil
}

if pr.Issue != nil && pr.Issue.Repo != nil {
pr.BaseRepo = pr.Issue.Repo
return nil
}

pr.BaseRepo, err = getRepositoryByID(e, pr.BaseRepoID)
if err != nil {
return fmt.Errorf("GetRepositoryByID(base): %v", err)
}
return nil
}
Expand Down Expand Up @@ -414,32 +433,6 @@ func (pr *PullRequest) GetGitRefName() string {
return fmt.Sprintf("refs/pull/%d/head", pr.Index)
}

func (pr *PullRequest) getHeadRepo(e Engine) (err error) {
pr.HeadRepo, err = getRepositoryByID(e, pr.HeadRepoID)
if err != nil && !IsErrRepoNotExist(err) {
return fmt.Errorf("getRepositoryByID(head): %v", err)
}
return nil
}

// GetHeadRepo loads the head repository
func (pr *PullRequest) GetHeadRepo() error {
return pr.getHeadRepo(x)
}

// GetBaseRepo loads the target repository
func (pr *PullRequest) GetBaseRepo() (err error) {
if pr.BaseRepo != nil {
return nil
}

pr.BaseRepo, err = GetRepositoryByID(pr.BaseRepoID)
if err != nil {
return fmt.Errorf("GetRepositoryByID(base): %v", err)
}
return nil
}

// IsChecking returns true if this pull request is still checking conflict.
func (pr *PullRequest) IsChecking() bool {
return pr.Status == PullRequestStatusChecking
Expand All @@ -452,7 +445,7 @@ func (pr *PullRequest) CanAutoMerge() bool {

// GetLastCommitStatus returns the last commit status for this pull request.
func (pr *PullRequest) GetLastCommitStatus() (status *CommitStatus, err error) {
if err = pr.GetHeadRepo(); err != nil {
if err = pr.LoadHeadRepo(); err != nil {
return nil, err
}

Expand Down Expand Up @@ -774,7 +767,7 @@ func (pr *PullRequest) GetWorkInProgressPrefix() string {
// IsHeadEqualWithBranch returns if the commits of branchName are available in pull request head
func (pr *PullRequest) IsHeadEqualWithBranch(branchName string) (bool, error) {
var err error
if err = pr.GetBaseRepo(); err != nil {
if err = pr.LoadBaseRepo(); err != nil {
return false, err
}
baseGitRepo, err := git.OpenRepository(pr.BaseRepo.RepoPath())
Expand All @@ -786,7 +779,7 @@ func (pr *PullRequest) IsHeadEqualWithBranch(branchName string) (bool, error) {
return false, err
}

if err = pr.GetHeadRepo(); err != nil {
if err = pr.LoadHeadRepo(); err != nil {
return false, err
}
headGitRepo, err := git.OpenRepository(pr.HeadRepo.RepoPath())
Expand Down
2 changes: 1 addition & 1 deletion models/pull_sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (

// SignMerge determines if we should sign a PR merge commit to the base repository
func (pr *PullRequest) SignMerge(u *User, tmpBasePath, baseCommit, headCommit string) (bool, string, error) {
if err := pr.GetBaseRepo(); err != nil {
if err := pr.LoadBaseRepo(); err != nil {
log.Error("Unable to get Base Repo for pull request")
return false, "", err
}
Expand Down
10 changes: 5 additions & 5 deletions models/pull_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,21 @@ func TestPullRequest_LoadIssue(t *testing.T) {
assert.Equal(t, int64(2), pr.Issue.ID)
}

func TestPullRequest_GetBaseRepo(t *testing.T) {
func TestPullRequest_LoadBaseRepo(t *testing.T) {
assert.NoError(t, PrepareTestDatabase())
pr := AssertExistsAndLoadBean(t, &PullRequest{ID: 1}).(*PullRequest)
assert.NoError(t, pr.GetBaseRepo())
assert.NoError(t, pr.LoadBaseRepo())
assert.NotNil(t, pr.BaseRepo)
assert.Equal(t, pr.BaseRepoID, pr.BaseRepo.ID)
assert.NoError(t, pr.GetBaseRepo())
assert.NoError(t, pr.LoadBaseRepo())
assert.NotNil(t, pr.BaseRepo)
assert.Equal(t, pr.BaseRepoID, pr.BaseRepo.ID)
}

func TestPullRequest_GetHeadRepo(t *testing.T) {
func TestPullRequest_LoadHeadRepo(t *testing.T) {
assert.NoError(t, PrepareTestDatabase())
pr := AssertExistsAndLoadBean(t, &PullRequest{ID: 1}).(*PullRequest)
assert.NoError(t, pr.GetHeadRepo())
assert.NoError(t, pr.LoadHeadRepo())
assert.NotNil(t, pr.HeadRepo)
assert.Equal(t, pr.HeadRepoID, pr.HeadRepo.ID)
}
Expand Down
121 changes: 59 additions & 62 deletions modules/convert/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ func ToAPIPullRequest(pr *models.PullRequest) *api.PullRequest {
baseBranch *git.Branch
headBranch *git.Branch
baseCommit *git.Commit
headCommit *git.Commit
err error
)

Expand All @@ -32,20 +31,14 @@ func ToAPIPullRequest(pr *models.PullRequest) *api.PullRequest {
}

apiIssue := pr.Issue.APIFormat()
if pr.BaseRepo == nil {
pr.BaseRepo, err = models.GetRepositoryByID(pr.BaseRepoID)
if err != nil {
log.Error("GetRepositoryById[%d]: %v", pr.ID, err)
return nil
}
if err := pr.LoadBaseRepo(); err != nil {
log.Error("GetRepositoryById[%d]: %v", pr.ID, err)
return nil
}
if pr.HeadRepoID != 0 && pr.HeadRepo == nil {
pr.HeadRepo, err = models.GetRepositoryByID(pr.HeadRepoID)
if err != nil && !models.IsErrRepoNotExist(err) {
log.Error("GetRepositoryById[%d]: %v", pr.ID, err)
return nil

}
if err := pr.LoadHeadRepo(); err != nil {
log.Error("GetRepositoryById[%d]: %v", pr.ID, err)
return nil
}

apiPullRequest := &api.PullRequest{
Expand All @@ -69,70 +62,74 @@ func ToAPIPullRequest(pr *models.PullRequest) *api.PullRequest {
Deadline: apiIssue.Deadline,
Created: pr.Issue.CreatedUnix.AsTimePtr(),
Updated: pr.Issue.UpdatedUnix.AsTimePtr(),
}
baseBranch, err = repo_module.GetBranch(pr.BaseRepo, pr.BaseBranch)
if err != nil {
if git.IsErrBranchNotExist(err) {
apiPullRequest.Base = nil
} else {
log.Error("GetBranch[%s]: %v", pr.BaseBranch, err)
return nil
}
} else {
apiBaseBranchInfo := &api.PRBranchInfo{

Base: &api.PRBranchInfo{
Name: pr.BaseBranch,
Ref: pr.BaseBranch,
RepoID: pr.BaseRepoID,
Repository: pr.BaseRepo.APIFormat(models.AccessModeNone),
}
},
Head: &api.PRBranchInfo{
Name: pr.HeadBranch,
Ref: fmt.Sprintf("refs/pull/%d/head", pr.Index),
RepoID: -1,
},
}

baseBranch, err = repo_module.GetBranch(pr.BaseRepo, pr.BaseBranch)
if err != nil && !git.IsErrBranchNotExist(err) {
log.Error("GetBranch[%s]: %v", pr.BaseBranch, err)
return nil
}

if err == nil {
baseCommit, err = baseBranch.GetCommit()
if err != nil {
if git.IsErrNotExist(err) {
apiBaseBranchInfo.Sha = ""
} else {
log.Error("GetCommit[%s]: %v", baseBranch.Name, err)
return nil
}
} else {
apiBaseBranchInfo.Sha = baseCommit.ID.String()
if err != nil && !git.IsErrNotExist(err) {
log.Error("GetCommit[%s]: %v", baseBranch.Name, err)
return nil
}

if err == nil {
apiPullRequest.Base.Sha = baseCommit.ID.String()
}
apiPullRequest.Base = apiBaseBranchInfo
}

if pr.HeadRepo != nil {
headBranch, err = repo_module.GetBranch(pr.HeadRepo, pr.HeadBranch)
apiPullRequest.Head.RepoID = pr.HeadRepo.ID
apiPullRequest.Head.Repository = pr.HeadRepo.APIFormat(models.AccessModeNone)

headGitRepo, err := git.OpenRepository(pr.HeadRepo.RepoPath())
if err != nil {
if git.IsErrBranchNotExist(err) {
apiPullRequest.Head = nil
} else {
log.Error("GetBranch[%s]: %v", pr.HeadBranch, err)
log.Error("OpenRepository[%s]: %v", pr.HeadRepo.RepoPath(), err)
return nil
}
defer headGitRepo.Close()

headBranch, err = headGitRepo.GetBranch(pr.HeadBranch)
if err != nil && !git.IsErrBranchNotExist(err) {
log.Error("GetBranch[%s]: %v", pr.HeadBranch, err)
return nil
}

if git.IsErrBranchNotExist(err) {
headCommitID, err := headGitRepo.GetRefCommitID(apiPullRequest.Head.Ref)
if err != nil && !git.IsErrNotExist(err) {
log.Error("GetCommit[%s]: %v", headBranch.Name, err)
return nil
}
if err == nil {
apiPullRequest.Head.Sha = headCommitID
}
} else {
apiHeadBranchInfo := &api.PRBranchInfo{
Name: pr.HeadBranch,
Ref: pr.HeadBranch,
RepoID: pr.HeadRepoID,
Repository: pr.HeadRepo.APIFormat(models.AccessModeNone),
commit, err := headBranch.GetCommit()
if err != nil && !git.IsErrNotExist(err) {
log.Error("GetCommit[%s]: %v", headBranch.Name, err)
return nil
}
headCommit, err = headBranch.GetCommit()
if err != nil {
if git.IsErrNotExist(err) {
apiHeadBranchInfo.Sha = ""
} else {
log.Error("GetCommit[%s]: %v", headBranch.Name, err)
return nil
}
} else {
apiHeadBranchInfo.Sha = headCommit.ID.String()
if err == nil {
apiPullRequest.Head.Ref = pr.HeadBranch
apiPullRequest.Head.Sha = commit.ID.String()
}
apiPullRequest.Head = apiHeadBranchInfo
}
} else {
apiPullRequest.Head = &api.PRBranchInfo{
Name: pr.HeadBranch,
Ref: fmt.Sprintf("refs/pull/%d/head", pr.Index),
RepoID: -1,
}
}

Expand Down
10 changes: 9 additions & 1 deletion modules/convert/pull_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,27 @@ import (
"testing"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/structs"

"github.com/stretchr/testify/assert"
)

func TestPullRequest_APIFormat(t *testing.T) {
//with HeadRepo
assert.NoError(t, models.PrepareTestDatabase())
headRepo := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository)
pr := models.AssertExistsAndLoadBean(t, &models.PullRequest{ID: 1}).(*models.PullRequest)
assert.NoError(t, pr.LoadAttributes())
assert.NoError(t, pr.LoadIssue())
apiPullRequest := ToAPIPullRequest(pr)
assert.NotNil(t, apiPullRequest)
assert.Nil(t, apiPullRequest.Head)
assert.EqualValues(t, &structs.PRBranchInfo{
Name: "branch1",
Ref: "refs/pull/2/head",
Sha: "4a357436d925b5c974181ff12a994538ddc5a269",
RepoID: 1,
Repository: headRepo.APIFormat(models.AccessModeNone),
}, apiPullRequest.Head)

//withOut HeadRepo
pr = models.AssertExistsAndLoadBean(t, &models.PullRequest{ID: 1}).(*models.PullRequest)
Expand Down
Loading