From eaf179570bf1b34f743fbe57484ecad948535405 Mon Sep 17 00:00:00 2001 From: hiifong Date: Mon, 11 Aug 2025 11:07:11 +0800 Subject: [PATCH 01/18] squash merge message --- routers/web/repo/issue_view.go | 49 ++++++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/routers/web/repo/issue_view.go b/routers/web/repo/issue_view.go index d0064e763ef82..c18e5e6213309 100644 --- a/routers/web/repo/issue_view.go +++ b/routers/web/repo/issue_view.go @@ -389,6 +389,7 @@ func ViewIssue(ctx *context.Context) { prepareIssueViewSidebarPin, func(ctx *context.Context, issue *issues_model.Issue) { preparePullViewPullInfo(ctx, issue) }, preparePullViewReviewAndMerge, + prepareIssueViewSquashMergeMsg, } for _, prepareFunc := range prepareFuncs { @@ -442,6 +443,7 @@ func ViewPullMergeBox(ctx *context.Context) { } preparePullViewPullInfo(ctx, issue) preparePullViewReviewAndMerge(ctx, issue) + prepareIssueViewSquashMergeMsg(ctx, issue) ctx.Data["PullMergeBoxReloading"] = issue.PullRequest.IsChecking() // TODO: it should use a dedicated struct to render the pull merge box, to make sure all data is prepared correctly @@ -928,14 +930,6 @@ func preparePullViewReviewAndMerge(ctx *context.Context, issue *issues_model.Iss ctx.Data["DefaultMergeMessage"] = defaultMergeMessage ctx.Data["DefaultMergeBody"] = defaultMergeBody - defaultSquashMergeMessage, defaultSquashMergeBody, err := pull_service.GetDefaultMergeMessage(ctx, ctx.Repo.GitRepo, pull, repo_model.MergeStyleSquash) - if err != nil { - ctx.ServerError("GetDefaultSquashMergeMessage", err) - return - } - ctx.Data["DefaultSquashMergeMessage"] = defaultSquashMergeMessage - ctx.Data["DefaultSquashMergeBody"] = defaultSquashMergeBody - pb, err := git_model.GetFirstMatchProtectedBranchRule(ctx, pull.BaseRepoID, pull.BaseBranch) if err != nil { ctx.ServerError("LoadProtectedBranch", err) @@ -1006,3 +1000,42 @@ func prepareIssueViewContent(ctx *context.Context, issue *issues_model.Issue) { return } } + +func getIssueViewSquashMergeCommits(ctx *context.Context, issue *issues_model.Issue) (string, error) { + pull := issue.PullRequest + pull.Issue = issue + + baseCommit := GetMergedBaseCommitID(ctx, issue) + + compareInfo, err := ctx.Repo.GitRepo.GetCompareInfo(ctx.Repo.Repository.RepoPath(), + baseCommit, pull.GetGitHeadRefName(), false, false) + if err != nil { + return "", err + } + + commits := "" + for _, c := range compareInfo.Commits { + commits += fmt.Sprintf("* %s\n", c.CommitMessage) + } + + return commits, nil +} + +func prepareIssueViewSquashMergeMsg(ctx *context.Context, issue *issues_model.Issue) { + pull := issue.PullRequest + + defaultSquashMergeMessage, defaultSquashMergeBody, err := pull_service.GetDefaultMergeMessage(ctx, ctx.Repo.GitRepo, pull, repo_model.MergeStyleSquash) + if err != nil { + ctx.ServerError("GetDefaultSquashMergeMessage", err) + return + } + + commitsMsg, err := getIssueViewSquashMergeCommits(ctx, issue) + if err != nil { + ctx.ServerError("getIssueViewSquashMergeCommits", err) + return + } + + ctx.Data["DefaultSquashMergeMessage"] = defaultSquashMergeMessage + ctx.Data["DefaultSquashMergeBody"] = fmt.Sprintf("--------------------\n%s\n%s", commitsMsg, defaultSquashMergeBody) +} From 3df6e9397aed1c184c6f28ca7a661029ab2d128e Mon Sep 17 00:00:00 2001 From: hiifong Date: Mon, 11 Aug 2025 11:47:53 +0800 Subject: [PATCH 02/18] fix bug --- routers/web/repo/issue_view.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/routers/web/repo/issue_view.go b/routers/web/repo/issue_view.go index c18e5e6213309..9805e2fa63fe8 100644 --- a/routers/web/repo/issue_view.go +++ b/routers/web/repo/issue_view.go @@ -389,7 +389,10 @@ func ViewIssue(ctx *context.Context) { prepareIssueViewSidebarPin, func(ctx *context.Context, issue *issues_model.Issue) { preparePullViewPullInfo(ctx, issue) }, preparePullViewReviewAndMerge, - prepareIssueViewSquashMergeMsg, + } + + if ctx.PathParam("type") == "pulls" { + prepareFuncs = append(prepareFuncs, prepareIssueViewSquashMergeMsg) } for _, prepareFunc := range prepareFuncs { From 1e67f18f255b1249f5a9e05734ffbb3971e8e69b Mon Sep 17 00:00:00 2001 From: hiifong Date: Mon, 11 Aug 2025 11:51:50 +0800 Subject: [PATCH 03/18] fix bug --- routers/web/repo/issue_view.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routers/web/repo/issue_view.go b/routers/web/repo/issue_view.go index 9805e2fa63fe8..e51d1b5cdc36e 100644 --- a/routers/web/repo/issue_view.go +++ b/routers/web/repo/issue_view.go @@ -391,7 +391,7 @@ func ViewIssue(ctx *context.Context) { preparePullViewReviewAndMerge, } - if ctx.PathParam("type") == "pulls" { + if issue.IsPull { prepareFuncs = append(prepareFuncs, prepareIssueViewSquashMergeMsg) } From 5039cc98ac0bea990c0c9ecf9b96fd5fd4e18c55 Mon Sep 17 00:00:00 2001 From: hiifong Date: Mon, 11 Aug 2025 12:17:35 +0800 Subject: [PATCH 04/18] Update --- routers/web/repo/issue_view.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/routers/web/repo/issue_view.go b/routers/web/repo/issue_view.go index e51d1b5cdc36e..7f6f2c569c73c 100644 --- a/routers/web/repo/issue_view.go +++ b/routers/web/repo/issue_view.go @@ -392,7 +392,7 @@ func ViewIssue(ctx *context.Context) { } if issue.IsPull { - prepareFuncs = append(prepareFuncs, prepareIssueViewSquashMergeMsg) + prepareFuncs = append(prepareFuncs, preparePullViewSquashMergeMsg) } for _, prepareFunc := range prepareFuncs { @@ -446,7 +446,7 @@ func ViewPullMergeBox(ctx *context.Context) { } preparePullViewPullInfo(ctx, issue) preparePullViewReviewAndMerge(ctx, issue) - prepareIssueViewSquashMergeMsg(ctx, issue) + preparePullViewSquashMergeMsg(ctx, issue) ctx.Data["PullMergeBoxReloading"] = issue.PullRequest.IsChecking() // TODO: it should use a dedicated struct to render the pull merge box, to make sure all data is prepared correctly @@ -1024,7 +1024,7 @@ func getIssueViewSquashMergeCommits(ctx *context.Context, issue *issues_model.Is return commits, nil } -func prepareIssueViewSquashMergeMsg(ctx *context.Context, issue *issues_model.Issue) { +func preparePullViewSquashMergeMsg(ctx *context.Context, issue *issues_model.Issue) { pull := issue.PullRequest defaultSquashMergeMessage, defaultSquashMergeBody, err := pull_service.GetDefaultMergeMessage(ctx, ctx.Repo.GitRepo, pull, repo_model.MergeStyleSquash) From 11c3f7f900c00dbd558a72942af2bb6e97c44b5d Mon Sep 17 00:00:00 2001 From: hiifong Date: Mon, 11 Aug 2025 12:20:11 +0800 Subject: [PATCH 05/18] Update --- routers/web/repo/issue_view.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/routers/web/repo/issue_view.go b/routers/web/repo/issue_view.go index 7f6f2c569c73c..a75ba758ebd21 100644 --- a/routers/web/repo/issue_view.go +++ b/routers/web/repo/issue_view.go @@ -1004,7 +1004,7 @@ func prepareIssueViewContent(ctx *context.Context, issue *issues_model.Issue) { } } -func getIssueViewSquashMergeCommits(ctx *context.Context, issue *issues_model.Issue) (string, error) { +func getPullViewSquashMergeCommits(ctx *context.Context, issue *issues_model.Issue) (string, error) { pull := issue.PullRequest pull.Issue = issue @@ -1033,7 +1033,7 @@ func preparePullViewSquashMergeMsg(ctx *context.Context, issue *issues_model.Iss return } - commitsMsg, err := getIssueViewSquashMergeCommits(ctx, issue) + commitsMsg, err := getPullViewSquashMergeCommits(ctx, issue) if err != nil { ctx.ServerError("getIssueViewSquashMergeCommits", err) return From 485a27ccdd6259378909b88feac34d5c772e315f Mon Sep 17 00:00:00 2001 From: hiifong Date: Mon, 11 Aug 2025 14:45:03 +0800 Subject: [PATCH 06/18] Update --- routers/web/repo/issue_view.go | 42 +++++++++++++++------------------- routers/web/repo/pull.go | 2 +- services/pull/pull.go | 39 ++++++++++++++++--------------- 3 files changed, 39 insertions(+), 44 deletions(-) diff --git a/routers/web/repo/issue_view.go b/routers/web/repo/issue_view.go index a75ba758ebd21..c89391dc7416a 100644 --- a/routers/web/repo/issue_view.go +++ b/routers/web/repo/issue_view.go @@ -391,10 +391,6 @@ func ViewIssue(ctx *context.Context) { preparePullViewReviewAndMerge, } - if issue.IsPull { - prepareFuncs = append(prepareFuncs, preparePullViewSquashMergeMsg) - } - for _, prepareFunc := range prepareFuncs { prepareFunc(ctx, issue) if ctx.Written() { @@ -446,7 +442,6 @@ func ViewPullMergeBox(ctx *context.Context) { } preparePullViewPullInfo(ctx, issue) preparePullViewReviewAndMerge(ctx, issue) - preparePullViewSquashMergeMsg(ctx, issue) ctx.Data["PullMergeBoxReloading"] = issue.PullRequest.IsChecking() // TODO: it should use a dedicated struct to render the pull merge box, to make sure all data is prepared correctly @@ -933,6 +928,24 @@ func preparePullViewReviewAndMerge(ctx *context.Context, issue *issues_model.Iss ctx.Data["DefaultMergeMessage"] = defaultMergeMessage ctx.Data["DefaultMergeBody"] = defaultMergeBody + defaultSquashMergeMessage, defaultSquashMergeBody, err := pull_service.GetDefaultMergeMessage(ctx, ctx.Repo.GitRepo, pull, repo_model.MergeStyleSquash) + if err != nil { + ctx.ServerError("GetDefaultSquashMergeMessage", err) + return + } + _, coAuthors := pull_service.GetSquashMergeCommitMessages(ctx, pull) + + defaultSquashMergeBody += fmt.Sprintf("\n%s", coAuthors) + + commitsMsg, err := getPullViewSquashMergeCommits(ctx, issue) + if err != nil { + ctx.ServerError("getIssueViewSquashMergeCommits", err) + return + } + + ctx.Data["DefaultSquashMergeMessage"] = defaultSquashMergeMessage + ctx.Data["DefaultSquashMergeBody"] = fmt.Sprintf("--------------------\n%s\n%s", commitsMsg, defaultSquashMergeBody) + pb, err := git_model.GetFirstMatchProtectedBranchRule(ctx, pull.BaseRepoID, pull.BaseBranch) if err != nil { ctx.ServerError("LoadProtectedBranch", err) @@ -1023,22 +1036,3 @@ func getPullViewSquashMergeCommits(ctx *context.Context, issue *issues_model.Iss return commits, nil } - -func preparePullViewSquashMergeMsg(ctx *context.Context, issue *issues_model.Issue) { - pull := issue.PullRequest - - defaultSquashMergeMessage, defaultSquashMergeBody, err := pull_service.GetDefaultMergeMessage(ctx, ctx.Repo.GitRepo, pull, repo_model.MergeStyleSquash) - if err != nil { - ctx.ServerError("GetDefaultSquashMergeMessage", err) - return - } - - commitsMsg, err := getPullViewSquashMergeCommits(ctx, issue) - if err != nil { - ctx.ServerError("getIssueViewSquashMergeCommits", err) - return - } - - ctx.Data["DefaultSquashMergeMessage"] = defaultSquashMergeMessage - ctx.Data["DefaultSquashMergeBody"] = fmt.Sprintf("--------------------\n%s\n%s", commitsMsg, defaultSquashMergeBody) -} diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index bc58efeb6f693..cfad56c11e226 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -430,7 +430,7 @@ func prepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C ctx.ServerError("IsUserAllowedToUpdate", err) return nil } - ctx.Data["GetCommitMessages"] = pull_service.GetSquashMergeCommitMessages(ctx, pull) + ctx.Data["GetCommitMessages"], _ = pull_service.GetSquashMergeCommitMessages(ctx, pull) } else { ctx.Data["GetCommitMessages"] = "" } diff --git a/services/pull/pull.go b/services/pull/pull.go index e55d4f5bb194f..dd1688d47ffcb 100644 --- a/services/pull/pull.go +++ b/services/pull/pull.go @@ -784,15 +784,15 @@ func CloseRepoBranchesPulls(ctx context.Context, doer *user_model.User, repo *re var commitMessageTrailersPattern = regexp.MustCompile(`(?:^|\n\n)(?:[\w-]+[ \t]*:[^\n]+\n*(?:[ \t]+[^\n]+\n*)*)+$`) // GetSquashMergeCommitMessages returns the commit messages between head and merge base (if there is one) -func GetSquashMergeCommitMessages(ctx context.Context, pr *issues_model.PullRequest) string { +func GetSquashMergeCommitMessages(ctx context.Context, pr *issues_model.PullRequest) (string, string) { if err := pr.LoadIssue(ctx); err != nil { log.Error("Cannot load issue %d for PR id %d: Error: %v", pr.IssueID, pr.ID, err) - return "" + return "", "" } if err := pr.Issue.LoadPoster(ctx); err != nil { log.Error("Cannot load poster %d for pr id %d, index %d Error: %v", pr.Issue.PosterID, pr.ID, pr.Index, err) - return "" + return "", "" } if pr.HeadRepo == nil { @@ -800,14 +800,14 @@ func GetSquashMergeCommitMessages(ctx context.Context, pr *issues_model.PullRequ pr.HeadRepo, err = repo_model.GetRepositoryByID(ctx, pr.HeadRepoID) if err != nil { log.Error("GetRepositoryByIdCtx[%d]: %v", pr.HeadRepoID, err) - return "" + return "", "" } } gitRepo, closer, err := gitrepo.RepositoryFromContextOrOpen(ctx, pr.HeadRepo) if err != nil { log.Error("Unable to open head repository: Error: %v", err) - return "" + return "", "" } defer closer.Close() @@ -818,19 +818,19 @@ func GetSquashMergeCommitMessages(ctx context.Context, pr *issues_model.PullRequ pr.HeadCommitID, err = gitRepo.GetRefCommitID(pr.GetGitHeadRefName()) if err != nil { log.Error("Unable to get head commit: %s Error: %v", pr.GetGitHeadRefName(), err) - return "" + return "", "" } headCommit, err = gitRepo.GetCommit(pr.HeadCommitID) } if err != nil { log.Error("Unable to get head commit: %s Error: %v", pr.HeadBranch, err) - return "" + return "", "" } mergeBase, err := gitRepo.GetCommit(pr.MergeBase) if err != nil { log.Error("Unable to get merge base commit: %s Error: %v", pr.MergeBase, err) - return "" + return "", "" } limit := setting.Repository.PullRequest.DefaultMergeMessageCommitsLimit @@ -838,7 +838,7 @@ func GetSquashMergeCommitMessages(ctx context.Context, pr *issues_model.PullRequ commits, err := gitRepo.CommitsBetweenLimit(headCommit, mergeBase, limit, 0) if err != nil { log.Error("Unable to get commits between: %s %s Error: %v", pr.HeadBranch, pr.MergeBase, err) - return "" + return "", "" } posterSig := pr.Issue.Poster.NewGitSig().String() @@ -846,6 +846,7 @@ func GetSquashMergeCommitMessages(ctx context.Context, pr *issues_model.PullRequ uniqueAuthors := make(container.Set[string]) authors := make([]string, 0, len(commits)) stringBuilder := strings.Builder{} + coAuthorStringBuilder := strings.Builder{} if !setting.Repository.PullRequest.PopulateSquashCommentWithCommitMessages { message := strings.TrimSpace(pr.Issue.Content) @@ -879,12 +880,12 @@ func GetSquashMergeCommitMessages(ctx context.Context, pr *issues_model.PullRequ } if _, err := stringBuilder.Write(toWrite); err != nil { log.Error("Unable to write commit message Error: %v", err) - return "" + return "", "" } if _, err := stringBuilder.WriteRune('\n'); err != nil { log.Error("Unable to write commit message Error: %v", err) - return "" + return "", "" } } } @@ -908,7 +909,7 @@ func GetSquashMergeCommitMessages(ctx context.Context, pr *issues_model.PullRequ commits, err := gitRepo.CommitsBetweenLimit(headCommit, mergeBase, limit, skip) if err != nil { log.Error("Unable to get commits between: %s %s Error: %v", pr.HeadBranch, pr.MergeBase, err) - return "" + return "", "" } if len(commits) == 0 { break @@ -927,21 +928,21 @@ func GetSquashMergeCommitMessages(ctx context.Context, pr *issues_model.PullRequ } for _, author := range authors { - if _, err := stringBuilder.WriteString("Co-authored-by: "); err != nil { + if _, err := coAuthorStringBuilder.WriteString("Co-authored-by: "); err != nil { log.Error("Unable to write to string builder Error: %v", err) - return "" + return "", "" } - if _, err := stringBuilder.WriteString(author); err != nil { + if _, err := coAuthorStringBuilder.WriteString(author); err != nil { log.Error("Unable to write to string builder Error: %v", err) - return "" + return "", "" } - if _, err := stringBuilder.WriteRune('\n'); err != nil { + if _, err := coAuthorStringBuilder.WriteRune('\n'); err != nil { log.Error("Unable to write to string builder Error: %v", err) - return "" + return "", "" } } - return stringBuilder.String() + return stringBuilder.String(), coAuthorStringBuilder.String() } // GetIssuesAllCommitStatus returns a map of issue ID to a list of all statuses for the most recent commit as well as a map of issue ID to only the commit's latest status From 2a2400102b7fc9850bd905908488d233bb43918d Mon Sep 17 00:00:00 2001 From: hiifong Date: Mon, 11 Aug 2025 14:48:32 +0800 Subject: [PATCH 07/18] Update --- routers/web/repo/issue_view.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routers/web/repo/issue_view.go b/routers/web/repo/issue_view.go index c89391dc7416a..1ca22da0aa0eb 100644 --- a/routers/web/repo/issue_view.go +++ b/routers/web/repo/issue_view.go @@ -939,7 +939,7 @@ func preparePullViewReviewAndMerge(ctx *context.Context, issue *issues_model.Iss commitsMsg, err := getPullViewSquashMergeCommits(ctx, issue) if err != nil { - ctx.ServerError("getIssueViewSquashMergeCommits", err) + ctx.ServerError("getPullViewSquashMergeCommits", err) return } From 5807ae0fc12ac77e9abbc9d1a1337c6e68bb09f8 Mon Sep 17 00:00:00 2001 From: hiifong Date: Mon, 11 Aug 2025 14:54:53 +0800 Subject: [PATCH 08/18] Update --- routers/web/repo/issue_view.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/routers/web/repo/issue_view.go b/routers/web/repo/issue_view.go index 1ca22da0aa0eb..13056dce007f2 100644 --- a/routers/web/repo/issue_view.go +++ b/routers/web/repo/issue_view.go @@ -10,6 +10,7 @@ import ( "net/url" "sort" "strconv" + "strings" activities_model "code.gitea.io/gitea/models/activities" "code.gitea.io/gitea/models/db" @@ -1029,10 +1030,12 @@ func getPullViewSquashMergeCommits(ctx *context.Context, issue *issues_model.Iss return "", err } - commits := "" + commitsBuilder := strings.Builder{} for _, c := range compareInfo.Commits { - commits += fmt.Sprintf("* %s\n", c.CommitMessage) + commitsBuilder.WriteString("* ") + commitsBuilder.WriteString(c.CommitMessage) + commitsBuilder.WriteRune('\n') } - return commits, nil + return commitsBuilder.String(), nil } From c318cd08b6f3a438f8b05ce1d651d4d7ca629cfe Mon Sep 17 00:00:00 2001 From: hiifong Date: Mon, 11 Aug 2025 15:07:21 +0800 Subject: [PATCH 09/18] fix lint --- routers/web/repo/issue_view.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routers/web/repo/issue_view.go b/routers/web/repo/issue_view.go index 13056dce007f2..18c1207144256 100644 --- a/routers/web/repo/issue_view.go +++ b/routers/web/repo/issue_view.go @@ -936,7 +936,7 @@ func preparePullViewReviewAndMerge(ctx *context.Context, issue *issues_model.Iss } _, coAuthors := pull_service.GetSquashMergeCommitMessages(ctx, pull) - defaultSquashMergeBody += fmt.Sprintf("\n%s", coAuthors) + defaultSquashMergeBody = fmt.Sprintf("%s\n%s", defaultSquashMergeBody, coAuthors) commitsMsg, err := getPullViewSquashMergeCommits(ctx, issue) if err != nil { From 71480fc4f1a0f46115893aa88d1b87dcb8554c3e Mon Sep 17 00:00:00 2001 From: hiifong Date: Fri, 15 Aug 2025 09:43:58 +0800 Subject: [PATCH 10/18] Update --- routers/web/repo/issue_view.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/routers/web/repo/issue_view.go b/routers/web/repo/issue_view.go index 18c1207144256..786d6ead43aa3 100644 --- a/routers/web/repo/issue_view.go +++ b/routers/web/repo/issue_view.go @@ -936,7 +936,7 @@ func preparePullViewReviewAndMerge(ctx *context.Context, issue *issues_model.Iss } _, coAuthors := pull_service.GetSquashMergeCommitMessages(ctx, pull) - defaultSquashMergeBody = fmt.Sprintf("%s\n%s", defaultSquashMergeBody, coAuthors) + defaultSquashMergeBody = fmt.Sprintf("%s%s", defaultSquashMergeBody, coAuthors) commitsMsg, err := getPullViewSquashMergeCommits(ctx, issue) if err != nil { @@ -945,7 +945,7 @@ func preparePullViewReviewAndMerge(ctx *context.Context, issue *issues_model.Iss } ctx.Data["DefaultSquashMergeMessage"] = defaultSquashMergeMessage - ctx.Data["DefaultSquashMergeBody"] = fmt.Sprintf("--------------------\n%s\n%s", commitsMsg, defaultSquashMergeBody) + ctx.Data["DefaultSquashMergeBody"] = fmt.Sprintf("--------------------\n%s%s", commitsMsg, defaultSquashMergeBody) pb, err := git_model.GetFirstMatchProtectedBranchRule(ctx, pull.BaseRepoID, pull.BaseBranch) if err != nil { From b0456cfd4ce3699d1d71ce1a9bfe15cd1316a9e6 Mon Sep 17 00:00:00 2001 From: hiifong Date: Sun, 31 Aug 2025 20:11:55 +0800 Subject: [PATCH 11/18] Add test --- tests/integration/pull_merge_test.go | 97 +++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) diff --git a/tests/integration/pull_merge_test.go b/tests/integration/pull_merge_test.go index 3afa5f10f18f6..d0ad6c703ec3c 100644 --- a/tests/integration/pull_merge_test.go +++ b/tests/integration/pull_merge_test.go @@ -40,6 +40,7 @@ import ( 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/require" "github.com/stretchr/testify/assert" ) @@ -168,10 +169,104 @@ func TestPullSquash(t *testing.T) { resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "This is a pull title") - elem := strings.Split(test.RedirectURL(resp), "/") + prURL := test.RedirectURL(resp) + elem := strings.Split(prURL, "/") assert.Equal(t, "pulls", elem[3]) + + resp = session.MakeRequest(t, NewRequest(t, "GET", prURL), http.StatusOK) + htmlDoc := NewHTMLParser(t, resp.Body) + dataURL, exists := htmlDoc.doc.Find("#allow-edits-from-maintainers").Attr("data-url") + assert.True(t, exists) + req := NewRequestWithValues(t, "POST", dataURL+"/set_allow_maintainer_edit", map[string]string{ + "_csrf": htmlDoc.GetCSRF(), + "allow_maintainer_edit": "true", + }) + session.MakeRequest(t, req, http.StatusOK) + + user2Session := loginUser(t, "user2") + resp = user2Session.MakeRequest(t, NewRequest(t, "GET", prURL+"/files"), http.StatusOK) + htmlDoc = NewHTMLParser(t, resp.Body) + nodes := htmlDoc.doc.Find(".diff-file-box[data-new-filename=\"README.md\"] .diff-file-header-actions .tippy-target a") + if assert.Equal(t, 2, nodes.Length()) { + assert.Equal(t, "Edit File", nodes.Last().Text()) + editFileLink, exists := nodes.Last().Attr("href") + if assert.True(t, exists) { + // edit the file + resp := user2Session.MakeRequest(t, NewRequest(t, "GET", editFileLink), http.StatusOK) + htmlDoc := NewHTMLParser(t, resp.Body) + lastCommit := htmlDoc.GetInputValueByName("last_commit") + assert.NotEmpty(t, lastCommit) + req := NewRequestWithValues(t, "POST", editFileLink, map[string]string{ + "_csrf": htmlDoc.GetCSRF(), + "last_commit": lastCommit, + "tree_path": "README.md", + "content": "Hello, World (Edite!!)", + "commit_summary": "user2 updated the file", + "commit_choice": "direct", + }) + resp = user2Session.MakeRequest(t, req, http.StatusOK) + assert.NotEmpty(t, test.RedirectURL(resp)) + } + } + resp = user2Session.MakeRequest(t, NewRequest(t, "GET", prURL+"/files"), http.StatusOK) + htmlDoc = NewHTMLParser(t, resp.Body) + nodes = htmlDoc.doc.Find(".diff-file-box[data-new-filename=\"README.md\"] .diff-file-header-actions .tippy-target a") + if assert.Equal(t, 2, nodes.Length()) { + assert.Equal(t, "Edit File", nodes.Last().Text()) + editFileLink, exists := nodes.Last().Attr("href") + if assert.True(t, exists) { + // edit the file + resp := user2Session.MakeRequest(t, NewRequest(t, "GET", editFileLink), http.StatusOK) + htmlDoc := NewHTMLParser(t, resp.Body) + lastCommit := htmlDoc.GetInputValueByName("last_commit") + assert.NotEmpty(t, lastCommit) + req := NewRequestWithValues(t, "POST", editFileLink, map[string]string{ + "_csrf": htmlDoc.GetCSRF(), + "last_commit": lastCommit, + "tree_path": "README.md", + "content": "Hello, World (Edite!!!)", + "commit_summary": "user2 updated the file!", + "commit_choice": "direct", + }) + resp = user2Session.MakeRequest(t, req, http.StatusOK) + assert.NotEmpty(t, test.RedirectURL(resp)) + } + } + testPullMerge(t, session, elem[1], elem[2], elem[4], repo_model.MergeStyleSquash, false) + req = NewRequest(t, "GET", "/user2/repo1/src/branch/master/") + resp = user2Session.MakeRequest(t, req, http.StatusOK) + htmlDoc = NewHTMLParser(t, resp.Body) + commitHref := htmlDoc.doc.Find(".latest-commit .commit-id-short").AttrOr("href", "") + assert.NotEmpty(t, commitHref) + + req = NewRequest(t, "GET", commitHref) + resp = user2Session.MakeRequest(t, req, http.StatusOK) + htmlDoc = NewHTMLParser(t, resp.Body) + prTitle, exists := htmlDoc.doc.Find(".commit-summary").Attr("title") + assert.True(t, exists) + assert.Contains(t, prTitle, "This is a pull title") + + commitBody := htmlDoc.doc.Find(".commit-body").Text() + assert.NotEmpty(t, commitBody) + assert.Contains(t, commitBody, "--------------------") + + req = NewRequest(t, "GET", fmt.Sprintf("/user2/repo1/pulls/%s/commits/list", elem[4])) + resp = user2Session.MakeRequest(t, req, http.StatusOK) + + var pullCommitList struct { + Commits []pull_service.CommitInfo `json:"commits"` + LastReviewCommitSha string `json:"last_review_commit_sha"` + } + DecodeJSON(t, resp, &pullCommitList) + + require.Len(t, pullCommitList.Commits, 4) + + for _, commit := range pullCommitList.Commits { + assert.Contains(t, commitBody, fmt.Sprintf("* %s", commit.Summary)) + } + hookTasks, err = webhook.HookTasks(db.DefaultContext, 1, 1) assert.NoError(t, err) assert.Len(t, hookTasks, hookTasksLenBefore+1) From dd8191fb5189df88ee912dac5228bca5436f3547 Mon Sep 17 00:00:00 2001 From: hiifong Date: Mon, 1 Sep 2025 10:25:22 +0800 Subject: [PATCH 12/18] fix test --- tests/integration/pull_merge_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integration/pull_merge_test.go b/tests/integration/pull_merge_test.go index 7b3bfdc23b9a3..f5e457918555d 100644 --- a/tests/integration/pull_merge_test.go +++ b/tests/integration/pull_merge_test.go @@ -39,9 +39,9 @@ import ( 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/require" "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 { @@ -263,7 +263,7 @@ func TestPullSquash(t *testing.T) { require.Len(t, pullCommitList.Commits, 4) for _, commit := range pullCommitList.Commits { - assert.Contains(t, commitBody, fmt.Sprintf("* %s", commit.Summary)) + assert.Contains(t, commitBody, "* "+commit.Summary) } hookTasks, err = webhook.HookTasks(t.Context(), 1, 1) From 099ccf229df14f0a663186f4864daadc0b18d9a6 Mon Sep 17 00:00:00 2001 From: hiifong Date: Tue, 2 Sep 2025 09:54:37 +0800 Subject: [PATCH 13/18] fix test --- tests/integration/pull_merge_test.go | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/tests/integration/pull_merge_test.go b/tests/integration/pull_merge_test.go index f5e457918555d..864c3a406c53f 100644 --- a/tests/integration/pull_merge_test.go +++ b/tests/integration/pull_merge_test.go @@ -44,16 +44,22 @@ import ( "github.com/stretchr/testify/require" ) -func testPullMerge(t *testing.T, session *TestSession, user, repo, pullnum string, mergeStyle repo_model.MergeStyle, deleteBranch bool) *httptest.ResponseRecorder { +func testPullMerge(t *testing.T, session *TestSession, user, repo, pullnum string, mergeStyle repo_model.MergeStyle, deleteBranch bool, messages ...string) *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") + message := "" + if len(messages) > 0 { + message = messages[0] + } + options := map[string]string{ - "_csrf": htmlDoc.GetCSRF(), - "do": string(mergeStyle), + "_csrf": htmlDoc.GetCSRF(), + "do": string(mergeStyle), + "merge_message_field": message, } if deleteBranch { @@ -167,7 +173,6 @@ func TestPullSquash(t *testing.T) { testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited!)\n") resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "This is a pull title") - prURL := test.RedirectURL(resp) elem := strings.Split(prURL, "/") assert.Equal(t, "pulls", elem[3]) @@ -232,7 +237,8 @@ func TestPullSquash(t *testing.T) { } } - testPullMerge(t, session, elem[1], elem[2], elem[4], repo_model.MergeStyleSquash, false) + message := "This a pull description\n--------------------\n* user2 updated the file!\n* user2 updated the file\n* Update README.md\n* Update README.md\n" + testPullMerge(t, session, elem[1], elem[2], elem[4], repo_model.MergeStyleSquash, false, message) req = NewRequest(t, "GET", "/user2/repo1/src/branch/master/") resp = user2Session.MakeRequest(t, req, http.StatusOK) From 3703c2cd0ba5fa89024dda9974737e0e03dfd63a Mon Sep 17 00:00:00 2001 From: hiifong Date: Tue, 2 Sep 2025 10:20:16 +0800 Subject: [PATCH 14/18] fix test --- routers/web/repo/issue_view.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/routers/web/repo/issue_view.go b/routers/web/repo/issue_view.go index 786d6ead43aa3..e79330a992f05 100644 --- a/routers/web/repo/issue_view.go +++ b/routers/web/repo/issue_view.go @@ -1024,8 +1024,7 @@ func getPullViewSquashMergeCommits(ctx *context.Context, issue *issues_model.Iss baseCommit := GetMergedBaseCommitID(ctx, issue) - compareInfo, err := ctx.Repo.GitRepo.GetCompareInfo(ctx.Repo.Repository.RepoPath(), - baseCommit, pull.GetGitHeadRefName(), false, false) + compareInfo, err := pull_service.GetCompareInfo(ctx, ctx.Repo.Repository, ctx.Repo.Repository, ctx.Repo.GitRepo, baseCommit, pull.GetGitHeadRefName(), false, false) if err != nil { return "", err } From 7d53f05c85112b90b241a9a9567aa67a3188fe6d Mon Sep 17 00:00:00 2001 From: hiifong Date: Tue, 2 Sep 2025 10:48:08 +0800 Subject: [PATCH 15/18] fix test --- tests/integration/pull_merge_test.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tests/integration/pull_merge_test.go b/tests/integration/pull_merge_test.go index 864c3a406c53f..1292be2451589 100644 --- a/tests/integration/pull_merge_test.go +++ b/tests/integration/pull_merge_test.go @@ -12,6 +12,7 @@ import ( "os" "path" "path/filepath" + "regexp" "strconv" "strings" "testing" @@ -40,6 +41,7 @@ import ( commitstatus_service "code.gitea.io/gitea/services/repository/commitstatus" files_service "code.gitea.io/gitea/services/repository/files" + "github.com/PuerkitoBio/goquery" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -237,7 +239,18 @@ func TestPullSquash(t *testing.T) { } } - message := "This a pull description\n--------------------\n* user2 updated the file!\n* user2 updated the file\n* Update README.md\n* Update README.md\n" + resp = session.MakeRequest(t, NewRequest(t, "GET", prURL+"/merge_box"), http.StatusOK) + htmlDoc = NewHTMLParser(t, resp.Body) + message := "" + htmlDoc.doc.Find("script").Each(func(i int, s *goquery.Selection) { + scriptContent := s.Text() + re := regexp.MustCompile(`const\s+defaultSquashMergeMessage\s*=\s*"(.*?)"\s*;`) + matches := re.FindStringSubmatch(scriptContent) + if len(matches) > 1 { + message = matches[1] + } + }) + testPullMerge(t, session, elem[1], elem[2], elem[4], repo_model.MergeStyleSquash, false, message) req = NewRequest(t, "GET", "/user2/repo1/src/branch/master/") From 05c4db8de0f275e3b487db7fadf4b80d5f4f02de Mon Sep 17 00:00:00 2001 From: hiifong Date: Tue, 2 Sep 2025 14:00:20 +0800 Subject: [PATCH 16/18] fix test --- routers/web/repo/issue_view.go | 44 ++++++++++------------------------ 1 file changed, 13 insertions(+), 31 deletions(-) diff --git a/routers/web/repo/issue_view.go b/routers/web/repo/issue_view.go index e79330a992f05..5571e54bd34cf 100644 --- a/routers/web/repo/issue_view.go +++ b/routers/web/repo/issue_view.go @@ -388,8 +388,10 @@ func ViewIssue(ctx *context.Context) { prepareIssueViewSidebarTimeTracker, prepareIssueViewSidebarDependency, prepareIssueViewSidebarPin, - func(ctx *context.Context, issue *issues_model.Issue) { preparePullViewPullInfo(ctx, issue) }, - preparePullViewReviewAndMerge, + func(ctx *context.Context, issue *issues_model.Issue) { + compareInfo := preparePullViewPullInfo(ctx, issue) + preparePullViewReviewAndMerge(ctx, issue, compareInfo) + }, } for _, prepareFunc := range prepareFuncs { @@ -441,8 +443,8 @@ func ViewPullMergeBox(ctx *context.Context) { ctx.NotFound(nil) return } - preparePullViewPullInfo(ctx, issue) - preparePullViewReviewAndMerge(ctx, issue) + compareInfo := preparePullViewPullInfo(ctx, issue) + preparePullViewReviewAndMerge(ctx, issue, compareInfo) ctx.Data["PullMergeBoxReloading"] = issue.PullRequest.IsChecking() // TODO: it should use a dedicated struct to render the pull merge box, to make sure all data is prepared correctly @@ -823,7 +825,7 @@ func prepareIssueViewCommentsAndSidebarParticipants(ctx *context.Context, issue ctx.Data["NumParticipants"] = len(participants) } -func preparePullViewReviewAndMerge(ctx *context.Context, issue *issues_model.Issue) { +func preparePullViewReviewAndMerge(ctx *context.Context, issue *issues_model.Issue, compareInfo *pull_service.CompareInfo) { getBranchData(ctx, issue) if !issue.IsPull { return @@ -938,14 +940,15 @@ func preparePullViewReviewAndMerge(ctx *context.Context, issue *issues_model.Iss defaultSquashMergeBody = fmt.Sprintf("%s%s", defaultSquashMergeBody, coAuthors) - commitsMsg, err := getPullViewSquashMergeCommits(ctx, issue) - if err != nil { - ctx.ServerError("getPullViewSquashMergeCommits", err) - return + commitsBuilder := strings.Builder{} + for _, c := range compareInfo.Commits { + commitsBuilder.WriteString("* ") + commitsBuilder.WriteString(c.CommitMessage) + commitsBuilder.WriteRune('\n') } ctx.Data["DefaultSquashMergeMessage"] = defaultSquashMergeMessage - ctx.Data["DefaultSquashMergeBody"] = fmt.Sprintf("--------------------\n%s%s", commitsMsg, defaultSquashMergeBody) + ctx.Data["DefaultSquashMergeBody"] = fmt.Sprintf("--------------------\n%s%s", commitsBuilder.String(), defaultSquashMergeBody) pb, err := git_model.GetFirstMatchProtectedBranchRule(ctx, pull.BaseRepoID, pull.BaseBranch) if err != nil { @@ -1017,24 +1020,3 @@ func prepareIssueViewContent(ctx *context.Context, issue *issues_model.Issue) { return } } - -func getPullViewSquashMergeCommits(ctx *context.Context, issue *issues_model.Issue) (string, error) { - pull := issue.PullRequest - pull.Issue = issue - - baseCommit := GetMergedBaseCommitID(ctx, issue) - - compareInfo, err := pull_service.GetCompareInfo(ctx, ctx.Repo.Repository, ctx.Repo.Repository, ctx.Repo.GitRepo, baseCommit, pull.GetGitHeadRefName(), false, false) - if err != nil { - return "", err - } - - commitsBuilder := strings.Builder{} - for _, c := range compareInfo.Commits { - commitsBuilder.WriteString("* ") - commitsBuilder.WriteString(c.CommitMessage) - commitsBuilder.WriteRune('\n') - } - - return commitsBuilder.String(), nil -} From b09ada694e9cb637bf1452d196b16616d79ee4df Mon Sep 17 00:00:00 2001 From: hiifong Date: Wed, 3 Sep 2025 11:14:23 +0800 Subject: [PATCH 17/18] fix test --- routers/web/repo/issue_view.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/routers/web/repo/issue_view.go b/routers/web/repo/issue_view.go index 5571e54bd34cf..59e85dd8123a7 100644 --- a/routers/web/repo/issue_view.go +++ b/routers/web/repo/issue_view.go @@ -949,6 +949,9 @@ func preparePullViewReviewAndMerge(ctx *context.Context, issue *issues_model.Iss ctx.Data["DefaultSquashMergeMessage"] = defaultSquashMergeMessage ctx.Data["DefaultSquashMergeBody"] = fmt.Sprintf("--------------------\n%s%s", commitsBuilder.String(), defaultSquashMergeBody) + if len(pull.Issue.Content) == 0 { + ctx.Data["DefaultSquashMergeBody"] = fmt.Sprintf("%s%s", commitsBuilder.String(), defaultSquashMergeBody) + } pb, err := git_model.GetFirstMatchProtectedBranchRule(ctx, pull.BaseRepoID, pull.BaseBranch) if err != nil { From daf7629eb89a6517c46cb6f839873a1bdd90bcec Mon Sep 17 00:00:00 2001 From: hiifong Date: Wed, 3 Sep 2025 11:54:12 +0800 Subject: [PATCH 18/18] fix test --- tests/integration/pull_create_test.go | 12 +++++++++--- tests/integration/pull_merge_test.go | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/tests/integration/pull_create_test.go b/tests/integration/pull_create_test.go index aeff5e2b4e076..9224d9897183b 100644 --- a/tests/integration/pull_create_test.go +++ b/tests/integration/pull_create_test.go @@ -20,7 +20,7 @@ import ( "github.com/stretchr/testify/assert" ) -func testPullCreate(t *testing.T, session *TestSession, user, repo string, toSelf bool, targetBranch, sourceBranch, title string) *httptest.ResponseRecorder { +func testPullCreate(t *testing.T, session *TestSession, user, repo string, toSelf bool, targetBranch, sourceBranch, title string, contents ...string) *httptest.ResponseRecorder { req := NewRequest(t, "GET", path.Join(user, repo)) resp := session.MakeRequest(t, req, http.StatusOK) @@ -52,9 +52,15 @@ func testPullCreate(t *testing.T, session *TestSession, user, repo string, toSel htmlDoc = NewHTMLParser(t, resp.Body) link, exists = htmlDoc.doc.Find("form.ui.form").Attr("action") assert.True(t, exists, "The template has changed") + + content := "" + if len(contents) > 0 { + content = contents[0] + } req = NewRequestWithValues(t, "POST", link, map[string]string{ - "_csrf": htmlDoc.GetCSRF(), - "title": title, + "_csrf": htmlDoc.GetCSRF(), + "title": title, + "content": content, }) resp = session.MakeRequest(t, req, http.StatusOK) return resp diff --git a/tests/integration/pull_merge_test.go b/tests/integration/pull_merge_test.go index 1292be2451589..c74155a661e89 100644 --- a/tests/integration/pull_merge_test.go +++ b/tests/integration/pull_merge_test.go @@ -174,7 +174,7 @@ func TestPullSquash(t *testing.T) { testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n") testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited!)\n") - resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "This is a pull title") + resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "This is a pull title", "This is a pull content") prURL := test.RedirectURL(resp) elem := strings.Split(prURL, "/") assert.Equal(t, "pulls", elem[3])