feat: vendor gitea 1.16.2

This commit is contained in:
2026-06-02 08:36:01 +00:00
parent 247cd60f69
commit 54798b4615
2145 changed files with 162965 additions and 126447 deletions
@@ -11,7 +11,6 @@ import (
"net/url"
"os"
"path"
"path/filepath"
"strconv"
"strings"
"testing"
@@ -34,41 +33,46 @@ import (
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/modules/translation"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/automerge"
"code.gitea.io/gitea/services/automergequeue"
pull_service "code.gitea.io/gitea/services/pull"
repo_service "code.gitea.io/gitea/services/repository"
commitstatus_service "code.gitea.io/gitea/services/repository/commitstatus"
files_service "code.gitea.io/gitea/services/repository/files"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func testPullMerge(t *testing.T, session *TestSession, user, repo, pullnum string, mergeStyle repo_model.MergeStyle, deleteBranch bool) *httptest.ResponseRecorder {
req := NewRequest(t, "GET", path.Join(user, repo, "pulls", pullnum))
resp := session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
link := path.Join(user, repo, "pulls", pullnum, "merge")
type MergeOptions struct {
Style repo_model.MergeStyle
HeadCommitID string
DeleteBranch bool
}
func testPullMerge(t *testing.T, session *TestSession, user, repo, pullNum string, mergeOptions MergeOptions) *httptest.ResponseRecorder {
options := map[string]string{
"_csrf": htmlDoc.GetCSRF(),
"do": string(mergeStyle),
"do": string(mergeOptions.Style),
"head_commit_id": mergeOptions.HeadCommitID,
"delete_branch_after_merge": util.Iif(mergeOptions.DeleteBranch, "on", ""),
}
var resp *httptest.ResponseRecorder
require.Eventually(t, func() bool {
req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/pulls/%s/merge", user, repo, pullNum), options)
resp = session.MakeRequest(t, req, NoExpectedStatus)
return resp.Code == http.StatusOK
}, 5*time.Second, 50*time.Millisecond, "Timed out waiting for pull merge to succeed")
if deleteBranch {
options["delete_branch_after_merge"] = "on"
}
redirect := test.RedirectURL(resp)
assert.Equal(t, fmt.Sprintf("/%s/%s/pulls/%s", user, repo, pullNum), redirect)
req = NewRequestWithValues(t, "POST", link, options)
resp = session.MakeRequest(t, req, http.StatusOK)
respJSON := struct {
Redirect string
}{}
DecodeJSON(t, resp, &respJSON)
assert.Equal(t, fmt.Sprintf("/%s/%s/pulls/%s", user, repo, pullnum), respJSON.Redirect)
pullNumInt, err := strconv.ParseInt(pullNum, 10, 64)
assert.NoError(t, err)
repository, err := repo_model.GetRepositoryByOwnerAndName(t.Context(), user, repo)
assert.NoError(t, err)
pull, err := issues_model.GetPullRequestByIndex(t.Context(), repository.ID, pullNumInt)
assert.NoError(t, err)
assert.True(t, pull.HasMerged)
return resp
}
@@ -81,9 +85,7 @@ func testPullCleanUp(t *testing.T, session *TestSession, user, repo, pullnum str
htmlDoc := NewHTMLParser(t, resp.Body)
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(),
})
req = NewRequest(t, "POST", link)
resp = session.MakeRequest(t, req, http.StatusOK)
return resp
@@ -95,7 +97,7 @@ func TestPullMerge(t *testing.T) {
assert.NoError(t, err)
hookTasksLenBefore := len(hookTasks)
session := loginUser(t, "user1")
session := loginUser(t, "user1") // FIXME: don't use admin user for testing
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
@@ -111,7 +113,10 @@ func TestPullMerge(t *testing.T) {
elem := strings.Split(test.RedirectURL(resp), "/")
assert.Equal(t, "pulls", elem[3])
testPullMerge(t, session, elem[1], elem[2], elem[4], repo_model.MergeStyleMerge, false)
testPullMerge(t, session, elem[1], elem[2], elem[4], MergeOptions{
Style: repo_model.MergeStyleMerge,
DeleteBranch: false,
})
repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo.ID})
assert.Equal(t, 4, repo.NumPulls)
@@ -129,7 +134,7 @@ func TestPullRebase(t *testing.T) {
assert.NoError(t, err)
hookTasksLenBefore := len(hookTasks)
session := loginUser(t, "user1")
session := loginUser(t, "user1") // FIXME: don't use admin user for testing
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
@@ -145,7 +150,10 @@ func TestPullRebase(t *testing.T) {
elem := strings.Split(test.RedirectURL(resp), "/")
assert.Equal(t, "pulls", elem[3])
testPullMerge(t, session, elem[1], elem[2], elem[4], repo_model.MergeStyleRebase, false)
testPullMerge(t, session, elem[1], elem[2], elem[4], MergeOptions{
Style: repo_model.MergeStyleRebase,
DeleteBranch: false,
})
repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo.ID})
assert.Equal(t, 4, repo.NumPulls)
@@ -163,7 +171,7 @@ func TestPullRebaseMerge(t *testing.T) {
assert.NoError(t, err)
hookTasksLenBefore := len(hookTasks)
session := loginUser(t, "user1")
session := loginUser(t, "user1") // FIXME: don't use admin user for testing
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
@@ -179,7 +187,10 @@ func TestPullRebaseMerge(t *testing.T) {
elem := strings.Split(test.RedirectURL(resp), "/")
assert.Equal(t, "pulls", elem[3])
testPullMerge(t, session, elem[1], elem[2], elem[4], repo_model.MergeStyleRebaseMerge, false)
testPullMerge(t, session, elem[1], elem[2], elem[4], MergeOptions{
Style: repo_model.MergeStyleRebaseMerge,
DeleteBranch: false,
})
repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo.ID})
assert.Equal(t, 4, repo.NumPulls)
@@ -197,7 +208,7 @@ func TestPullSquash(t *testing.T) {
assert.NoError(t, err)
hookTasksLenBefore := len(hookTasks)
session := loginUser(t, "user1")
session := loginUser(t, "user1") // FIXME: don't use admin user for testing
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited!)\n")
@@ -206,7 +217,54 @@ func TestPullSquash(t *testing.T) {
elem := strings.Split(test.RedirectURL(resp), "/")
assert.Equal(t, "pulls", elem[3])
testPullMerge(t, session, elem[1], elem[2], elem[4], repo_model.MergeStyleSquash, false)
testPullMerge(t, session, elem[1], elem[2], elem[4], MergeOptions{
Style: repo_model.MergeStyleSquash,
DeleteBranch: false,
})
hookTasks, err = webhook.HookTasks(t.Context(), 1, 1)
assert.NoError(t, err)
assert.Len(t, hookTasks, hookTasksLenBefore+1)
})
}
func TestPullSquashWithHeadCommitID(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
hookTasks, err := webhook.HookTasks(t.Context(), 1, 1) // Retrieve previous hook number
assert.NoError(t, err)
hookTasksLenBefore := len(hookTasks)
session := loginUser(t, "user1") // FIXME: don't use admin user for testing
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited!)\n")
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user2", Name: "repo1"})
assert.Equal(t, 3, repo.NumPulls)
assert.Equal(t, 3, repo.NumOpenPulls)
resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "This is a pull title")
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user1", Name: "repo1"})
headBranch, err := git_model.GetBranch(t.Context(), repo1.ID, "master")
assert.NoError(t, err)
assert.NotNil(t, headBranch)
elem := strings.Split(test.RedirectURL(resp), "/")
assert.Equal(t, "pulls", elem[3])
repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo.ID})
assert.Equal(t, 4, repo.NumPulls)
assert.Equal(t, 4, repo.NumOpenPulls)
testPullMerge(t, session, elem[1], elem[2], elem[4], MergeOptions{
Style: repo_model.MergeStyleSquash,
DeleteBranch: false,
HeadCommitID: headBranch.CommitID,
})
repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo.ID})
assert.Equal(t, 4, repo.NumPulls)
assert.Equal(t, 3, repo.NumOpenPulls)
hookTasks, err = webhook.HookTasks(t.Context(), 1, 1)
assert.NoError(t, err)
@@ -216,7 +274,7 @@ func TestPullSquash(t *testing.T) {
func TestPullCleanUpAfterMerge(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
session := loginUser(t, "user1")
session := loginUser(t, "user1") // FIXME: don't use admin user for testing
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "feature/test", "README.md", "Hello, World (Edited - TestPullCleanUpAfterMerge)\n")
@@ -228,11 +286,15 @@ func TestPullCleanUpAfterMerge(t *testing.T) {
elem := strings.Split(test.RedirectURL(resp), "/")
assert.Equal(t, "pulls", elem[3])
repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo.ID})
assert.Equal(t, 4, repo.NumPulls)
assert.Equal(t, 4, repo.NumOpenPulls)
testPullMerge(t, session, elem[1], elem[2], elem[4], repo_model.MergeStyleMerge, false)
testPullMerge(t, session, elem[1], elem[2], elem[4], MergeOptions{
Style: repo_model.MergeStyleMerge,
DeleteBranch: false,
})
repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo.ID})
assert.Equal(t, 4, repo.NumPulls)
@@ -263,7 +325,7 @@ func TestPullCleanUpAfterMerge(t *testing.T) {
func TestCantMergeWorkInProgress(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
session := loginUser(t, "user1")
session := loginUser(t, "user1") // FIXME: don't use admin user for testing
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
@@ -282,7 +344,7 @@ func TestCantMergeWorkInProgress(t *testing.T) {
func TestCantMergeConflict(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
session := loginUser(t, "user1")
session := loginUser(t, "user1") // FIXME: don't use admin user for testing
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "conflict", "README.md", "Hello, World (Edited Once)\n")
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "base", "README.md", "Hello, World (Edited Twice)\n")
@@ -312,23 +374,19 @@ func TestCantMergeConflict(t *testing.T) {
BaseBranch: "base",
})
gitRepo, err := gitrepo.OpenRepository(t.Context(), repo1)
assert.NoError(t, err)
err = pull_service.Merge(t.Context(), pr, user1, gitRepo, repo_model.MergeStyleMerge, "", "CONFLICT", false)
err := pull_service.Merge(t.Context(), pr, user1, repo_model.MergeStyleMerge, "", "CONFLICT", false)
assert.Error(t, err, "Merge should return an error due to conflict")
assert.True(t, pull_service.IsErrMergeConflicts(err), "Merge error is not a conflict error")
err = pull_service.Merge(t.Context(), pr, user1, gitRepo, repo_model.MergeStyleRebase, "", "CONFLICT", false)
err = pull_service.Merge(t.Context(), pr, user1, repo_model.MergeStyleRebase, "", "CONFLICT", false)
assert.Error(t, err, "Merge should return an error due to conflict")
assert.True(t, pull_service.IsErrRebaseConflicts(err), "Merge error is not a conflict error")
gitRepo.Close()
})
}
func TestCantMergeUnrelated(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
session := loginUser(t, "user1")
session := loginUser(t, "user1") // FIXME: don't use admin user for testing
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "base", "README.md", "Hello, World (Edited Twice)\n")
@@ -343,24 +401,24 @@ func TestCantMergeUnrelated(t *testing.T) {
})
path := repo_model.RepoPath(user1.Name, repo1.Name)
err := gitcmd.NewCommand("read-tree", "--empty").Run(t.Context(), &gitcmd.RunOpts{Dir: path})
err := gitcmd.NewCommand("read-tree", "--empty").WithDir(path).Run(t.Context())
assert.NoError(t, err)
stdin := strings.NewReader("Unrelated File")
var stdout strings.Builder
err = gitcmd.NewCommand("hash-object", "-w", "--stdin").Run(t.Context(), &gitcmd.RunOpts{
Dir: path,
Stdin: stdin,
Stdout: &stdout,
})
stdout, _, err := gitcmd.NewCommand("hash-object", "-w", "--stdin").
WithDir(path).
WithStdinBytes([]byte("Unrelated File")).
RunStdString(t.Context())
assert.NoError(t, err)
sha := strings.TrimSpace(stdout.String())
sha := strings.TrimSpace(stdout)
_, _, err = gitcmd.NewCommand("update-index", "--add", "--replace", "--cacheinfo").AddDynamicArguments("100644", sha, "somewher-over-the-rainbow").RunStdString(t.Context(), &gitcmd.RunOpts{Dir: path})
_, _, err = gitcmd.NewCommand("update-index", "--add", "--replace", "--cacheinfo").
AddDynamicArguments("100644", sha, "somewhere-over-the-rainbow").
WithDir(path).
RunStdString(t.Context())
assert.NoError(t, err)
treeSha, _, err := gitcmd.NewCommand("write-tree").RunStdString(t.Context(), &gitcmd.RunOpts{Dir: path})
treeSha, _, err := gitcmd.NewCommand("write-tree").WithDir(path).RunStdString(t.Context())
assert.NoError(t, err)
treeSha = strings.TrimSpace(treeSha)
@@ -379,18 +437,18 @@ func TestCantMergeUnrelated(t *testing.T) {
_, _ = messageBytes.WriteString("Unrelated")
_, _ = messageBytes.WriteString("\n")
stdout.Reset()
err = gitcmd.NewCommand("commit-tree").AddDynamicArguments(treeSha).
Run(t.Context(), &gitcmd.RunOpts{
Env: env,
Dir: path,
Stdin: messageBytes,
Stdout: &stdout,
})
stdout, _, err = gitcmd.NewCommand("commit-tree").AddDynamicArguments(treeSha).
WithEnv(env).
WithDir(path).
WithStdinBytes(messageBytes.Bytes()).
RunStdString(t.Context())
assert.NoError(t, err)
commitSha := strings.TrimSpace(stdout.String())
commitSha := strings.TrimSpace(stdout)
_, _, err = gitcmd.NewCommand("branch", "unrelated").AddDynamicArguments(commitSha).RunStdString(t.Context(), &gitcmd.RunOpts{Dir: path})
_, _, err = gitcmd.NewCommand("branch", "unrelated").
AddDynamicArguments(commitSha).
WithDir(path).
RunStdString(t.Context())
assert.NoError(t, err)
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "conflict", "README.md", "Hello, World (Edited Once)\n")
@@ -405,8 +463,6 @@ func TestCantMergeUnrelated(t *testing.T) {
session.MakeRequest(t, req, http.StatusCreated)
// Now this PR could be marked conflict - or at least a race may occur - so drop down to pure code at this point...
gitRepo, err := gitrepo.OpenRepository(t.Context(), repo1)
assert.NoError(t, err)
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{
HeadRepoID: repo1.ID,
BaseRepoID: repo1.ID,
@@ -414,16 +470,15 @@ func TestCantMergeUnrelated(t *testing.T) {
BaseBranch: "base",
})
err = pull_service.Merge(t.Context(), pr, user1, gitRepo, repo_model.MergeStyleMerge, "", "UNRELATED", false)
err = pull_service.Merge(t.Context(), pr, user1, repo_model.MergeStyleMerge, "", "UNRELATED", false)
assert.Error(t, err, "Merge should return an error due to unrelated")
assert.True(t, pull_service.IsErrMergeUnrelatedHistories(err), "Merge error is not a unrelated histories error")
gitRepo.Close()
})
}
func TestFastForwardOnlyMerge(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
session := loginUser(t, "user1")
session := loginUser(t, "user1") // FIXME: don't use admin user for testing
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "update", "README.md", "Hello, World 2\n")
@@ -451,20 +506,14 @@ func TestFastForwardOnlyMerge(t *testing.T) {
BaseBranch: "master",
})
gitRepo, err := git.OpenRepository(t.Context(), repo_model.RepoPath(user1.Name, repo1.Name))
err := pull_service.Merge(t.Context(), pr, user1, repo_model.MergeStyleFastForwardOnly, "", "FAST-FORWARD-ONLY", false)
assert.NoError(t, err)
err = pull_service.Merge(t.Context(), pr, user1, gitRepo, repo_model.MergeStyleFastForwardOnly, "", "FAST-FORWARD-ONLY", false)
assert.NoError(t, err)
gitRepo.Close()
})
}
func TestCantFastForwardOnlyMergeDiverging(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
session := loginUser(t, "user1")
session := loginUser(t, "user1") // FIXME: don't use admin user for testing
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "diverging", "README.md", "Hello, World diverged\n")
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World 2\n")
@@ -493,101 +542,15 @@ func TestCantFastForwardOnlyMergeDiverging(t *testing.T) {
BaseBranch: "master",
})
gitRepo, err := git.OpenRepository(t.Context(), repo_model.RepoPath(user1.Name, repo1.Name))
assert.NoError(t, err)
err = pull_service.Merge(t.Context(), pr, user1, gitRepo, repo_model.MergeStyleFastForwardOnly, "", "DIVERGING", false)
err := pull_service.Merge(t.Context(), pr, user1, repo_model.MergeStyleFastForwardOnly, "", "DIVERGING", false)
assert.Error(t, err, "Merge should return an error due to being for a diverging branch")
assert.True(t, pull_service.IsErrMergeDivergingFastForwardOnly(err), "Merge error is not a diverging fast-forward-only error")
gitRepo.Close()
})
}
func TestConflictChecking(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
// Create new clean repo to test conflict checking.
baseRepo, err := repo_service.CreateRepository(t.Context(), user, user, repo_service.CreateRepoOptions{
Name: "conflict-checking",
Description: "Tempo repo",
AutoInit: true,
Readme: "Default",
DefaultBranch: "main",
})
assert.NoError(t, err)
assert.NotEmpty(t, baseRepo)
// create a commit on new branch.
_, err = files_service.ChangeRepoFiles(t.Context(), baseRepo, user, &files_service.ChangeRepoFilesOptions{
Files: []*files_service.ChangeRepoFile{
{
Operation: "create",
TreePath: "important_file",
ContentReader: strings.NewReader("Just a non-important file"),
},
},
Message: "Add a important file",
OldBranch: "main",
NewBranch: "important-secrets",
})
assert.NoError(t, err)
// create a commit on main branch.
_, err = files_service.ChangeRepoFiles(t.Context(), baseRepo, user, &files_service.ChangeRepoFilesOptions{
Files: []*files_service.ChangeRepoFile{
{
Operation: "create",
TreePath: "important_file",
ContentReader: strings.NewReader("Not the same content :P"),
},
},
Message: "Add a important file",
OldBranch: "main",
NewBranch: "main",
})
assert.NoError(t, err)
// create Pull to merge the important-secrets branch into main branch.
pullIssue := &issues_model.Issue{
RepoID: baseRepo.ID,
Title: "PR with conflict!",
PosterID: user.ID,
Poster: user,
IsPull: true,
}
pullRequest := &issues_model.PullRequest{
HeadRepoID: baseRepo.ID,
BaseRepoID: baseRepo.ID,
HeadBranch: "important-secrets",
BaseBranch: "main",
HeadRepo: baseRepo,
BaseRepo: baseRepo,
Type: issues_model.PullRequestGitea,
}
prOpts := &pull_service.NewPullRequestOptions{Repo: baseRepo, Issue: pullIssue, PullRequest: pullRequest}
err = pull_service.NewPullRequest(t.Context(), prOpts)
assert.NoError(t, err)
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{Title: "PR with conflict!"})
assert.NoError(t, issue.LoadPullRequest(t.Context()))
conflictingPR := issue.PullRequest
// Ensure conflictedFiles is populated.
assert.Len(t, conflictingPR.ConflictedFiles, 1)
// Check if status is correct.
assert.Equal(t, issues_model.PullRequestStatusConflict, conflictingPR.Status)
// Ensure that mergeable returns false
assert.False(t, conflictingPR.Mergeable(t.Context()))
})
}
func TestPullRetargetChildOnBranchDelete(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
session := loginUser(t, "user1")
session := loginUser(t, "user1") // FIXME: don't use admin user for testing
testEditFileToNewBranch(t, session, "user2", "repo1", "master", "base-pr", "README.md", "Hello, World\n(Edited - TestPullRetargetOnCleanup - base PR)\n")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFileToNewBranch(t, session, "user1", "repo1", "base-pr", "child-pr", "README.md", "Hello, World\n(Edited - TestPullRetargetOnCleanup - base PR)\n(Edited - TestPullRetargetOnCleanup - child PR)")
@@ -600,7 +563,10 @@ func TestPullRetargetChildOnBranchDelete(t *testing.T) {
elemChildPR := strings.Split(test.RedirectURL(respChildPR), "/")
assert.Equal(t, "pulls", elemChildPR[3])
testPullMerge(t, session, elemBasePR[1], elemBasePR[2], elemBasePR[4], repo_model.MergeStyleMerge, true)
testPullMerge(t, session, elemBasePR[1], elemBasePR[2], elemBasePR[4], MergeOptions{
Style: repo_model.MergeStyleMerge,
DeleteBranch: true,
})
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user2", Name: "repo1"})
branchBasePR := unittest.AssertExistsAndLoadBean(t, &git_model.Branch{RepoID: repo1.ID, Name: "base-pr"})
@@ -621,7 +587,7 @@ func TestPullRetargetChildOnBranchDelete(t *testing.T) {
func TestPullDontRetargetChildOnWrongRepo(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
session := loginUser(t, "user1")
session := loginUser(t, "user1") // FIXME: don't use admin user for testing
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "base-pr", "README.md", "Hello, World\n(Edited - TestPullDontRetargetChildOnWrongRepo - base PR)\n")
testEditFileToNewBranch(t, session, "user1", "repo1", "base-pr", "child-pr", "README.md", "Hello, World\n(Edited - TestPullDontRetargetChildOnWrongRepo - base PR)\n(Edited - TestPullDontRetargetChildOnWrongRepo - child PR)")
@@ -636,7 +602,10 @@ func TestPullDontRetargetChildOnWrongRepo(t *testing.T) {
defer test.MockVariableValue(&setting.Repository.PullRequest.RetargetChildrenOnMerge, false)()
testPullMerge(t, session, elemBasePR[1], elemBasePR[2], elemBasePR[4], repo_model.MergeStyleMerge, true)
testPullMerge(t, session, elemBasePR[1], elemBasePR[2], elemBasePR[4], MergeOptions{
Style: repo_model.MergeStyleMerge,
DeleteBranch: true,
})
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user1", Name: "repo1"})
branchBasePR := unittest.AssertExistsAndLoadBean(t, &git_model.Branch{RepoID: repo1.ID, Name: "base-pr"})
@@ -668,7 +637,10 @@ func TestPullRequestMergedWithNoPermissionDeleteBranch(t *testing.T) {
// user2 has no permission to delete branch of repo user1/repo1
session2 := loginUser(t, "user2")
testPullMerge(t, session2, elemBasePR[1], elemBasePR[2], elemBasePR[4], repo_model.MergeStyleMerge, true)
testPullMerge(t, session2, elemBasePR[1], elemBasePR[2], elemBasePR[4], MergeOptions{
Style: repo_model.MergeStyleMerge,
DeleteBranch: true,
})
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user4", Name: "repo1"})
branchBasePR := unittest.AssertExistsAndLoadBean(t, &git_model.Branch{RepoID: repo1.ID, Name: "base-pr"})
@@ -680,7 +652,7 @@ func TestPullRequestMergedWithNoPermissionDeleteBranch(t *testing.T) {
func TestPullMergeIndexerNotifier(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
// create a pull request
session := loginUser(t, "user1")
session := loginUser(t, "user1") // FIXME: don't use admin user for testing
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
createPullResp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "Indexer notifier test pull")
@@ -716,7 +688,10 @@ func TestPullMergeIndexerNotifier(t *testing.T) {
// merge the pull request
elem := strings.Split(test.RedirectURL(createPullResp), "/")
assert.Equal(t, "pulls", elem[3])
testPullMerge(t, session, elem[1], elem[2], elem[4], repo_model.MergeStyleMerge, false)
testPullMerge(t, session, elem[1], elem[2], elem[4], MergeOptions{
Style: repo_model.MergeStyleMerge,
DeleteBranch: false,
})
// check if the issue is closed
issue = unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{
@@ -737,31 +712,13 @@ func TestPullMergeIndexerNotifier(t *testing.T) {
})
}
func testResetRepo(t *testing.T, repoPath, branch, commitID string) {
f, err := os.OpenFile(filepath.Join(repoPath, "refs", "heads", branch), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o644)
assert.NoError(t, err)
_, err = f.WriteString(commitID + "\n")
assert.NoError(t, err)
f.Close()
repo, err := git.OpenRepository(t.Context(), repoPath)
assert.NoError(t, err)
defer repo.Close()
id, err := repo.GetBranchCommitID(branch)
assert.NoError(t, err)
assert.Equal(t, commitID, id)
}
func TestPullAutoMergeAfterCommitStatusSucceed(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
// create a pull request
session := loginUser(t, "user1")
session := loginUser(t, "user1") // FIXME: don't use admin user for testing
user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
forkedName := "repo1-1"
testRepoFork(t, session, "user2", "repo1", "user1", forkedName, "")
defer func() {
testDeleteRepository(t, session, "user1", forkedName)
}()
testEditFile(t, session, "user1", forkedName, "master", "README.md", "Hello, World (Edited)\n")
testPullCreate(t, session, "user1", forkedName, false, "master", "master", "Indexer notifier test pull")
@@ -774,11 +731,8 @@ func TestPullAutoMergeAfterCommitStatusSucceed(t *testing.T) {
HeadBranch: "master",
})
// add protected branch for commit status
csrf := GetUserCSRFToken(t, session)
// Change the "master" branch to "protected"
req := NewRequestWithValues(t, "POST", "/user2/repo1/settings/branches/edit", map[string]string{
"_csrf": csrf,
"rule_name": "master",
"enable_push": "true",
"enable_status_check": "true",
@@ -818,16 +772,10 @@ func TestPullAutoMergeAfterCommitStatusSucceed(t *testing.T) {
assert.NoError(t, err)
sha, err := baseGitRepo.GetRefCommitID(pr.GetGitHeadRefName())
assert.NoError(t, err)
masterCommitID, err := baseGitRepo.GetBranchCommitID("master")
assert.NoError(t, err)
branches, _, err := baseGitRepo.GetBranchNames(0, 100)
assert.NoError(t, err)
assert.ElementsMatch(t, []string{"sub-home-md-img-check", "home-md-img-check", "pr-to-update", "branch2", "DefaultBranch", "develop", "feature/1", "master"}, branches)
baseGitRepo.Close()
defer func() {
testResetRepo(t, baseRepo.RepoPath(), "master", masterCommitID)
}()
err = commitstatus_service.CreateCommitStatus(t.Context(), baseRepo, user1, sha, &git_model.CommitStatus{
State: commitstatus.CommitStatusSuccess,
@@ -848,18 +796,17 @@ func TestPullAutoMergeAfterCommitStatusSucceed(t *testing.T) {
func TestPullAutoMergeAfterCommitStatusSucceedAndApproval(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
// create a pull request
session := loginUser(t, "user1")
user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
forkedName := "repo1-2"
testRepoFork(t, session, "user2", "repo1", "user1", forkedName, "")
defer func() {
testDeleteRepository(t, session, "user1", forkedName)
}()
testEditFile(t, session, "user1", forkedName, "master", "README.md", "Hello, World (Edited)\n")
testPullCreate(t, session, "user1", forkedName, false, "master", "master", "Indexer notifier test pull")
baseUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
baseSession := loginUser(t, "user2")
forkUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5})
forkSession := loginUser(t, "user5")
forkedName := "repo1-fork"
testRepoFork(t, forkSession, "user2", "repo1", forkUser.Name, forkedName, "")
testEditFile(t, forkSession, forkUser.Name, forkedName, "master", "README.md", "Hello, World (Edited)\n")
testPullCreate(t, forkSession, forkUser.Name, forkedName, false, "master", "master", "Indexer notifier test pull")
baseRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user2", Name: "repo1"})
forkedRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user1", Name: forkedName})
forkedRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: forkUser.Name, Name: forkedName})
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{
BaseRepoID: baseRepo.ID,
BaseBranch: "master",
@@ -867,26 +814,23 @@ func TestPullAutoMergeAfterCommitStatusSucceedAndApproval(t *testing.T) {
HeadBranch: "master",
})
// add protected branch for commit status
csrf := GetUserCSRFToken(t, session)
// Change master branch to protected
req := NewRequestWithValues(t, "POST", "/user2/repo1/settings/branches/edit", map[string]string{
"_csrf": csrf,
"rule_name": "master",
"enable_push": "true",
"enable_status_check": "true",
"status_check_contexts": "gitea/actions",
"required_approvals": "1",
})
session.MakeRequest(t, req, http.StatusSeeOther)
baseSession.MakeRequest(t, req, http.StatusSeeOther)
// first time insert automerge record, return true
scheduled, err := automerge.ScheduleAutoMerge(t.Context(), user1, pr, repo_model.MergeStyleMerge, "auto merge test", false)
scheduled, err := automerge.ScheduleAutoMerge(t.Context(), baseUser, pr, repo_model.MergeStyleMerge, "auto merge test", false)
assert.NoError(t, err)
assert.True(t, scheduled)
// second time insert automerge record, return false because it does exist
scheduled, err = automerge.ScheduleAutoMerge(t.Context(), user1, pr, repo_model.MergeStyleMerge, "auto merge test", false)
scheduled, err = automerge.ScheduleAutoMerge(t.Context(), baseUser, pr, repo_model.MergeStyleMerge, "auto merge test", false)
assert.Error(t, err)
assert.False(t, scheduled)
@@ -900,14 +844,9 @@ func TestPullAutoMergeAfterCommitStatusSucceedAndApproval(t *testing.T) {
assert.NoError(t, err)
sha, err := baseGitRepo.GetRefCommitID(pr.GetGitHeadRefName())
assert.NoError(t, err)
masterCommitID, err := baseGitRepo.GetBranchCommitID("master")
assert.NoError(t, err)
baseGitRepo.Close()
defer func() {
testResetRepo(t, baseRepo.RepoPath(), "master", masterCommitID)
}()
err = commitstatus_service.CreateCommitStatus(t.Context(), baseRepo, user1, sha, &git_model.CommitStatus{
err = commitstatus_service.CreateCommitStatus(t.Context(), baseRepo, baseUser, sha, &git_model.CommitStatus{
State: commitstatus.CommitStatusSuccess,
TargetURL: "https://gitea.com",
Context: "gitea/actions",
@@ -922,19 +861,13 @@ func TestPullAutoMergeAfterCommitStatusSucceedAndApproval(t *testing.T) {
assert.Empty(t, pr.MergedCommitID)
// approve the PR from non-author
approveSession := loginUser(t, "user2")
req = NewRequest(t, "GET", fmt.Sprintf("/user2/repo1/pulls/%d", pr.Index))
resp := approveSession.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
testSubmitReview(t, approveSession, htmlDoc.GetCSRF(), "user2", "repo1", strconv.Itoa(int(pr.Index)), sha, "approve", http.StatusOK)
testSubmitReview(t, baseSession, "user2", "repo1", strconv.Itoa(int(pr.Index)), sha, "approve", http.StatusOK)
time.Sleep(2 * time.Second)
// reload pr again
pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: pr.ID})
assert.True(t, pr.HasMerged)
assert.Eventually(t, func() bool {
pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: pr.ID})
return pr.HasMerged
}, 2*time.Second, 100*time.Millisecond)
assert.NotEmpty(t, pr.MergedCommitID)
unittest.AssertNotExistsBean(t, &pull_model.AutoMerge{PullID: pr.ID})
})
}
@@ -954,10 +887,10 @@ func TestPullAutoMergeAfterCommitStatusSucceedAndApprovalForAgitFlow(t *testing.
err := os.WriteFile(path.Join(dstPath, "test_file"), []byte("## test content"), 0o666)
assert.NoError(t, err)
err = git.AddChanges(t.Context(), dstPath, true)
err = gitAddChangesDeprecated(t.Context(), dstPath, true)
assert.NoError(t, err)
err = git.CommitChanges(t.Context(), dstPath, git.CommitChangesOptions{
err = gitCommitChangesDeprecated(t.Context(), dstPath, gitCommitChangesOptions{
Committer: &git.Signature{
Email: "user2@example.com",
Name: "user2",
@@ -972,18 +905,16 @@ func TestPullAutoMergeAfterCommitStatusSucceedAndApprovalForAgitFlow(t *testing.
})
assert.NoError(t, err)
stderrBuf := &bytes.Buffer{}
err = gitcmd.NewCommand("push", "origin", "HEAD:refs/for/master", "-o").
_, stderr, err := gitcmd.NewCommand("push", "origin", "HEAD:refs/for/master", "-o").
AddDynamicArguments(`topic=test/head2`).
AddArguments("-o").
AddDynamicArguments(`title="create a test pull request with agit"`).
AddArguments("-o").
AddDynamicArguments(`description="This PR is a test pull request which created with agit"`).
Run(t.Context(), &gitcmd.RunOpts{Dir: dstPath, Stderr: stderrBuf})
WithDir(dstPath).
RunStdString(t.Context())
assert.NoError(t, err)
assert.Contains(t, stderrBuf.String(), setting.AppURL+"user2/repo1/pulls/6")
assert.Contains(t, stderr, setting.AppURL+"user2/repo1/pulls/6")
baseRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user2", Name: "repo1"})
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{
@@ -994,12 +925,9 @@ func TestPullAutoMergeAfterCommitStatusSucceedAndApprovalForAgitFlow(t *testing.
HeadBranch: "user2/test/head2",
})
session := loginUser(t, "user1")
// add protected branch for commit status
csrf := GetUserCSRFToken(t, session)
session := loginUser(t, "user1") // FIXME: don't use admin user for testing
// Change master branch to protected
req := NewRequestWithValues(t, "POST", "/user2/repo1/settings/branches/edit", map[string]string{
"_csrf": csrf,
"rule_name": "master",
"enable_push": "true",
"enable_status_check": "true",
@@ -1029,13 +957,7 @@ func TestPullAutoMergeAfterCommitStatusSucceedAndApprovalForAgitFlow(t *testing.
assert.NoError(t, err)
sha, err := baseGitRepo.GetRefCommitID(pr.GetGitHeadRefName())
assert.NoError(t, err)
masterCommitID, err := baseGitRepo.GetBranchCommitID("master")
assert.NoError(t, err)
baseGitRepo.Close()
defer func() {
testResetRepo(t, baseRepo.RepoPath(), "master", masterCommitID)
}()
err = commitstatus_service.CreateCommitStatus(t.Context(), baseRepo, user1, sha, &git_model.CommitStatus{
State: commitstatus.CommitStatusSuccess,
TargetURL: "https://gitea.com",
@@ -1049,11 +971,8 @@ func TestPullAutoMergeAfterCommitStatusSucceedAndApprovalForAgitFlow(t *testing.
assert.Empty(t, pr.MergedCommitID)
// approve the PR from non-author
approveSession := loginUser(t, "user1")
req = NewRequest(t, "GET", fmt.Sprintf("/user2/repo1/pulls/%d", pr.Index))
resp := approveSession.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
testSubmitReview(t, approveSession, htmlDoc.GetCSRF(), "user2", "repo1", strconv.Itoa(int(pr.Index)), sha, "approve", http.StatusOK)
approveSession := loginUser(t, "user1") // FIXME: don't use admin user for testing
testSubmitReview(t, approveSession, "user2", "repo1", strconv.Itoa(int(pr.Index)), sha, "approve", http.StatusOK)
// reload pr again
pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: pr.ID})
@@ -1067,11 +986,9 @@ func TestPullAutoMergeAfterCommitStatusSucceedAndApprovalForAgitFlow(t *testing.
func TestPullNonMergeForAdminWithBranchProtection(t *testing.T) {
onGiteaRun(t, func(t *testing.T, u *url.URL) {
// create a pull request
session := loginUser(t, "user1")
session := loginUser(t, "user1") // FIXME: don't use admin user for testing
forkedName := "repo1-1"
testRepoFork(t, session, "user2", "repo1", "user1", forkedName, "")
defer testDeleteRepository(t, session, "user1", forkedName)
testEditFile(t, session, "user1", forkedName, "master", "README.md", "Hello, World (Edited)\n")
testPullCreate(t, session, "user1", forkedName, false, "master", "master", "Indexer notifier test pull")
@@ -1084,11 +1001,8 @@ func TestPullNonMergeForAdminWithBranchProtection(t *testing.T) {
HeadBranch: "master",
})
// add protected branch for commit status
csrf := GetUserCSRFToken(t, session)
// Change master branch to protected
pbCreateReq := NewRequestWithValues(t, "POST", "/user2/repo1/settings/branches/edit", map[string]string{
"_csrf": csrf,
"rule_name": "master",
"enable_push": "true",
"enable_status_check": "true",
@@ -1100,7 +1014,6 @@ func TestPullNonMergeForAdminWithBranchProtection(t *testing.T) {
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
mergeReq := NewRequestWithValues(t, "POST", "/api/v1/repos/user2/repo1/pulls/6/merge", map[string]string{
"_csrf": csrf,
"head_commit_id": "",
"merge_when_checks_succeed": "false",
"force_merge": "true",
@@ -1113,7 +1026,7 @@ func TestPullNonMergeForAdminWithBranchProtection(t *testing.T) {
func TestPullSquashMergeEmpty(t *testing.T) {
onGiteaRun(t, func(t *testing.T, u *url.URL) {
session := loginUser(t, "user1")
session := loginUser(t, "user1") // FIXME: don't use admin user for testing
testEditFileToNewBranch(t, session, "user2", "repo1", "master", "pr-squash-empty", "README.md", "Hello, World (Edited)\n")
resp := testPullCreate(t, session, "user2", "repo1", false, "master", "pr-squash-empty", "This is a pull title")
@@ -1130,13 +1043,152 @@ func TestPullSquashMergeEmpty(t *testing.T) {
doGitCheckoutBranch(dstPath, "-b", "pr-squash-empty", "remotes/origin/pr-squash-empty")(t)
doGitCheckoutBranch(dstPath, "master")(t)
_, _, err := gitcmd.NewCommand("cherry-pick").AddArguments("pr-squash-empty").
RunStdString(t.Context(), &gitcmd.RunOpts{
Dir: dstPath,
})
WithDir(dstPath).
RunStdString(t.Context())
assert.NoError(t, err)
doGitPushTestRepository(dstPath)(t)
testPullMerge(t, session, elem[1], elem[2], elem[4], repo_model.MergeStyleSquash, false)
testPullMerge(t, session, elem[1], elem[2], elem[4], MergeOptions{
Style: repo_model.MergeStyleSquash,
DeleteBranch: false,
})
})
}
func TestPullSquashMessage(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
user2Session := loginUser(t, user2.Name)
defer test.MockVariableValue(&setting.Repository.PullRequest.PopulateSquashCommentWithCommitMessages, true)()
defer test.MockVariableValue(&setting.Repository.PullRequest.DefaultMergeMessageSize, 80)()
repo, err := repo_service.CreateRepository(t.Context(), user2, user2, repo_service.CreateRepoOptions{
Name: "squash-message-test",
Description: "Test squash message",
AutoInit: true,
Readme: "Default",
DefaultBranch: "main",
})
require.NoError(t, err)
type commitInfo struct {
userName string
commitMessage string
}
testCases := []struct {
name string
commitInfos []*commitInfo
expectedMessage string
}{
{
name: "Single-line messages",
commitInfos: []*commitInfo{
{
userName: user2.Name,
commitMessage: "commit msg 1",
},
{
userName: user2.Name,
commitMessage: "commit msg 2",
},
},
expectedMessage: `* commit msg 1
* commit msg 2
`,
},
{
name: "Multiple-line messages",
commitInfos: []*commitInfo{
{
userName: user2.Name,
commitMessage: `commit msg 1
Commit description.`,
},
{
userName: user2.Name,
commitMessage: `commit msg 2
- Detail 1
- Detail 2`,
},
},
expectedMessage: `* commit msg 1
Commit description.
* commit msg 2
- Detail 1
- Detail 2
`,
},
{
name: "Too long message",
commitInfos: []*commitInfo{
{
userName: user2.Name,
commitMessage: `loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong message`,
},
},
expectedMessage: `* looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo...`,
},
{
name: "Test Co-authored-by",
commitInfos: []*commitInfo{
{
userName: user2.Name,
commitMessage: "commit msg 1",
},
{
userName: "user4",
commitMessage: "commit msg 2",
},
},
expectedMessage: `* commit msg 1
* commit msg 2
---------
Co-authored-by: user4 <user4@example.com>
`,
},
}
for tcNum, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
branchName := "test-branch-" + strconv.Itoa(tcNum)
for infoIdx, info := range tc.commitInfos {
createFileOpts := createFileInBranchOptions{
CommitMessage: info.commitMessage,
CommitterName: info.userName,
CommitterEmail: util.Iif(info.userName != "", info.userName+"@example.com", ""),
OldBranch: util.Iif(infoIdx == 0, "main", branchName),
NewBranch: branchName,
}
testCreateFileInBranch(t, user2, repo, createFileOpts, map[string]string{"dummy-file-" + strconv.Itoa(infoIdx): "dummy content"})
}
resp := testPullCreateDirectly(t, user2Session, createPullRequestOptions{
BaseRepoOwner: user2.Name,
BaseRepoName: repo.Name,
BaseBranch: repo.DefaultBranch,
HeadBranch: branchName,
Title: "Pull for " + branchName,
})
elems := strings.Split(test.RedirectURL(resp), "/")
pullIndex, err := strconv.ParseInt(elems[4], 10, 64)
assert.NoError(t, err)
pullRequest := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{BaseRepoID: repo.ID, Index: pullIndex})
squashMergeCommitMessage := pull_service.GetSquashMergeCommitMessages(t.Context(), pullRequest)
assert.Equal(t, tc.expectedMessage, squashMergeCommitMessage)
})
}
})
}