mirror of
https://github.com/go-gitea/gitea.git
synced 2025-10-24 13:53:42 +09:00
Honor delete branch on merge repo setting when using merge API (#35488)
Fix #35463. --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
@@ -129,7 +129,7 @@ func TestAPIRepoIssueConfigPaths(t *testing.T) {
|
||||
configData, err := yaml.Marshal(configMap)
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = createFileInBranch(owner, repo, fullPath, repo.DefaultBranch, string(configData))
|
||||
_, err = createFile(owner, repo, fullPath, string(configData))
|
||||
assert.NoError(t, err)
|
||||
|
||||
issueConfig := getIssueConfig(t, owner.Name, repo.Name)
|
||||
|
||||
@@ -17,19 +17,23 @@ import (
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
unit_model "code.gitea.io/gitea/models/unit"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/services/convert"
|
||||
"code.gitea.io/gitea/services/forms"
|
||||
"code.gitea.io/gitea/services/gitdiff"
|
||||
issue_service "code.gitea.io/gitea/services/issue"
|
||||
pull_service "code.gitea.io/gitea/services/pull"
|
||||
repo_service "code.gitea.io/gitea/services/repository"
|
||||
files_service "code.gitea.io/gitea/services/repository/files"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestAPIViewPulls(t *testing.T) {
|
||||
@@ -186,6 +190,76 @@ func TestAPIMergePullWIP(t *testing.T) {
|
||||
MakeRequest(t, req, http.StatusMethodNotAllowed)
|
||||
}
|
||||
|
||||
func TestAPIMergePull(t *testing.T) {
|
||||
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
apiCtx := NewAPITestContext(t, repo.OwnerName, repo.Name, auth_model.AccessTokenScopeWriteRepository)
|
||||
|
||||
checkBranchExists := func(t *testing.T, branchName string, status int) {
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/%s/branches/%s", owner.Name, repo.Name, branchName)).AddTokenAuth(apiCtx.Token)
|
||||
MakeRequest(t, req, status)
|
||||
}
|
||||
|
||||
createTestBranchPR := func(t *testing.T, branchName string) *api.PullRequest {
|
||||
testCreateFileInBranch(t, owner, repo, createFileInBranchOptions{NewBranch: branchName}, map[string]string{"a-new-file-" + branchName + ".txt": "dummy content"})
|
||||
prDTO, err := doAPICreatePullRequest(apiCtx, repo.OwnerName, repo.Name, repo.DefaultBranch, branchName)(t)
|
||||
require.NoError(t, err)
|
||||
return &prDTO
|
||||
}
|
||||
|
||||
performMerge := func(t *testing.T, prIndex int64, params map[string]any, optExpectedStatus ...int) {
|
||||
req := NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/merge", owner.Name, repo.Name, prIndex), params).AddTokenAuth(apiCtx.Token)
|
||||
expectedStatus := util.OptionalArg(optExpectedStatus, http.StatusOK)
|
||||
MakeRequest(t, req, expectedStatus)
|
||||
}
|
||||
|
||||
t.Run("Normal", func(t *testing.T) {
|
||||
newBranch := "test-pull-1"
|
||||
prDTO := createTestBranchPR(t, newBranch)
|
||||
performMerge(t, prDTO.Index, map[string]any{"do": "merge"})
|
||||
checkBranchExists(t, newBranch, http.StatusOK)
|
||||
// try to merge again, make sure we cannot perform a merge on the same PR
|
||||
performMerge(t, prDTO.Index, map[string]any{"do": "merge"}, http.StatusMethodNotAllowed)
|
||||
})
|
||||
|
||||
t.Run("DeleteBranchAfterMergePassedByFormField", func(t *testing.T) {
|
||||
newBranch := "test-pull-2"
|
||||
prDTO := createTestBranchPR(t, newBranch)
|
||||
performMerge(t, prDTO.Index, map[string]any{"do": "merge", "delete_branch_after_merge": true})
|
||||
checkBranchExists(t, newBranch, http.StatusNotFound)
|
||||
})
|
||||
|
||||
updateRepoUnitDefaultDeleteBranchAfterMerge := func(t *testing.T, repo *repo_model.Repository, value bool) {
|
||||
prUnit, err := repo.GetUnit(t.Context(), unit_model.TypePullRequests)
|
||||
require.NoError(t, err)
|
||||
|
||||
prUnit.PullRequestsConfig().DefaultDeleteBranchAfterMerge = value
|
||||
require.NoError(t, repo_service.UpdateRepositoryUnits(t.Context(), repo, []repo_model.RepoUnit{{
|
||||
RepoID: repo.ID,
|
||||
Type: unit_model.TypePullRequests,
|
||||
Config: prUnit.PullRequestsConfig(),
|
||||
}}, nil))
|
||||
}
|
||||
|
||||
t.Run("DeleteBranchAfterMergePassedByRepoSettings", func(t *testing.T) {
|
||||
newBranch := "test-pull-3"
|
||||
prDTO := createTestBranchPR(t, newBranch)
|
||||
updateRepoUnitDefaultDeleteBranchAfterMerge(t, repo, true)
|
||||
performMerge(t, prDTO.Index, map[string]any{"do": "merge"})
|
||||
checkBranchExists(t, newBranch, http.StatusNotFound)
|
||||
})
|
||||
|
||||
t.Run("DeleteBranchAfterMergeFormFieldIsSetButNotRepoSettings", func(t *testing.T) {
|
||||
newBranch := "test-pull-4"
|
||||
prDTO := createTestBranchPR(t, newBranch)
|
||||
updateRepoUnitDefaultDeleteBranchAfterMerge(t, repo, false)
|
||||
performMerge(t, prDTO.Index, map[string]any{"do": "merge", "delete_branch_after_merge": true})
|
||||
checkBranchExists(t, newBranch, http.StatusNotFound)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestAPICreatePullSuccess(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
repo10 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10})
|
||||
|
||||
@@ -133,7 +133,7 @@ func BenchmarkAPICreateFileSmall(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
for n := 0; b.Loop(); n++ {
|
||||
treePath := fmt.Sprintf("update/file%d.txt", n)
|
||||
_, _ = createFileInBranch(user2, repo1, treePath, repo1.DefaultBranch, treePath)
|
||||
_, _ = createFile(user2, repo1, treePath)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -149,7 +149,7 @@ func BenchmarkAPICreateFileMedium(b *testing.B) {
|
||||
for n := 0; b.Loop(); n++ {
|
||||
treePath := fmt.Sprintf("update/file%d.txt", n)
|
||||
copy(data, treePath)
|
||||
_, _ = createFileInBranch(user2, repo1, treePath, repo1.DefaultBranch, treePath)
|
||||
_, _ = createFile(user2, repo1, treePath)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -6,26 +6,36 @@ package integration
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
files_service "code.gitea.io/gitea/services/repository/files"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func createFileInBranch(user *user_model.User, repo *repo_model.Repository, treePath, branchName, content string) (*api.FilesResponse, error) {
|
||||
type createFileInBranchOptions struct {
|
||||
OldBranch, NewBranch string
|
||||
}
|
||||
|
||||
func testCreateFileInBranch(t *testing.T, user *user_model.User, repo *repo_model.Repository, createOpts createFileInBranchOptions, files map[string]string) *api.FilesResponse {
|
||||
resp, err := createFileInBranch(user, repo, createOpts, files)
|
||||
require.NoError(t, err)
|
||||
return resp
|
||||
}
|
||||
|
||||
func createFileInBranch(user *user_model.User, repo *repo_model.Repository, createOpts createFileInBranchOptions, files map[string]string) (*api.FilesResponse, error) {
|
||||
ctx := context.TODO()
|
||||
opts := &files_service.ChangeRepoFilesOptions{
|
||||
Files: []*files_service.ChangeRepoFile{
|
||||
{
|
||||
Operation: "create",
|
||||
TreePath: treePath,
|
||||
ContentReader: strings.NewReader(content),
|
||||
},
|
||||
},
|
||||
OldBranch: branchName,
|
||||
Author: nil,
|
||||
Committer: nil,
|
||||
opts := &files_service.ChangeRepoFilesOptions{OldBranch: createOpts.OldBranch, NewBranch: createOpts.NewBranch}
|
||||
for path, content := range files {
|
||||
opts.Files = append(opts.Files, &files_service.ChangeRepoFile{
|
||||
Operation: "create",
|
||||
TreePath: path,
|
||||
ContentReader: strings.NewReader(content),
|
||||
})
|
||||
}
|
||||
return files_service.ChangeRepoFiles(ctx, repo, user, opts)
|
||||
}
|
||||
@@ -53,10 +63,12 @@ func createOrReplaceFileInBranch(user *user_model.User, repo *repo_model.Reposit
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = createFileInBranch(user, repo, treePath, branchName, content)
|
||||
_, err = createFileInBranch(user, repo, createFileInBranchOptions{OldBranch: branchName}, map[string]string{treePath: content})
|
||||
return err
|
||||
}
|
||||
|
||||
func createFile(user *user_model.User, repo *repo_model.Repository, treePath string) (*api.FilesResponse, error) {
|
||||
return createFileInBranch(user, repo, treePath, repo.DefaultBranch, "This is a NEW file")
|
||||
// TODO: replace all usages of this function with testCreateFileInBranch or testCreateFile
|
||||
func createFile(user *user_model.User, repo *repo_model.Repository, treePath string, optContent ...string) (*api.FilesResponse, error) {
|
||||
content := util.OptionalArg(optContent, "This is a NEW file") // some tests need this default content because its SHA is hardcoded
|
||||
return createFileInBranch(user, repo, createFileInBranchOptions{}, map[string]string{treePath: content})
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ func testPullCleanUp(t *testing.T, session *TestSession, user, repo, pullnum str
|
||||
|
||||
// Click the little button to create a pull
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
link, exists := htmlDoc.doc.Find(".timeline-item .delete-button").Attr("data-url")
|
||||
link, exists := htmlDoc.doc.Find(".timeline-item .delete-branch-after-merge").Attr("data-url")
|
||||
assert.True(t, exists, "The template has changed, can not find delete button url")
|
||||
req = NewRequestWithValues(t, "POST", link, map[string]string{
|
||||
"_csrf": htmlDoc.GetCSRF(),
|
||||
|
||||
Reference in New Issue
Block a user