Allow custom default merge message with .gitea/default_merge_message/<merge_style>_TEMPLATE.md (#18177)
* Allow custom default merge message with .gitea/MERGE_MESSAGE_<merge_style>_TEMPLATE.md * Some improvements * Follow some advices * Fix bug * Fix bug * Fix lint * Fix close comment * Fix test * Fix and docs * Improve codes * Update docs and remove unnecessary variables * return error for GetDefaultMergeMessage * Fix test * improve code * ignore unknow unit type * return error for GetDefaultMergeMessage * Update services/pull/merge.go * Some improvements * Follow some advices * Fix bug * Fix lint * Improve codes * Update docs and remove unnecessary variables * return error for GetDefaultMergeMessage * improve code * Handle deleted HeadRepo in GetDefaultMergeMessage Signed-off-by: Andrew Thornton <art27@cantab.net> * Fix test * Fix test Co-authored-by: zeripath <art27@cantab.net>
This commit is contained in:
parent
5ca224a789
commit
4344a64107
14 changed files with 292 additions and 165 deletions
|
@ -234,7 +234,7 @@ func handlePull(pullID int64, sha string) {
|
|||
defer baseGitRepo.Close()
|
||||
}
|
||||
|
||||
if err := pull_service.Merge(pr, doer, baseGitRepo, scheduledPRM.MergeStyle, "", scheduledPRM.Message); err != nil {
|
||||
if err := pull_service.Merge(ctx, pr, doer, baseGitRepo, scheduledPRM.MergeStyle, "", scheduledPRM.Message); err != nil {
|
||||
log.Error("pull_service.Merge: %v", err)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
package forms
|
||||
|
||||
import (
|
||||
stdContext "context"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
@ -602,31 +601,6 @@ func (f *MergePullRequestForm) Validate(req *http.Request, errs binding.Errors)
|
|||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
// SetDefaults if not provided for mergestyle and commit message
|
||||
func (f *MergePullRequestForm) SetDefaults(ctx stdContext.Context, pr *models.PullRequest) (err error) {
|
||||
if f.Do == "" {
|
||||
f.Do = "merge"
|
||||
}
|
||||
|
||||
f.MergeTitleField = strings.TrimSpace(f.MergeTitleField)
|
||||
if len(f.MergeTitleField) == 0 {
|
||||
switch f.Do {
|
||||
case "merge", "rebase-merge":
|
||||
f.MergeTitleField, err = pr.GetDefaultMergeMessage(ctx)
|
||||
case "squash":
|
||||
f.MergeTitleField, err = pr.GetDefaultSquashMessage(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
f.MergeMessageField = strings.TrimSpace(f.MergeMessageField)
|
||||
if len(f.MergeMessageField) > 0 {
|
||||
f.MergeTitleField += "\n\n" + f.MergeMessageField
|
||||
f.MergeMessageField = ""
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// CodeCommentForm form for adding code comments for PRs
|
||||
type CodeCommentForm struct {
|
||||
Origin string `binding:"Required;In(timeline,diff)"`
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -33,9 +34,101 @@ import (
|
|||
issue_service "code.gitea.io/gitea/services/issue"
|
||||
)
|
||||
|
||||
// GetDefaultMergeMessage returns default message used when merging pull request
|
||||
func GetDefaultMergeMessage(baseGitRepo *git.Repository, pr *models.PullRequest, mergeStyle repo_model.MergeStyle) (string, error) {
|
||||
if err := pr.LoadHeadRepo(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err := pr.LoadBaseRepo(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if pr.BaseRepo == nil {
|
||||
return "", repo_model.ErrRepoNotExist{ID: pr.BaseRepoID}
|
||||
}
|
||||
|
||||
if err := pr.LoadIssue(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
isExternalTracker := pr.BaseRepo.UnitEnabled(unit.TypeExternalTracker)
|
||||
issueReference := "#"
|
||||
if isExternalTracker {
|
||||
issueReference = "!"
|
||||
}
|
||||
|
||||
if mergeStyle != "" {
|
||||
templateFilepath := fmt.Sprintf(".gitea/default_merge_message/%s_TEMPLATE.md", strings.ToUpper(string(mergeStyle)))
|
||||
commit, err := baseGitRepo.GetBranchCommit(pr.BaseRepo.DefaultBranch)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
templateContent, err := commit.GetFileContent(templateFilepath, setting.Repository.PullRequest.DefaultMergeMessageSize)
|
||||
if err != nil {
|
||||
if !git.IsErrNotExist(err) {
|
||||
return "", err
|
||||
}
|
||||
} else {
|
||||
vars := map[string]string{
|
||||
"BaseRepoOwnerName": pr.BaseRepo.OwnerName,
|
||||
"BaseRepoName": pr.BaseRepo.Name,
|
||||
"BaseBranch": pr.BaseBranch,
|
||||
"HeadRepoOwnerName": "",
|
||||
"HeadRepoName": "",
|
||||
"HeadBranch": pr.HeadBranch,
|
||||
"PullRequestTitle": pr.Issue.Title,
|
||||
"PullRequestDescription": pr.Issue.Content,
|
||||
"PullRequestPosterName": pr.Issue.Poster.Name,
|
||||
"PullRequestIndex": strconv.FormatInt(pr.Index, 10),
|
||||
"PullRequestReference": fmt.Sprintf("%s%d", issueReference, pr.Index),
|
||||
}
|
||||
if pr.HeadRepo != nil {
|
||||
vars["HeadRepoOwnerName"] = pr.HeadRepo.OwnerName
|
||||
vars["HeadRepoName"] = pr.HeadRepo.Name
|
||||
}
|
||||
refs, err := pr.ResolveCrossReferences(baseGitRepo.Ctx)
|
||||
if err == nil {
|
||||
closeIssueIndexes := make([]string, 0, len(refs))
|
||||
closeWord := "close"
|
||||
if len(setting.Repository.PullRequest.CloseKeywords) > 0 {
|
||||
closeWord = setting.Repository.PullRequest.CloseKeywords[0]
|
||||
}
|
||||
for _, ref := range refs {
|
||||
if ref.RefAction == references.XRefActionCloses {
|
||||
closeIssueIndexes = append(closeIssueIndexes, fmt.Sprintf("%s %s%d", closeWord, issueReference, ref.Issue.Index))
|
||||
}
|
||||
}
|
||||
if len(closeIssueIndexes) > 0 {
|
||||
vars["ClosingIssues"] = strings.Join(closeIssueIndexes, ", ")
|
||||
} else {
|
||||
vars["ClosingIssues"] = ""
|
||||
}
|
||||
}
|
||||
|
||||
return os.Expand(templateContent, func(s string) string {
|
||||
return vars[s]
|
||||
}), nil
|
||||
}
|
||||
}
|
||||
|
||||
// Squash merge has a different from other styles.
|
||||
if mergeStyle == repo_model.MergeStyleSquash {
|
||||
return fmt.Sprintf("%s (%s%d)", pr.Issue.Title, issueReference, pr.Issue.Index), nil
|
||||
}
|
||||
|
||||
if pr.BaseRepoID == pr.HeadRepoID {
|
||||
return fmt.Sprintf("Merge pull request '%s' (%s%d) from %s into %s", pr.Issue.Title, issueReference, pr.Issue.Index, pr.HeadBranch, pr.BaseBranch), nil
|
||||
}
|
||||
|
||||
if pr.HeadRepo == nil {
|
||||
return fmt.Sprintf("Merge pull request '%s' (%s%d) from <deleted>:%s into %s", pr.Issue.Title, issueReference, pr.Issue.Index, pr.HeadBranch, pr.BaseBranch), nil
|
||||
}
|
||||
|
||||
return fmt.Sprintf("Merge pull request '%s' (%s%d) from %s:%s into %s", pr.Issue.Title, issueReference, pr.Issue.Index, pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseBranch), nil
|
||||
}
|
||||
|
||||
// Merge merges pull request to base repository.
|
||||
// Caller should check PR is ready to be merged (review and status checks)
|
||||
func Merge(pr *models.PullRequest, doer *user_model.User, baseGitRepo *git.Repository, mergeStyle repo_model.MergeStyle, expectedHeadCommitID, message string) error {
|
||||
func Merge(ctx context.Context, pr *models.PullRequest, doer *user_model.User, baseGitRepo *git.Repository, mergeStyle repo_model.MergeStyle, expectedHeadCommitID, message string) error {
|
||||
if err := pr.LoadHeadRepo(); err != nil {
|
||||
log.Error("LoadHeadRepo: %v", err)
|
||||
return fmt.Errorf("LoadHeadRepo: %v", err)
|
||||
|
@ -79,18 +172,18 @@ func Merge(pr *models.PullRequest, doer *user_model.User, baseGitRepo *git.Repos
|
|||
pr.Merger = doer
|
||||
pr.MergerID = doer.ID
|
||||
|
||||
if _, err := pr.SetMerged(db.DefaultContext); err != nil {
|
||||
if _, err := pr.SetMerged(ctx); err != nil {
|
||||
log.Error("setMerged [%d]: %v", pr.ID, err)
|
||||
}
|
||||
|
||||
if err := pr.LoadIssueCtx(db.DefaultContext); err != nil {
|
||||
if err := pr.LoadIssueCtx(ctx); err != nil {
|
||||
log.Error("loadIssue [%d]: %v", pr.ID, err)
|
||||
}
|
||||
|
||||
if err := pr.Issue.LoadRepo(db.DefaultContext); err != nil {
|
||||
if err := pr.Issue.LoadRepo(ctx); err != nil {
|
||||
log.Error("loadRepo for issue [%d]: %v", pr.ID, err)
|
||||
}
|
||||
if err := pr.Issue.Repo.GetOwner(db.DefaultContext); err != nil {
|
||||
if err := pr.Issue.Repo.GetOwner(ctx); err != nil {
|
||||
log.Error("GetOwner for issue repo [%d]: %v", pr.ID, err)
|
||||
}
|
||||
|
||||
|
@ -100,17 +193,17 @@ func Merge(pr *models.PullRequest, doer *user_model.User, baseGitRepo *git.Repos
|
|||
cache.Remove(pr.Issue.Repo.GetCommitsCountCacheKey(pr.BaseBranch, true))
|
||||
|
||||
// Resolve cross references
|
||||
refs, err := pr.ResolveCrossReferences(db.DefaultContext)
|
||||
refs, err := pr.ResolveCrossReferences(ctx)
|
||||
if err != nil {
|
||||
log.Error("ResolveCrossReferences: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, ref := range refs {
|
||||
if err = ref.LoadIssueCtx(db.DefaultContext); err != nil {
|
||||
if err = ref.LoadIssueCtx(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = ref.Issue.LoadRepo(db.DefaultContext); err != nil {
|
||||
if err = ref.Issue.LoadRepo(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
close := ref.RefAction == references.XRefActionCloses
|
||||
|
|
|
@ -8,6 +8,12 @@ package pull
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unit"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
@ -29,3 +35,57 @@ func TestPullRequest_CommitMessageTrailersPattern(t *testing.T) {
|
|||
assert.True(t, commitMessageTrailersPattern.MatchString("Additional whitespace is accepted.\n\nSigned-off-by \t : \tBob <bob@example.com> "))
|
||||
assert.True(t, commitMessageTrailersPattern.MatchString("Folded value.\n\nFolded-trailer: This is\n a folded\n trailer value\nOther-Trailer: Value"))
|
||||
}
|
||||
|
||||
func TestPullRequest_GetDefaultMergeMessage_InternalTracker(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
pr := unittest.AssertExistsAndLoadBean(t, &models.PullRequest{ID: 2}).(*models.PullRequest)
|
||||
|
||||
assert.NoError(t, pr.LoadBaseRepo())
|
||||
gitRepo, err := git.OpenRepository(git.DefaultContext, pr.BaseRepo.RepoPath())
|
||||
assert.NoError(t, err)
|
||||
defer gitRepo.Close()
|
||||
|
||||
mergeMessage, err := GetDefaultMergeMessage(gitRepo, pr, "")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "Merge pull request 'issue3' (#3) from branch2 into master", mergeMessage)
|
||||
|
||||
pr.BaseRepoID = 1
|
||||
pr.HeadRepoID = 2
|
||||
mergeMessage, err = GetDefaultMergeMessage(gitRepo, pr, "")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "Merge pull request 'issue3' (#3) from user2/repo1:branch2 into master", mergeMessage)
|
||||
}
|
||||
|
||||
func TestPullRequest_GetDefaultMergeMessage_ExternalTracker(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
externalTracker := repo_model.RepoUnit{
|
||||
Type: unit.TypeExternalTracker,
|
||||
Config: &repo_model.ExternalTrackerConfig{
|
||||
ExternalTrackerFormat: "https://someurl.com/{user}/{repo}/{issue}",
|
||||
},
|
||||
}
|
||||
baseRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
||||
baseRepo.Units = []*repo_model.RepoUnit{&externalTracker}
|
||||
|
||||
pr := unittest.AssertExistsAndLoadBean(t, &models.PullRequest{ID: 2, BaseRepo: baseRepo}).(*models.PullRequest)
|
||||
|
||||
assert.NoError(t, pr.LoadBaseRepo())
|
||||
gitRepo, err := git.OpenRepository(git.DefaultContext, pr.BaseRepo.RepoPath())
|
||||
assert.NoError(t, err)
|
||||
defer gitRepo.Close()
|
||||
|
||||
mergeMessage, err := GetDefaultMergeMessage(gitRepo, pr, "")
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "Merge pull request 'issue3' (!3) from branch2 into master", mergeMessage)
|
||||
|
||||
pr.BaseRepoID = 1
|
||||
pr.HeadRepoID = 2
|
||||
pr.BaseRepo = nil
|
||||
pr.HeadRepo = nil
|
||||
mergeMessage, err = GetDefaultMergeMessage(gitRepo, pr, "")
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "Merge pull request 'issue3' (#3) from user2/repo2:branch2 into master", mergeMessage)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue