mirror of
https://github.com/go-gitea/gitea.git
synced 2026-02-05 15:48:03 +01:00
fix
This commit is contained in:
@@ -116,9 +116,6 @@ const (
|
||||
CommentTypeUnpin // 37 unpin Issue/PullRequest
|
||||
|
||||
CommentTypeChangeTimeEstimate // 38 Change time estimate
|
||||
|
||||
CommentTypeMarkedAsWorkInProgress // 39 Mark PR as work in progress
|
||||
CommentTypeMarkedAsReadyForReview // 40 Mark PR as ready for review
|
||||
)
|
||||
|
||||
var commentStrings = []string{
|
||||
@@ -161,8 +158,6 @@ var commentStrings = []string{
|
||||
"pin",
|
||||
"unpin",
|
||||
"change_time_estimate",
|
||||
"marked_as_work_in_progress",
|
||||
"marked_as_ready_for_review",
|
||||
}
|
||||
|
||||
func (t CommentType) String() string {
|
||||
|
||||
@@ -208,24 +208,8 @@ func ChangeIssueTitle(ctx context.Context, issue *Issue, doer *user_model.User,
|
||||
if err = issue.LoadRepo(ctx); err != nil {
|
||||
return fmt.Errorf("loadRepo: %w", err)
|
||||
}
|
||||
|
||||
// Determine the comment type based on WIP prefix changes for pull requests
|
||||
commentType := CommentTypeChangeTitle
|
||||
if issue.IsPull {
|
||||
hadWIP := HasWorkInProgressPrefix(oldTitle)
|
||||
hasWIP := HasWorkInProgressPrefix(issue.Title)
|
||||
|
||||
if !hadWIP && hasWIP {
|
||||
// WIP prefix was added
|
||||
commentType = CommentTypeMarkedAsWorkInProgress
|
||||
} else if hadWIP && !hasWIP {
|
||||
// WIP prefix was removed
|
||||
commentType = CommentTypeMarkedAsReadyForReview
|
||||
}
|
||||
}
|
||||
|
||||
opts := &CreateCommentOptions{
|
||||
Type: commentType,
|
||||
Type: CommentTypeChangeTitle,
|
||||
Doer: doer,
|
||||
Repo: issue.Repo,
|
||||
Issue: issue,
|
||||
|
||||
@@ -658,12 +658,18 @@ func (pr *PullRequest) IsWorkInProgress(ctx context.Context) bool {
|
||||
|
||||
// HasWorkInProgressPrefix determines if the given PR title has a Work In Progress prefix
|
||||
func HasWorkInProgressPrefix(title string) bool {
|
||||
_, ok := CutWorkInProgressPrefix(title)
|
||||
return ok
|
||||
}
|
||||
|
||||
func CutWorkInProgressPrefix(title string) (origTitle string, ok bool) {
|
||||
for _, prefix := range setting.Repository.PullRequest.WorkInProgressPrefixes {
|
||||
if strings.HasPrefix(strings.ToUpper(title), strings.ToUpper(prefix)) {
|
||||
return true
|
||||
prefixLen := len(prefix)
|
||||
if prefixLen <= len(title) && util.AsciiEqualFold(title[:prefixLen], prefix) {
|
||||
return title[len(prefix):], true
|
||||
}
|
||||
}
|
||||
return false
|
||||
return title, false
|
||||
}
|
||||
|
||||
// IsFilesConflicted determines if the Pull Request has changes conflicting with the target branch.
|
||||
|
||||
48
modules/templates/util_render_comment.go
Normal file
48
modules/templates/util_render_comment.go
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package templates
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"strings"
|
||||
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
"code.gitea.io/gitea/modules/htmlutil"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/svg"
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
func commentTimelineEventIsWipToggle(c *issues_model.Comment) (isToggle, isWip bool) {
|
||||
title1, ok1 := issues_model.CutWorkInProgressPrefix(c.OldTitle)
|
||||
title2, ok2 := issues_model.CutWorkInProgressPrefix(c.NewTitle)
|
||||
return ok1 != ok2 && strings.TrimSpace(title1) == strings.TrimSpace(title2), ok2
|
||||
}
|
||||
|
||||
func (ut *RenderUtils) RenderTimelineEventBadge(c *issues_model.Comment) template.HTML {
|
||||
if c.Type == issues_model.CommentTypeChangeTitle {
|
||||
isToggle, isWip := commentTimelineEventIsWipToggle(c)
|
||||
if !isToggle {
|
||||
return svg.RenderHTML("octicon-pencil")
|
||||
}
|
||||
return util.Iif(isWip, svg.RenderHTML("octicon-git-pull-request-draft"), svg.RenderHTML("octicon-eye"))
|
||||
}
|
||||
setting.PanicInDevOrTesting("unimplemented comment type %v: %v", c.Type, c)
|
||||
return htmlutil.HTMLFormat("(CommentType:%v)", c.Type)
|
||||
}
|
||||
|
||||
func (ut *RenderUtils) RenderTimelineEventComment(c *issues_model.Comment, createdStr template.HTML) template.HTML {
|
||||
if c.Type == issues_model.CommentTypeChangeTitle {
|
||||
locale := ut.ctx.Value(translation.ContextKey).(translation.Locale)
|
||||
isToggle, isWip := commentTimelineEventIsWipToggle(c)
|
||||
if !isToggle {
|
||||
return locale.Tr("repo.issues.change_title_at", ut.RenderEmoji(c.OldTitle), ut.RenderEmoji(c.NewTitle), createdStr)
|
||||
}
|
||||
trKey := util.Iif(isWip, "repo.pulls.marked_as_work_in_progress", "repo.pulls.marked_as_ready_for_review")
|
||||
return locale.Tr(trKey, createdStr)
|
||||
}
|
||||
setting.PanicInDevOrTesting("unimplemented comment type %v: %v", c.Type, c)
|
||||
return htmlutil.HTMLFormat("(Comment:%v,%v)", c.Type, c.Content)
|
||||
}
|
||||
@@ -344,6 +344,35 @@ func (d *pullCommitStatusCheckData) CommitStatusCheckPrompt(locale translation.L
|
||||
return locale.TrString("repo.pulls.status_checking")
|
||||
}
|
||||
|
||||
func getViewPullHeadRepoInfo(ctx *context.Context, pull *issues_model.PullRequest, baseGitRepo *git.Repository) (headCommitID string, headCommitExists bool, err error) {
|
||||
if pull.HeadRepo == nil {
|
||||
return "", false, nil
|
||||
}
|
||||
headGitRepo, closer, err := gitrepo.RepositoryFromContextOrOpen(ctx, pull.HeadRepo)
|
||||
if err != nil {
|
||||
return "", false, util.Iif(errors.Is(err, util.ErrNotExist), nil, err)
|
||||
}
|
||||
defer closer.Close()
|
||||
|
||||
if pull.Flow == issues_model.PullRequestFlowGithub {
|
||||
headCommitExists, _ = git_model.IsBranchExist(ctx, pull.HeadRepo.ID, pull.HeadBranch)
|
||||
} else {
|
||||
headCommitExists = gitrepo.IsReferenceExist(ctx, pull.BaseRepo, pull.GetGitHeadRefName())
|
||||
}
|
||||
|
||||
if headCommitExists {
|
||||
if pull.Flow != issues_model.PullRequestFlowGithub {
|
||||
headCommitID, err = baseGitRepo.GetRefCommitID(pull.GetGitHeadRefName())
|
||||
} else {
|
||||
headCommitID, err = headGitRepo.GetBranchCommitID(pull.HeadBranch)
|
||||
}
|
||||
if err != nil {
|
||||
return "", false, util.Iif(errors.Is(err, util.ErrNotExist), nil, err)
|
||||
}
|
||||
}
|
||||
return headCommitID, headCommitExists, nil
|
||||
}
|
||||
|
||||
// prepareViewPullInfo show meta information for a pull request preview page
|
||||
func prepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git_service.CompareInfo {
|
||||
ctx.Data["PullRequestWorkInProgressPrefixes"] = setting.Repository.PullRequest.WorkInProgressPrefixes
|
||||
@@ -430,34 +459,10 @@ func prepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git_s
|
||||
return compareInfo
|
||||
}
|
||||
|
||||
var headBranchExist bool
|
||||
var headBranchSha string
|
||||
// HeadRepo may be missing
|
||||
if pull.HeadRepo != nil {
|
||||
headGitRepo, closer, err := gitrepo.RepositoryFromContextOrOpen(ctx, pull.HeadRepo)
|
||||
if err != nil {
|
||||
ctx.ServerError("RepositoryFromContextOrOpen", err)
|
||||
return nil
|
||||
}
|
||||
defer closer.Close()
|
||||
|
||||
if pull.Flow == issues_model.PullRequestFlowGithub {
|
||||
headBranchExist, _ = git_model.IsBranchExist(ctx, pull.HeadRepo.ID, pull.HeadBranch)
|
||||
} else {
|
||||
headBranchExist = gitrepo.IsReferenceExist(ctx, pull.BaseRepo, pull.GetGitHeadRefName())
|
||||
}
|
||||
|
||||
if headBranchExist {
|
||||
if pull.Flow != issues_model.PullRequestFlowGithub {
|
||||
headBranchSha, err = baseGitRepo.GetRefCommitID(pull.GetGitHeadRefName())
|
||||
} else {
|
||||
headBranchSha, err = headGitRepo.GetBranchCommitID(pull.HeadBranch)
|
||||
}
|
||||
if err != nil {
|
||||
ctx.ServerError("GetBranchCommitID", err)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
headBranchSha, headBranchExist, err := getViewPullHeadRepoInfo(ctx, pull, baseGitRepo)
|
||||
if err != nil {
|
||||
ctx.ServerError("getViewPullHeadRepoInfo", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if headBranchExist {
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package issue
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestChangeTitleWIPPrefix(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
// Load a pull request
|
||||
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1})
|
||||
assert.NoError(t, pr.LoadIssue(t.Context()))
|
||||
issue := pr.Issue
|
||||
|
||||
// Load repo and doer
|
||||
assert.NoError(t, issue.LoadRepo(t.Context()))
|
||||
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID})
|
||||
|
||||
// Get the WIP prefix from settings
|
||||
wipPrefix := setting.Repository.PullRequest.WorkInProgressPrefixes[0]
|
||||
|
||||
// Store original title
|
||||
originalTitle := issue.Title
|
||||
wipTitle := wipPrefix + " " + originalTitle
|
||||
|
||||
// Test 1: Add WIP prefix
|
||||
err := ChangeTitle(t.Context(), issue, doer, wipTitle)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Check that a comment was created with the correct type
|
||||
comments, err := issues_model.FindComments(t.Context(), &issues_model.FindCommentsOptions{
|
||||
IssueID: issue.ID,
|
||||
Type: issues_model.CommentTypeMarkedAsWorkInProgress,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, comments, 1, "Should have created a CommentTypeMarkedAsWorkInProgress comment")
|
||||
|
||||
// Test 2: Remove WIP prefix
|
||||
err = ChangeTitle(t.Context(), issue, doer, originalTitle)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Check that a comment was created with the correct type
|
||||
comments, err = issues_model.FindComments(t.Context(), &issues_model.FindCommentsOptions{
|
||||
IssueID: issue.ID,
|
||||
Type: issues_model.CommentTypeMarkedAsReadyForReview,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, comments, 1, "Should have created a CommentTypeMarkedAsReadyForReview comment")
|
||||
}
|
||||
|
||||
func TestChangeTitleNormalChange(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
// Load a pull request
|
||||
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1})
|
||||
assert.NoError(t, pr.LoadIssue(t.Context()))
|
||||
issue := pr.Issue
|
||||
|
||||
// Load repo and doer
|
||||
assert.NoError(t, issue.LoadRepo(t.Context()))
|
||||
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID})
|
||||
|
||||
// Store original title
|
||||
originalTitle := issue.Title
|
||||
newTitle := "New title without WIP"
|
||||
|
||||
// Ensure neither title has WIP prefix
|
||||
assert.False(t, issues_model.HasWorkInProgressPrefix(originalTitle))
|
||||
assert.False(t, issues_model.HasWorkInProgressPrefix(newTitle))
|
||||
|
||||
// Change title
|
||||
err := ChangeTitle(t.Context(), issue, doer, newTitle)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Check that a normal change title comment was created
|
||||
comments, err := issues_model.FindComments(t.Context(), &issues_model.FindCommentsOptions{
|
||||
IssueID: issue.ID,
|
||||
Type: issues_model.CommentTypeChangeTitle,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, comments, "Should have created a CommentTypeChangeTitle comment")
|
||||
|
||||
// Verify the last comment has the correct old and new titles
|
||||
lastComment := comments[len(comments)-1]
|
||||
assert.Equal(t, originalTitle, lastComment.OldTitle)
|
||||
assert.Equal(t, newTitle, lastComment.NewTitle)
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
{{template "base/alert"}}
|
||||
{{range .Issue.Comments}}
|
||||
{{range $comment := .Issue.Comments}}
|
||||
{{if call $.ShouldShowCommentType .Type}}
|
||||
{{$createdStr:= DateUtils.TimeSince .CreatedUnix}}
|
||||
|
||||
@@ -13,8 +13,7 @@
|
||||
29 = PULL_PUSH_EVENT, 30 = PROJECT_CHANGED, 31 = PROJECT_BOARD_CHANGED
|
||||
32 = DISMISSED_REVIEW, 33 = COMMENT_TYPE_CHANGE_ISSUE_REF, 34 = PR_SCHEDULE_TO_AUTO_MERGE,
|
||||
35 = CANCEL_SCHEDULED_AUTO_MERGE_PR, 36 = PIN_ISSUE, 37 = UNPIN_ISSUE,
|
||||
38 = COMMENT_TYPE_CHANGE_TIME_ESTIMATE, 39 = MARKED_AS_WORK_IN_PROGRESS,
|
||||
40 = MARKED_AS_READY_FOR_REVIEW -->
|
||||
38 = COMMENT_TYPE_CHANGE_TIME_ESTIMATE -->
|
||||
{{if eq .Type 0}}
|
||||
<div class="timeline-item comment" id="{{.HashTag}}">
|
||||
{{if .OriginalAuthor}}
|
||||
@@ -221,11 +220,11 @@
|
||||
</div>
|
||||
{{else if eq .Type 10}}
|
||||
<div class="timeline-item event" id="{{.HashTag}}">
|
||||
<span class="badge">{{svg "octicon-pencil"}}</span>
|
||||
<span class="badge">{{ctx.RenderUtils.RenderTimelineEventBadge $comment}}</span>
|
||||
{{template "shared/user/avatarlink" dict "user" .Poster}}
|
||||
<span class="comment-text-line">
|
||||
{{template "shared/user/authorlink" .Poster}}
|
||||
{{ctx.Locale.Tr "repo.issues.change_title_at" (.OldTitle|ctx.RenderUtils.RenderEmoji) (.NewTitle|ctx.RenderUtils.RenderEmoji) $createdStr}}
|
||||
{{ctx.RenderUtils.RenderTimelineEventComment $comment $createdStr}}
|
||||
</span>
|
||||
</div>
|
||||
{{else if eq .Type 11}}
|
||||
@@ -693,24 +692,6 @@
|
||||
{{end}}
|
||||
</span>
|
||||
</div>
|
||||
{{else if eq .Type 39}}
|
||||
<div class="timeline-item event" id="{{.HashTag}}">
|
||||
<span class="badge">{{svg "octicon-git-pull-request-draft"}}</span>
|
||||
{{template "shared/user/avatarlink" dict "user" .Poster}}
|
||||
<span class="comment-text-line">
|
||||
{{template "shared/user/authorlink" .Poster}}
|
||||
{{ctx.Locale.Tr "repo.pulls.marked_as_work_in_progress" $createdStr}}
|
||||
</span>
|
||||
</div>
|
||||
{{else if eq .Type 40}}
|
||||
<div class="timeline-item event" id="{{.HashTag}}">
|
||||
<span class="badge">{{svg "octicon-eye"}}</span>
|
||||
{{template "shared/user/avatarlink" dict "user" .Poster}}
|
||||
<span class="comment-text-line">
|
||||
{{template "shared/user/authorlink" .Poster}}
|
||||
{{ctx.Locale.Tr "repo.pulls.marked_as_ready_for_review" $createdStr}}
|
||||
</span>
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
Reference in New Issue
Block a user