mirror of
https://github.com/hanzoai/forge.git
synced 2026-10-30 15:00:39 +00:00
Source files keep their SPDX-License-Identifier and Hanzo copyright line; the Gitea, Gogs and LFS Test Server copyrights they used to repeat now live once in NOTICE, alongside LICENSE. The header lint accepts any copyright line above the SPDX line, so it no longer demands an upstream one. Co-authored-by: Hanzo Dev <[email protected]>
155 lines
4.5 KiB
Go
155 lines
4.5 KiB
Go
// Copyright 2026 Hanzo AI, Inc. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package pull
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"testing"
|
|
|
|
issues_model "github.com/hanzoai/git/models/issues"
|
|
"github.com/hanzoai/git/models/unittest"
|
|
"github.com/hanzoai/git/modules/git/gitcmd"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func testPullRequestMergeCheck(t *testing.T,
|
|
targetFunc func(ctx context.Context, pr *issues_model.PullRequest) error,
|
|
pr *issues_model.PullRequest,
|
|
expectedStatus issues_model.PullRequestStatus,
|
|
expectedConflictedFiles []string,
|
|
expectedChangedProtectedFiles []string,
|
|
) {
|
|
assert.NoError(t, pr.LoadIssue(t.Context()))
|
|
assert.NoError(t, pr.LoadBaseRepo(t.Context()))
|
|
assert.NoError(t, pr.LoadHeadRepo(t.Context()))
|
|
pr.Status = issues_model.PullRequestStatusChecking
|
|
pr.ConflictedFiles = []string{"unrelated-conflicted-file"}
|
|
pr.ChangedProtectedFiles = []string{"unrelated-protected-file"}
|
|
pr.MergeBase = ""
|
|
pr.HeadCommitID = ""
|
|
err := targetFunc(t.Context(), pr)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, expectedStatus, pr.Status)
|
|
assert.Equal(t, expectedConflictedFiles, pr.ConflictedFiles)
|
|
assert.Equal(t, expectedChangedProtectedFiles, pr.ChangedProtectedFiles)
|
|
assert.NotEmpty(t, pr.MergeBase)
|
|
assert.NotEmpty(t, pr.HeadCommitID)
|
|
}
|
|
|
|
func TestPullRequestMergeable(t *testing.T) {
|
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2})
|
|
t.Run("NoConflict-MergeTree", func(t *testing.T) {
|
|
testPullRequestMergeCheck(t, checkPullRequestMergeableByMergeTree, pr, issues_model.PullRequestStatusMergeable, nil, nil)
|
|
})
|
|
t.Run("NoConflict-TmpRepo", func(t *testing.T) {
|
|
testPullRequestMergeCheck(t, checkPullRequestMergeableByTmpRepo, pr, issues_model.PullRequestStatusMergeable, nil, nil)
|
|
})
|
|
|
|
pr.BaseBranch, pr.HeadBranch = "test-merge-tree-conflict-base", "test-merge-tree-conflict-head"
|
|
conflictFiles := createConflictBranches(t, pr.BaseRepo.RepoPath(), pr.BaseBranch, pr.HeadBranch)
|
|
t.Run("Conflict-MergeTree", func(t *testing.T) {
|
|
testPullRequestMergeCheck(t, checkPullRequestMergeableByMergeTree, pr, issues_model.PullRequestStatusConflict, conflictFiles, nil)
|
|
})
|
|
t.Run("Conflict-TmpRepo", func(t *testing.T) {
|
|
testPullRequestMergeCheck(t, checkPullRequestMergeableByTmpRepo, pr, issues_model.PullRequestStatusConflict, conflictFiles, nil)
|
|
})
|
|
|
|
pr.BaseBranch, pr.HeadBranch = "test-merge-tree-empty-base", "test-merge-tree-empty-head"
|
|
createEmptyBranches(t, pr.BaseRepo.RepoPath(), pr.BaseBranch, pr.HeadBranch)
|
|
t.Run("Empty-MergeTree", func(t *testing.T) {
|
|
testPullRequestMergeCheck(t, checkPullRequestMergeableByMergeTree, pr, issues_model.PullRequestStatusEmpty, nil, nil)
|
|
})
|
|
t.Run("Empty-TmpRepo", func(t *testing.T) {
|
|
testPullRequestMergeCheck(t, checkPullRequestMergeableByTmpRepo, pr, issues_model.PullRequestStatusEmpty, nil, nil)
|
|
})
|
|
}
|
|
|
|
func createConflictBranches(t *testing.T, repoPath, baseBranch, headBranch string) []string {
|
|
conflictFile := "conflict.txt"
|
|
stdin := fmt.Sprintf(
|
|
`reset refs/heads/%[1]s
|
|
from refs/heads/master
|
|
|
|
commit refs/heads/%[1]s
|
|
mark :1
|
|
committer Test <[email protected]> 0 +0000
|
|
data 17
|
|
add conflict file
|
|
M 100644 inline %[3]s
|
|
data 4
|
|
base
|
|
|
|
commit refs/heads/%[1]s
|
|
mark :2
|
|
committer Test <[email protected]> 0 +0000
|
|
data 11
|
|
base change
|
|
from :1
|
|
M 100644 inline %[3]s
|
|
data 11
|
|
base change
|
|
|
|
reset refs/heads/%[2]s
|
|
from :1
|
|
|
|
commit refs/heads/%[2]s
|
|
mark :3
|
|
committer Test <[email protected]> 0 +0000
|
|
data 11
|
|
head change
|
|
from :1
|
|
M 100644 inline %[3]s
|
|
data 11
|
|
head change
|
|
`, baseBranch, headBranch, conflictFile)
|
|
err := gitcmd.NewCommand("fast-import").WithDir(repoPath).WithStdinBytes([]byte(stdin)).RunWithStderr(t.Context())
|
|
require.NoError(t, err)
|
|
return []string{conflictFile}
|
|
}
|
|
|
|
func createEmptyBranches(t *testing.T, repoPath, baseBranch, headBranch string) {
|
|
emptyFile := "empty.txt"
|
|
stdin := fmt.Sprintf(`reset refs/heads/%[1]s
|
|
from refs/heads/master
|
|
|
|
commit refs/heads/%[1]s
|
|
mark :1
|
|
committer Test <[email protected]> 0 +0000
|
|
data 14
|
|
add empty file
|
|
M 100644 inline %[3]s
|
|
data 4
|
|
base
|
|
|
|
reset refs/heads/%[2]s
|
|
from :1
|
|
|
|
commit refs/heads/%[2]s
|
|
mark :2
|
|
committer Test <[email protected]> 0 +0000
|
|
data 17
|
|
change empty file
|
|
from :1
|
|
M 100644 inline %[3]s
|
|
data 6
|
|
change
|
|
|
|
commit refs/heads/%[2]s
|
|
mark :3
|
|
committer Test <[email protected]> 0 +0000
|
|
data 17
|
|
revert empty file
|
|
from :2
|
|
M 100644 inline %[3]s
|
|
data 4
|
|
base
|
|
`, baseBranch, headBranch, emptyFile)
|
|
err := gitcmd.NewCommand("fast-import").WithDir(repoPath).WithStdinBytes([]byte(stdin)).RunWithStderr(t.Context())
|
|
require.NoError(t, err)
|
|
}
|