From 000d7c1ccb4db8041d2ca59b187a2d3c29e17be1 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Feb 2026 05:57:08 +0000 Subject: [PATCH 1/3] Improve timeline entries for WIP prefix changes in pull requests (#36518) Add new timeline event types when the WIP prefix is added or removed, replacing the previous ugly title change messages. Fixes: https://github.com/go-gitea/gitea/issues/36517 --------- Co-authored-by: silverwind Co-authored-by: wxiaoguang --- .gitignore | 2 - AGENTS.md | 2 - CLAUDE.md | 1 + models/issues/pull.go | 12 +++- modules/templates/util_render_comment.go | 48 +++++++++++++++ modules/templates/util_render_comment_test.go | 31 ++++++++++ options/locale/locale_en-US.json | 2 + routers/web/repo/pull.go | 61 ++++++++++--------- .../repo/issue/view_content/comments.tmpl | 6 +- 9 files changed, 127 insertions(+), 38 deletions(-) create mode 100644 CLAUDE.md create mode 100644 modules/templates/util_render_comment.go create mode 100644 modules/templates/util_render_comment_test.go diff --git a/.gitignore b/.gitignore index 11af4543bd..aa08e47aec 100644 --- a/.gitignore +++ b/.gitignore @@ -121,8 +121,6 @@ prime/ /.goosehints /.windsurfrules /.github/copilot-instructions.md -/AGENT.md -/CLAUDE.md /llms.txt # Ignore worktrees when working on multiple branches diff --git a/AGENTS.md b/AGENTS.md index f4414bfc8c..d0912c6bde 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,8 +1,6 @@ # Instructions for agents - Use `make help` to find available development targets -- Use the latest Golang stable release when working on Go code -- Use the latest Node.js LTS release when working on TypeScript code - Before committing `.go` changes, run `make fmt` to format, and run `make lint-go` to lint - Before committing `.ts` changes, run `make lint-js` to lint - Before committing `go.mod` changes, run `make tidy` diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000000..43c994c2d3 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/models/issues/pull.go b/models/issues/pull.go index 18977ed212..9f180f9ac9 100644 --- a/models/issues/pull.go +++ b/models/issues/pull.go @@ -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. diff --git a/modules/templates/util_render_comment.go b/modules/templates/util_render_comment.go new file mode 100644 index 0000000000..73f36ad21c --- /dev/null +++ b/modules/templates/util_render_comment.go @@ -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_at", "repo.pulls.marked_as_ready_for_review_at") + 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) +} diff --git a/modules/templates/util_render_comment_test.go b/modules/templates/util_render_comment_test.go new file mode 100644 index 0000000000..27e67bd354 --- /dev/null +++ b/modules/templates/util_render_comment_test.go @@ -0,0 +1,31 @@ +// Copyright 2026 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package templates + +import ( + "html/template" + "testing" + + issues_model "code.gitea.io/gitea/models/issues" + "code.gitea.io/gitea/modules/reqctx" + "code.gitea.io/gitea/modules/translation" + + "github.com/stretchr/testify/assert" +) + +func TestRenderTimelineEventComment(t *testing.T) { + ctx := reqctx.NewRequestContextForTest(t.Context()) + ctx.SetContextValue(translation.ContextKey, &translation.MockLocale{}) + ut := &RenderUtils{ctx: ctx} + var createdStr template.HTML = "(created-at)" + + c := &issues_model.Comment{Type: issues_model.CommentTypeChangeTitle, OldTitle: "WIP: title", NewTitle: "title"} + assert.Equal(t, "repo.pulls.marked_as_ready_for_review_at:(created-at)", string(ut.RenderTimelineEventComment(c, createdStr))) + + c = &issues_model.Comment{Type: issues_model.CommentTypeChangeTitle, OldTitle: "title", NewTitle: "WIP: title"} + assert.Equal(t, "repo.pulls.marked_as_work_in_progress_at:(created-at)", string(ut.RenderTimelineEventComment(c, createdStr))) + + c = &issues_model.Comment{Type: issues_model.CommentTypeChangeTitle, OldTitle: "title", NewTitle: "WIP: new title"} + assert.Equal(t, "repo.issues.change_title_at:title,WIP: new title,(created-at)", string(ut.RenderTimelineEventComment(c, createdStr))) +} diff --git a/options/locale/locale_en-US.json b/options/locale/locale_en-US.json index 417698544f..9ad81d5a8d 100644 --- a/options/locale/locale_en-US.json +++ b/options/locale/locale_en-US.json @@ -1778,6 +1778,8 @@ "repo.pulls.title_desc": "wants to merge %[1]d commits from %[2]s into %[3]s", "repo.pulls.merged_title_desc": "merged %[1]d commits from %[2]s into %[3]s %[4]s", "repo.pulls.change_target_branch_at": "changed target branch from %s to %s %s", + "repo.pulls.marked_as_work_in_progress_at": "marked the pull request as work in progress %s", + "repo.pulls.marked_as_ready_for_review_at": "marked the pull request as ready for review %s", "repo.pulls.tab_conversation": "Conversation", "repo.pulls.tab_commits": "Commits", "repo.pulls.tab_files": "Files Changed", diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index cff501ad71..d306927001 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -344,6 +344,35 @@ func (d *pullCommitStatusCheckData) CommitStatusCheckPrompt(locale translation.L return locale.TrString("repo.pulls.status_checking") } +func getViewPullHeadBranchInfo(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 := getViewPullHeadBranchInfo(ctx, pull, baseGitRepo) + if err != nil { + ctx.ServerError("getViewPullHeadBranchInfo", err) + return nil } if headBranchExist { diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index 0eeb10cba7..e7b4c8758d 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -1,5 +1,5 @@ {{template "base/alert"}} -{{range .Issue.Comments}} +{{range $comment := .Issue.Comments}} {{if call $.ShouldShowCommentType .Type}} {{$createdStr:= DateUtils.TimeSince .CreatedUnix}} @@ -220,11 +220,11 @@ {{else if eq .Type 10}}
- {{svg "octicon-pencil"}} + {{ctx.RenderUtils.RenderTimelineEventBadge $comment}} {{template "shared/user/avatarlink" dict "user" .Poster}} {{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}}
{{else if eq .Type 11}} From fca94bcdd73f16fc2b84448fa05b02c63ccbf502 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Feb 2026 19:11:44 +0800 Subject: [PATCH 2/3] Hide `add-matcher` and `remove-matcher` from actions job logs (#36520) Hides `::add-matcher::`, `##[add-matcher]` and `::remove-matcher` in job step logs. These are used to configure regex matchers to detect lines that should trigger annotation comments on the UI, currently unsupported by Gitea and these have no relevance to the user. --------- Signed-off-by: silverwind Signed-off-by: wxiaoguang --- web_src/js/components/RepoActionView.test.ts | 22 ++++++++++++++++++++ web_src/js/components/RepoActionView.vue | 17 ++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 web_src/js/components/RepoActionView.test.ts diff --git a/web_src/js/components/RepoActionView.test.ts b/web_src/js/components/RepoActionView.test.ts new file mode 100644 index 0000000000..d7b9a7de2a --- /dev/null +++ b/web_src/js/components/RepoActionView.test.ts @@ -0,0 +1,22 @@ +import {shouldHideLine, type LogLine} from './RepoActionView.vue'; + +test('shouldHideLine', () => { + expect(([ + {index: 1, message: 'Starting build process', timestamp: 1000}, + {index: 2, message: '::add-matcher::/home/runner/go/pkg/mod/example.com/tool/matcher.json', timestamp: 1001}, + {index: 3, message: 'Running tests...', timestamp: 1002}, + {index: 4, message: '##[add-matcher]/opt/hostedtoolcache/go/1.25.7/x64/matchers.json', timestamp: 1003}, + {index: 5, message: 'Test suite started', timestamp: 1004}, + {index: 7, message: 'All tests passed', timestamp: 1006}, + {index: 8, message: '::remove-matcher owner=go::', timestamp: 1007}, + {index: 9, message: 'Build complete', timestamp: 1008}, + ] as Array).filter((line) => !shouldHideLine(line)).map((line) => line.message)).toMatchInlineSnapshot(` + [ + "Starting build process", + "Running tests...", + "Test suite started", + "All tests passed", + "Build complete", + ] + `); +}); diff --git a/web_src/js/components/RepoActionView.vue b/web_src/js/components/RepoActionView.vue index 69579d3687..cf1ed80ffc 100644 --- a/web_src/js/components/RepoActionView.vue +++ b/web_src/js/components/RepoActionView.vue @@ -15,14 +15,19 @@ type RunStatus = 'unknown' | 'waiting' | 'running' | 'success' | 'failure' | 'ca type StepContainerElement = HTMLElement & {_stepLogsActiveContainer?: HTMLElement} -type LogLine = { +export type LogLine = { index: number; timestamp: number; message: string; }; +// `##[group]` is from Azure Pipelines, just supported by the way. https://learn.microsoft.com/en-us/azure/devops/pipelines/scripts/logging-commands const LogLinePrefixesGroup = ['::group::', '##[group]']; const LogLinePrefixesEndGroup = ['::endgroup::', '##[endgroup]']; +// https://github.com/actions/toolkit/blob/master/docs/commands.md +// https://github.com/actions/runner/blob/main/docs/adrs/0276-problem-matchers.md#registration +// Although there should be no `##[add-matcher]` syntax, there are still such outputs when using act-runner +const LogLinePrefixesHidden = ['::add-matcher::', '##[add-matcher]', '::remove-matcher']; type LogLineCommand = { name: 'group' | 'endgroup', @@ -63,6 +68,15 @@ function parseLineCommand(line: LogLine): LogLineCommand | null { return null; } +export function shouldHideLine(line: LogLine): boolean { + for (const prefix of LogLinePrefixesHidden) { + if (line.message.startsWith(prefix)) { + return true; + } + } + return false; +} + function isLogElementInViewport(el: Element, {extraViewPortHeight}={extraViewPortHeight: 0}): boolean { const rect = el.getBoundingClientRect(); // only check whether bottom is in viewport, because the log element can be a log group which is usually tall @@ -315,6 +329,7 @@ export default defineComponent({ appendLogs(stepIndex: number, startTime: number, logLines: LogLine[]) { for (const line of logLines) { + if (shouldHideLine(line)) continue; const el = this.getActiveLogsContainer(stepIndex); const cmd = parseLineCommand(line); if (cmd?.name === 'group') { From 50fdd2d49af1cdcb9900222326fd5134e735d5e4 Mon Sep 17 00:00:00 2001 From: Pascal Zimmermann Date: Fri, 6 Feb 2026 00:27:53 +0100 Subject: [PATCH 3/3] [SECURITY] fix: Adjust the toolchain version (#36537) # Summary: - Adjust the toolchain version to fix the security issues ```log Vulnerability #1: GO-2026-4337 Unexpected session resumption in crypto/tls More info: https://pkg.go.dev/vuln/GO-2026-4337 Standard library Found in: crypto/tls@go1.25.6 Fixed in: crypto/tls@go1.25.7 Example traces found: ``` Signed-off-by: Pascal Zimmermann --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 26a2b818ef..4593df66f2 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module code.gitea.io/gitea go 1.25.0 -toolchain go1.25.6 +toolchain go1.25.7 // rfc5280 said: "The serial number is an integer assigned by the CA to each certificate." // But some CAs use negative serial number, just relax the check. related: