aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmd/serv.go89
-rw-r--r--models/renderhelper/commit_checker.go2
-rw-r--r--models/repo/repo.go27
-rw-r--r--models/repo/repo_test.go15
-rw-r--r--modules/git/cmdverb.go36
-rw-r--r--modules/private/serv.go10
-rw-r--r--modules/templates/util_date_test.go2
-rw-r--r--modules/templates/util_render.go21
-rw-r--r--modules/templates/util_render_legacy.go16
-rw-r--r--modules/templates/util_render_test.go128
-rw-r--r--options/locale/locale_cs-CZ.ini7
-rw-r--r--options/locale/locale_de-DE.ini7
-rw-r--r--options/locale/locale_el-GR.ini7
-rw-r--r--options/locale/locale_es-ES.ini7
-rw-r--r--options/locale/locale_fa-IR.ini4
-rw-r--r--options/locale/locale_fi-FI.ini4
-rw-r--r--options/locale/locale_fr-FR.ini10
-rw-r--r--options/locale/locale_ga-IE.ini7
-rw-r--r--options/locale/locale_hu-HU.ini4
-rw-r--r--options/locale/locale_id-ID.ini4
-rw-r--r--options/locale/locale_is-IS.ini4
-rw-r--r--options/locale/locale_it-IT.ini4
-rw-r--r--options/locale/locale_ja-JP.ini7
-rw-r--r--options/locale/locale_ko-KR.ini4
-rw-r--r--options/locale/locale_lv-LV.ini7
-rw-r--r--options/locale/locale_nl-NL.ini4
-rw-r--r--options/locale/locale_pl-PL.ini4
-rw-r--r--options/locale/locale_pt-BR.ini7
-rw-r--r--options/locale/locale_pt-PT.ini7
-rw-r--r--options/locale/locale_ru-RU.ini7
-rw-r--r--options/locale/locale_si-LK.ini4
-rw-r--r--options/locale/locale_sk-SK.ini4
-rw-r--r--options/locale/locale_sv-SE.ini4
-rw-r--r--options/locale/locale_tr-TR.ini7
-rw-r--r--options/locale/locale_uk-UA.ini4
-rw-r--r--options/locale/locale_zh-CN.ini7
-rw-r--r--options/locale/locale_zh-HK.ini4
-rw-r--r--options/locale/locale_zh-TW.ini7
-rw-r--r--package-lock.json8
-rw-r--r--package.json2
-rw-r--r--routers/private/serv.go8
-rw-r--r--routers/web/feed/convert.go4
-rw-r--r--routers/web/repo/actions/view.go6
-rw-r--r--templates/repo/branch/list.tmpl4
-rw-r--r--templates/repo/commit_page.tmpl4
-rw-r--r--templates/repo/commits_list.tmpl4
-rw-r--r--templates/repo/commits_list_small.tmpl4
-rw-r--r--templates/repo/diff/compare.tmpl2
-rw-r--r--templates/repo/graph/commits.tmpl2
-rw-r--r--templates/repo/issue/view_title.tmpl2
-rw-r--r--templates/repo/latest_commit.tmpl4
-rw-r--r--templates/repo/view_list.tmpl2
-rw-r--r--templates/user/dashboard/feeds.tmpl2
-rw-r--r--tests/integration/git_general_test.go40
-rw-r--r--web_src/css/editor/combomarkdowneditor.css64
-rw-r--r--web_src/css/features/expander.css96
-rw-r--r--web_src/css/features/tribute.css32
-rw-r--r--web_src/css/index.css2
-rw-r--r--web_src/js/features/comp/TextExpander.ts1
59 files changed, 469 insertions, 327 deletions
diff --git a/cmd/serv.go b/cmd/serv.go
index b18508459f..26a3af50f3 100644
--- a/cmd/serv.go
+++ b/cmd/serv.go
@@ -11,7 +11,6 @@ import (
"os"
"os/exec"
"path/filepath"
- "regexp"
"strconv"
"strings"
"time"
@@ -20,7 +19,7 @@ import (
asymkey_model "code.gitea.io/gitea/models/asymkey"
git_model "code.gitea.io/gitea/models/git"
"code.gitea.io/gitea/models/perm"
- "code.gitea.io/gitea/modules/container"
+ "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/lfstransfer"
@@ -37,14 +36,6 @@ import (
"github.com/urfave/cli/v2"
)
-const (
- verbUploadPack = "git-upload-pack"
- verbUploadArchive = "git-upload-archive"
- verbReceivePack = "git-receive-pack"
- verbLfsAuthenticate = "git-lfs-authenticate"
- verbLfsTransfer = "git-lfs-transfer"
-)
-
// CmdServ represents the available serv sub-command.
var CmdServ = &cli.Command{
Name: "serv",
@@ -78,22 +69,6 @@ func setup(ctx context.Context, debug bool) {
}
}
-var (
- // keep getAccessMode() in sync
- allowedCommands = container.SetOf(
- verbUploadPack,
- verbUploadArchive,
- verbReceivePack,
- verbLfsAuthenticate,
- verbLfsTransfer,
- )
- allowedCommandsLfs = container.SetOf(
- verbLfsAuthenticate,
- verbLfsTransfer,
- )
- alphaDashDotPattern = regexp.MustCompile(`[^\w-\.]`)
-)
-
// fail prints message to stdout, it's mainly used for git serv and git hook commands.
// The output will be passed to git client and shown to user.
func fail(ctx context.Context, userMessage, logMsgFmt string, args ...any) error {
@@ -139,19 +114,20 @@ func handleCliResponseExtra(extra private.ResponseExtra) error {
func getAccessMode(verb, lfsVerb string) perm.AccessMode {
switch verb {
- case verbUploadPack, verbUploadArchive:
+ case git.CmdVerbUploadPack, git.CmdVerbUploadArchive:
return perm.AccessModeRead
- case verbReceivePack:
+ case git.CmdVerbReceivePack:
return perm.AccessModeWrite
- case verbLfsAuthenticate, verbLfsTransfer:
+ case git.CmdVerbLfsAuthenticate, git.CmdVerbLfsTransfer:
switch lfsVerb {
- case "upload":
+ case git.CmdSubVerbLfsUpload:
return perm.AccessModeWrite
- case "download":
+ case git.CmdSubVerbLfsDownload:
return perm.AccessModeRead
}
}
// should be unreachable
+ setting.PanicInDevOrTesting("unknown verb: %s %s", verb, lfsVerb)
return perm.AccessModeNone
}
@@ -230,12 +206,12 @@ func runServ(c *cli.Context) error {
log.Debug("SSH_ORIGINAL_COMMAND: %s", os.Getenv("SSH_ORIGINAL_COMMAND"))
}
- words, err := shellquote.Split(cmd)
+ sshCmdArgs, err := shellquote.Split(cmd)
if err != nil {
return fail(ctx, "Error parsing arguments", "Failed to parse arguments: %v", err)
}
- if len(words) < 2 {
+ if len(sshCmdArgs) < 2 {
if git.DefaultFeatures().SupportProcReceive {
// for AGit Flow
if cmd == "ssh_info" {
@@ -246,25 +222,21 @@ func runServ(c *cli.Context) error {
return fail(ctx, "Too few arguments", "Too few arguments in cmd: %s", cmd)
}
- verb := words[0]
- repoPath := strings.TrimPrefix(words[1], "/")
-
- var lfsVerb string
-
- rr := strings.SplitN(repoPath, "/", 2)
- if len(rr) != 2 {
+ repoPath := strings.TrimPrefix(sshCmdArgs[1], "/")
+ repoPathFields := strings.SplitN(repoPath, "/", 2)
+ if len(repoPathFields) != 2 {
return fail(ctx, "Invalid repository path", "Invalid repository path: %v", repoPath)
}
- username := rr[0]
- reponame := strings.TrimSuffix(rr[1], ".git")
+ username := repoPathFields[0]
+ reponame := strings.TrimSuffix(repoPathFields[1], ".git") // “the-repo-name" or "the-repo-name.wiki"
// LowerCase and trim the repoPath as that's how they are stored.
// This should be done after splitting the repoPath into username and reponame
// so that username and reponame are not affected.
repoPath = strings.ToLower(strings.TrimSpace(repoPath))
- if alphaDashDotPattern.MatchString(reponame) {
+ if !repo.IsValidSSHAccessRepoName(reponame) {
return fail(ctx, "Invalid repo name", "Invalid repo name: %s", reponame)
}
@@ -286,22 +258,23 @@ func runServ(c *cli.Context) error {
}()
}
- if allowedCommands.Contains(verb) {
- if allowedCommandsLfs.Contains(verb) {
- if !setting.LFS.StartServer {
- return fail(ctx, "LFS Server is not enabled", "")
- }
- if verb == verbLfsTransfer && !setting.LFS.AllowPureSSH {
- return fail(ctx, "LFS SSH transfer is not enabled", "")
- }
- if len(words) > 2 {
- lfsVerb = words[2]
- }
- }
- } else {
+ verb, lfsVerb := sshCmdArgs[0], ""
+ if !git.IsAllowedVerbForServe(verb) {
return fail(ctx, "Unknown git command", "Unknown git command %s", verb)
}
+ if git.IsAllowedVerbForServeLfs(verb) {
+ if !setting.LFS.StartServer {
+ return fail(ctx, "LFS Server is not enabled", "")
+ }
+ if verb == git.CmdVerbLfsTransfer && !setting.LFS.AllowPureSSH {
+ return fail(ctx, "LFS SSH transfer is not enabled", "")
+ }
+ if len(sshCmdArgs) > 2 {
+ lfsVerb = sshCmdArgs[2]
+ }
+ }
+
requestedMode := getAccessMode(verb, lfsVerb)
results, extra := private.ServCommand(ctx, keyID, username, reponame, requestedMode, verb, lfsVerb)
@@ -310,7 +283,7 @@ func runServ(c *cli.Context) error {
}
// LFS SSH protocol
- if verb == verbLfsTransfer {
+ if verb == git.CmdVerbLfsTransfer {
token, err := getLFSAuthToken(ctx, lfsVerb, results)
if err != nil {
return err
@@ -319,7 +292,7 @@ func runServ(c *cli.Context) error {
}
// LFS token authentication
- if verb == verbLfsAuthenticate {
+ if verb == git.CmdVerbLfsAuthenticate {
url := fmt.Sprintf("%s%s/%s.git/info/lfs", setting.AppURL, url.PathEscape(results.OwnerName), url.PathEscape(results.RepoName))
token, err := getLFSAuthToken(ctx, lfsVerb, results)
diff --git a/models/renderhelper/commit_checker.go b/models/renderhelper/commit_checker.go
index 4815643e67..407e45fb54 100644
--- a/models/renderhelper/commit_checker.go
+++ b/models/renderhelper/commit_checker.go
@@ -47,7 +47,7 @@ func (c *commitChecker) IsCommitIDExisting(commitID string) bool {
c.gitRepo, c.gitRepoCloser = r, closer
}
- exist = c.gitRepo.IsReferenceExist(commitID) // Don't use IsObjectExist since it doesn't support short hashs with gogit edition.
+ exist = c.gitRepo.IsReferenceExist(commitID) // Don't use IsObjectExist since it doesn't support short hashes with gogit edition.
c.commitCache[commitID] = exist
return exist
}
diff --git a/models/repo/repo.go b/models/repo/repo.go
index 2977dfb9f1..5aae02c6d8 100644
--- a/models/repo/repo.go
+++ b/models/repo/repo.go
@@ -64,18 +64,18 @@ func (err ErrRepoIsArchived) Error() string {
}
type globalVarsStruct struct {
- validRepoNamePattern *regexp.Regexp
- invalidRepoNamePattern *regexp.Regexp
- reservedRepoNames []string
- reservedRepoPatterns []string
+ validRepoNamePattern *regexp.Regexp
+ invalidRepoNamePattern *regexp.Regexp
+ reservedRepoNames []string
+ reservedRepoNamePatterns []string
}
var globalVars = sync.OnceValue(func() *globalVarsStruct {
return &globalVarsStruct{
- validRepoNamePattern: regexp.MustCompile(`[-.\w]+`),
- invalidRepoNamePattern: regexp.MustCompile(`[.]{2,}`),
- reservedRepoNames: []string{".", "..", "-"},
- reservedRepoPatterns: []string{"*.git", "*.wiki", "*.rss", "*.atom"},
+ validRepoNamePattern: regexp.MustCompile(`^[-.\w]+$`),
+ invalidRepoNamePattern: regexp.MustCompile(`[.]{2,}`),
+ reservedRepoNames: []string{".", "..", "-"},
+ reservedRepoNamePatterns: []string{"*.wiki", "*.git", "*.rss", "*.atom"},
}
})
@@ -86,7 +86,16 @@ func IsUsableRepoName(name string) error {
// Note: usually this error is normally caught up earlier in the UI
return db.ErrNameCharsNotAllowed{Name: name}
}
- return db.IsUsableName(vars.reservedRepoNames, vars.reservedRepoPatterns, name)
+ return db.IsUsableName(vars.reservedRepoNames, vars.reservedRepoNamePatterns, name)
+}
+
+// IsValidSSHAccessRepoName is like IsUsableRepoName, but it allows "*.wiki" because wiki repo needs to be accessed in SSH code
+func IsValidSSHAccessRepoName(name string) bool {
+ vars := globalVars()
+ if !vars.validRepoNamePattern.MatchString(name) || vars.invalidRepoNamePattern.MatchString(name) {
+ return false
+ }
+ return db.IsUsableName(vars.reservedRepoNames, vars.reservedRepoNamePatterns[1:], name) == nil
}
// TrustModelType defines the types of trust model for this repository
diff --git a/models/repo/repo_test.go b/models/repo/repo_test.go
index b2604ab575..66abe864fc 100644
--- a/models/repo/repo_test.go
+++ b/models/repo/repo_test.go
@@ -216,8 +216,23 @@ func TestIsUsableRepoName(t *testing.T) {
assert.Error(t, IsUsableRepoName("-"))
assert.Error(t, IsUsableRepoName("🌞"))
+ assert.Error(t, IsUsableRepoName("the/repo"))
assert.Error(t, IsUsableRepoName("the..repo"))
assert.Error(t, IsUsableRepoName("foo.wiki"))
assert.Error(t, IsUsableRepoName("foo.git"))
assert.Error(t, IsUsableRepoName("foo.RSS"))
}
+
+func TestIsValidSSHAccessRepoName(t *testing.T) {
+ assert.True(t, IsValidSSHAccessRepoName("a"))
+ assert.True(t, IsValidSSHAccessRepoName("-1_."))
+ assert.True(t, IsValidSSHAccessRepoName(".profile"))
+ assert.True(t, IsValidSSHAccessRepoName("foo.wiki"))
+
+ assert.False(t, IsValidSSHAccessRepoName("-"))
+ assert.False(t, IsValidSSHAccessRepoName("🌞"))
+ assert.False(t, IsValidSSHAccessRepoName("the/repo"))
+ assert.False(t, IsValidSSHAccessRepoName("the..repo"))
+ assert.False(t, IsValidSSHAccessRepoName("foo.git"))
+ assert.False(t, IsValidSSHAccessRepoName("foo.RSS"))
+}
diff --git a/modules/git/cmdverb.go b/modules/git/cmdverb.go
new file mode 100644
index 0000000000..3d6f4ae0c6
--- /dev/null
+++ b/modules/git/cmdverb.go
@@ -0,0 +1,36 @@
+// Copyright 2025 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package git
+
+const (
+ CmdVerbUploadPack = "git-upload-pack"
+ CmdVerbUploadArchive = "git-upload-archive"
+ CmdVerbReceivePack = "git-receive-pack"
+ CmdVerbLfsAuthenticate = "git-lfs-authenticate"
+ CmdVerbLfsTransfer = "git-lfs-transfer"
+
+ CmdSubVerbLfsUpload = "upload"
+ CmdSubVerbLfsDownload = "download"
+)
+
+func IsAllowedVerbForServe(verb string) bool {
+ switch verb {
+ case CmdVerbUploadPack,
+ CmdVerbUploadArchive,
+ CmdVerbReceivePack,
+ CmdVerbLfsAuthenticate,
+ CmdVerbLfsTransfer:
+ return true
+ }
+ return false
+}
+
+func IsAllowedVerbForServeLfs(verb string) bool {
+ switch verb {
+ case CmdVerbLfsAuthenticate,
+ CmdVerbLfsTransfer:
+ return true
+ }
+ return false
+}
diff --git a/modules/private/serv.go b/modules/private/serv.go
index 10e9f7995c..b1dafbd81b 100644
--- a/modules/private/serv.go
+++ b/modules/private/serv.go
@@ -46,18 +46,16 @@ type ServCommandResults struct {
}
// ServCommand preps for a serv call
-func ServCommand(ctx context.Context, keyID int64, ownerName, repoName string, mode perm.AccessMode, verbs ...string) (*ServCommandResults, ResponseExtra) {
+func ServCommand(ctx context.Context, keyID int64, ownerName, repoName string, mode perm.AccessMode, verb, lfsVerb string) (*ServCommandResults, ResponseExtra) {
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/serv/command/%d/%s/%s?mode=%d",
keyID,
url.PathEscape(ownerName),
url.PathEscape(repoName),
mode,
)
- for _, verb := range verbs {
- if verb != "" {
- reqURL += "&verb=" + url.QueryEscape(verb)
- }
- }
+ reqURL += "&verb=" + url.QueryEscape(verb)
+ // reqURL += "&lfs_verb=" + url.QueryEscape(lfsVerb) // TODO: actually there is no use of this parameter. In the future, the URL construction should be more flexible
+ _ = lfsVerb
req := newInternalRequestAPI(ctx, reqURL, "GET")
return requestJSONResp(req, &ServCommandResults{})
}
diff --git a/modules/templates/util_date_test.go b/modules/templates/util_date_test.go
index f3a2409a9f..9015462bbb 100644
--- a/modules/templates/util_date_test.go
+++ b/modules/templates/util_date_test.go
@@ -17,6 +17,7 @@ import (
func TestDateTime(t *testing.T) {
testTz, _ := time.LoadLocation("America/New_York")
defer test.MockVariableValue(&setting.DefaultUILocation, testTz)()
+ defer test.MockVariableValue(&setting.IsProd, true)()
defer test.MockVariableValue(&setting.IsInTesting, false)()
du := NewDateUtils()
@@ -53,6 +54,7 @@ func TestDateTime(t *testing.T) {
func TestTimeSince(t *testing.T) {
testTz, _ := time.LoadLocation("America/New_York")
defer test.MockVariableValue(&setting.DefaultUILocation, testTz)()
+ defer test.MockVariableValue(&setting.IsProd, true)()
defer test.MockVariableValue(&setting.IsInTesting, false)()
du := NewDateUtils()
diff --git a/modules/templates/util_render.go b/modules/templates/util_render.go
index 521233db40..8d9ba1000c 100644
--- a/modules/templates/util_render.go
+++ b/modules/templates/util_render.go
@@ -14,6 +14,8 @@ import (
"unicode"
issues_model "code.gitea.io/gitea/models/issues"
+ "code.gitea.io/gitea/models/renderhelper"
+ "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/emoji"
"code.gitea.io/gitea/modules/htmlutil"
"code.gitea.io/gitea/modules/log"
@@ -34,11 +36,11 @@ func NewRenderUtils(ctx reqctx.RequestContext) *RenderUtils {
}
// RenderCommitMessage renders commit message with XSS-safe and special links.
-func (ut *RenderUtils) RenderCommitMessage(msg string, metas map[string]string) template.HTML {
+func (ut *RenderUtils) RenderCommitMessage(msg string, repo *repo.Repository) template.HTML {
cleanMsg := template.HTMLEscapeString(msg)
// we can safely assume that it will not return any error, since there
// shouldn't be any special HTML.
- fullMessage, err := markup.PostProcessCommitMessage(markup.NewRenderContext(ut.ctx).WithMetas(metas), cleanMsg)
+ fullMessage, err := markup.PostProcessCommitMessage(renderhelper.NewRenderContextRepoComment(ut.ctx, repo), cleanMsg)
if err != nil {
log.Error("PostProcessCommitMessage: %v", err)
return ""
@@ -52,7 +54,7 @@ func (ut *RenderUtils) RenderCommitMessage(msg string, metas map[string]string)
// RenderCommitMessageLinkSubject renders commit message as a XSS-safe link to
// the provided default url, handling for special links without email to links.
-func (ut *RenderUtils) RenderCommitMessageLinkSubject(msg, urlDefault string, metas map[string]string) template.HTML {
+func (ut *RenderUtils) RenderCommitMessageLinkSubject(msg, urlDefault string, repo *repo.Repository) template.HTML {
msgLine := strings.TrimLeftFunc(msg, unicode.IsSpace)
lineEnd := strings.IndexByte(msgLine, '\n')
if lineEnd > 0 {
@@ -63,9 +65,8 @@ func (ut *RenderUtils) RenderCommitMessageLinkSubject(msg, urlDefault string, me
return ""
}
- // we can safely assume that it will not return any error, since there
- // shouldn't be any special HTML.
- renderedMessage, err := markup.PostProcessCommitMessageSubject(markup.NewRenderContext(ut.ctx).WithMetas(metas), urlDefault, template.HTMLEscapeString(msgLine))
+ // we can safely assume that it will not return any error, since there shouldn't be any special HTML.
+ renderedMessage, err := markup.PostProcessCommitMessageSubject(renderhelper.NewRenderContextRepoComment(ut.ctx, repo), urlDefault, template.HTMLEscapeString(msgLine))
if err != nil {
log.Error("PostProcessCommitMessageSubject: %v", err)
return ""
@@ -74,7 +75,7 @@ func (ut *RenderUtils) RenderCommitMessageLinkSubject(msg, urlDefault string, me
}
// RenderCommitBody extracts the body of a commit message without its title.
-func (ut *RenderUtils) RenderCommitBody(msg string, metas map[string]string) template.HTML {
+func (ut *RenderUtils) RenderCommitBody(msg string, repo *repo.Repository) template.HTML {
msgLine := strings.TrimSpace(msg)
lineEnd := strings.IndexByte(msgLine, '\n')
if lineEnd > 0 {
@@ -87,7 +88,7 @@ func (ut *RenderUtils) RenderCommitBody(msg string, metas map[string]string) tem
return ""
}
- renderedMessage, err := markup.PostProcessCommitMessage(markup.NewRenderContext(ut.ctx).WithMetas(metas), template.HTMLEscapeString(msgLine))
+ renderedMessage, err := markup.PostProcessCommitMessage(renderhelper.NewRenderContextRepoComment(ut.ctx, repo), template.HTMLEscapeString(msgLine))
if err != nil {
log.Error("PostProcessCommitMessage: %v", err)
return ""
@@ -105,8 +106,8 @@ func renderCodeBlock(htmlEscapedTextToRender template.HTML) template.HTML {
}
// RenderIssueTitle renders issue/pull title with defined post processors
-func (ut *RenderUtils) RenderIssueTitle(text string, metas map[string]string) template.HTML {
- renderedText, err := markup.PostProcessIssueTitle(markup.NewRenderContext(ut.ctx).WithMetas(metas), template.HTMLEscapeString(text))
+func (ut *RenderUtils) RenderIssueTitle(text string, repo *repo.Repository) template.HTML {
+ renderedText, err := markup.PostProcessIssueTitle(renderhelper.NewRenderContextRepoComment(ut.ctx, repo), template.HTMLEscapeString(text))
if err != nil {
log.Error("PostProcessIssueTitle: %v", err)
return ""
diff --git a/modules/templates/util_render_legacy.go b/modules/templates/util_render_legacy.go
index 8f7b84c83d..df8f5e64de 100644
--- a/modules/templates/util_render_legacy.go
+++ b/modules/templates/util_render_legacy.go
@@ -32,22 +32,22 @@ func renderMarkdownToHtmlLegacy(ctx context.Context, input string) template.HTML
return NewRenderUtils(reqctx.FromContext(ctx)).MarkdownToHtml(input)
}
-func renderCommitMessageLegacy(ctx context.Context, msg string, metas map[string]string) template.HTML {
+func renderCommitMessageLegacy(ctx context.Context, msg string, _ map[string]string) template.HTML {
panicIfDevOrTesting()
- return NewRenderUtils(reqctx.FromContext(ctx)).RenderCommitMessage(msg, metas)
+ return NewRenderUtils(reqctx.FromContext(ctx)).RenderCommitMessage(msg, nil)
}
-func renderCommitMessageLinkSubjectLegacy(ctx context.Context, msg, urlDefault string, metas map[string]string) template.HTML {
+func renderCommitMessageLinkSubjectLegacy(ctx context.Context, msg, urlDefault string, _ map[string]string) template.HTML {
panicIfDevOrTesting()
- return NewRenderUtils(reqctx.FromContext(ctx)).RenderCommitMessageLinkSubject(msg, urlDefault, metas)
+ return NewRenderUtils(reqctx.FromContext(ctx)).RenderCommitMessageLinkSubject(msg, urlDefault, nil)
}
-func renderIssueTitleLegacy(ctx context.Context, text string, metas map[string]string) template.HTML {
+func renderIssueTitleLegacy(ctx context.Context, text string, _ map[string]string) template.HTML {
panicIfDevOrTesting()
- return NewRenderUtils(reqctx.FromContext(ctx)).RenderIssueTitle(text, metas)
+ return NewRenderUtils(reqctx.FromContext(ctx)).RenderIssueTitle(text, nil)
}
-func renderCommitBodyLegacy(ctx context.Context, msg string, metas map[string]string) template.HTML {
+func renderCommitBodyLegacy(ctx context.Context, msg string, _ map[string]string) template.HTML {
panicIfDevOrTesting()
- return NewRenderUtils(reqctx.FromContext(ctx)).RenderCommitBody(msg, metas)
+ return NewRenderUtils(reqctx.FromContext(ctx)).RenderCommitBody(msg, nil)
}
diff --git a/modules/templates/util_render_test.go b/modules/templates/util_render_test.go
index 460b9dc190..9b51d0cd57 100644
--- a/modules/templates/util_render_test.go
+++ b/modules/templates/util_render_test.go
@@ -11,11 +11,11 @@ import (
"testing"
"code.gitea.io/gitea/models/issues"
- "code.gitea.io/gitea/models/unittest"
- "code.gitea.io/gitea/modules/git"
- "code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/models/repo"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/reqctx"
+ "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/modules/translation"
@@ -47,19 +47,8 @@ mail@domain.com
return strings.ReplaceAll(s, "<SPACE>", " ")
}
-var testMetas = map[string]string{
- "user": "user13",
- "repo": "repo11",
- "repoPath": "../../tests/gitea-repositories-meta/user13/repo11.git/",
- "markdownNewLineHardBreak": "true",
- "markupAllowShortIssuePattern": "true",
-}
-
func TestMain(m *testing.M) {
- unittest.InitSettingsForTesting()
- if err := git.InitSimple(context.Background()); err != nil {
- log.Fatal("git init failed, err: %v", err)
- }
+ setting.Markdown.RenderOptionsComment.ShortIssuePattern = true
markup.Init(&markup.RenderHelperFuncs{
IsUsernameMentionable: func(ctx context.Context, username string) bool {
return username == "mention-user"
@@ -74,46 +63,52 @@ func newTestRenderUtils(t *testing.T) *RenderUtils {
return NewRenderUtils(ctx)
}
-func TestRenderCommitBody(t *testing.T) {
- defer test.MockVariableValue(&markup.RenderBehaviorForTesting.DisableAdditionalAttributes, true)()
- type args struct {
- msg string
+func TestRenderRepoComment(t *testing.T) {
+ mockRepo := &repo.Repository{
+ ID: 1, OwnerName: "user13", Name: "repo11",
+ Owner: &user_model.User{ID: 13, Name: "user13"},
+ Units: []*repo.RepoUnit{},
}
- tests := []struct {
- name string
- args args
- want template.HTML
- }{
- {
- name: "multiple lines",
- args: args{
- msg: "first line\nsecond line",
+ t.Run("RenderCommitBody", func(t *testing.T) {
+ defer test.MockVariableValue(&markup.RenderBehaviorForTesting.DisableAdditionalAttributes, true)()
+ type args struct {
+ msg string
+ }
+ tests := []struct {
+ name string
+ args args
+ want template.HTML
+ }{
+ {
+ name: "multiple lines",
+ args: args{
+ msg: "first line\nsecond line",
+ },
+ want: "second line",
},
- want: "second line",
- },
- {
- name: "multiple lines with leading newlines",
- args: args{
- msg: "\n\n\n\nfirst line\nsecond line",
+ {
+ name: "multiple lines with leading newlines",
+ args: args{
+ msg: "\n\n\n\nfirst line\nsecond line",
+ },
+ want: "second line",
},
- want: "second line",
- },
- {
- name: "multiple lines with trailing newlines",
- args: args{
- msg: "first line\nsecond line\n\n\n",
+ {
+ name: "multiple lines with trailing newlines",
+ args: args{
+ msg: "first line\nsecond line\n\n\n",
+ },
+ want: "second line",
},
- want: "second line",
- },
- }
- ut := newTestRenderUtils(t)
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- assert.Equalf(t, tt.want, ut.RenderCommitBody(tt.args.msg, nil), "RenderCommitBody(%v, %v)", tt.args.msg, nil)
- })
- }
-
- expected := `/just/a/path.bin
+ }
+ ut := newTestRenderUtils(t)
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ assert.Equalf(t, tt.want, ut.RenderCommitBody(tt.args.msg, mockRepo), "RenderCommitBody(%v, %v)", tt.args.msg, nil)
+ })
+ }
+
+ expected := `/just/a/path.bin
<a href="https://example.com/file.bin">https://example.com/file.bin</a>
[local link](file.bin)
[remote link](<a href="https://example.com">https://example.com</a>)
@@ -132,22 +127,22 @@ com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
<a href="/mention-user">@mention-user</a> test
<a href="/user13/repo11/issues/123" class="ref-issue">#123</a>
space`
- assert.Equal(t, expected, string(newTestRenderUtils(t).RenderCommitBody(testInput(), testMetas)))
-}
+ assert.Equal(t, expected, string(newTestRenderUtils(t).RenderCommitBody(testInput(), mockRepo)))
+ })
-func TestRenderCommitMessage(t *testing.T) {
- expected := `space <a href="/mention-user" data-markdown-generated-content="">@mention-user</a> `
- assert.EqualValues(t, expected, newTestRenderUtils(t).RenderCommitMessage(testInput(), testMetas))
-}
+ t.Run("RenderCommitMessage", func(t *testing.T) {
+ expected := `space <a href="/mention-user" data-markdown-generated-content="">@mention-user</a> `
+ assert.EqualValues(t, expected, newTestRenderUtils(t).RenderCommitMessage(testInput(), mockRepo))
+ })
-func TestRenderCommitMessageLinkSubject(t *testing.T) {
- expected := `<a href="https://example.com/link" class="muted">space </a><a href="/mention-user" data-markdown-generated-content="">@mention-user</a>`
- assert.EqualValues(t, expected, newTestRenderUtils(t).RenderCommitMessageLinkSubject(testInput(), "https://example.com/link", testMetas))
-}
+ t.Run("RenderCommitMessageLinkSubject", func(t *testing.T) {
+ expected := `<a href="https://example.com/link" class="muted">space </a><a href="/mention-user" data-markdown-generated-content="">@mention-user</a>`
+ assert.EqualValues(t, expected, newTestRenderUtils(t).RenderCommitMessageLinkSubject(testInput(), "https://example.com/link", mockRepo))
+ })
-func TestRenderIssueTitle(t *testing.T) {
- defer test.MockVariableValue(&markup.RenderBehaviorForTesting.DisableAdditionalAttributes, true)()
- expected := ` space @mention-user<SPACE><SPACE>
+ t.Run("RenderIssueTitle", func(t *testing.T) {
+ defer test.MockVariableValue(&markup.RenderBehaviorForTesting.DisableAdditionalAttributes, true)()
+ expected := ` space @mention-user<SPACE><SPACE>
/just/a/path.bin
https://example.com/file.bin
[local link](file.bin)
@@ -168,8 +163,9 @@ mail@domain.com
<a href="/user13/repo11/issues/123" class="ref-issue">#123</a>
space<SPACE><SPACE>
`
- expected = strings.ReplaceAll(expected, "<SPACE>", " ")
- assert.Equal(t, expected, string(newTestRenderUtils(t).RenderIssueTitle(testInput(), testMetas)))
+ expected = strings.ReplaceAll(expected, "<SPACE>", " ")
+ assert.Equal(t, expected, string(newTestRenderUtils(t).RenderIssueTitle(testInput(), mockRepo)))
+ })
}
func TestRenderMarkdownToHtml(t *testing.T) {
diff --git a/options/locale/locale_cs-CZ.ini b/options/locale/locale_cs-CZ.ini
index 63ab9f9d3a..2a3bd3e743 100644
--- a/options/locale/locale_cs-CZ.ini
+++ b/options/locale/locale_cs-CZ.ini
@@ -3667,12 +3667,13 @@ owner.settings.chef.keypair.description=Pro autentizaci do registru Chef je zapo
secrets=Tajné klíče
description=Tejné klíče budou předány určitým akcím a nelze je přečíst jinak.
none=Zatím zde nejsou žádné tajné klíče.
-creation=Přidat tajný klíč
+
+; These keys are also for "edit secret", the keys are kept as-is to avoid unnecessary re-translation
creation.description=Popis
creation.name_placeholder=nerozlišovat velká a malá písmena, pouze alfanumerické znaky nebo podtržítka, nemohou začínat na GITEA_ nebo GITHUB_
creation.value_placeholder=Vložte jakýkoliv obsah. Mezery na začátku a konci budou vynechány.
-creation.success=Tajný klíč „%s“ byl přidán.
-creation.failed=Nepodařilo se přidat tajný klíč.
+
+
deletion=Odstranit tajný klíč
deletion.description=Odstranění tajného klíče je trvalé a nelze ho vrátit zpět. Pokračovat?
deletion.success=Tajný klíč byl odstraněn.
diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini
index 43333f8ac6..f115dee247 100644
--- a/options/locale/locale_de-DE.ini
+++ b/options/locale/locale_de-DE.ini
@@ -3659,12 +3659,13 @@ owner.settings.chef.keypair.description=Ein Schlüsselpaar ist notwendig, um mit
secrets=Secrets
description=Secrets werden an bestimmte Aktionen weitergegeben und können nicht anderweitig ausgelesen werden.
none=Noch keine Secrets vorhanden.
-creation=Secret hinzufügen
+
+; These keys are also for "edit secret", the keys are kept as-is to avoid unnecessary re-translation
creation.description=Beschreibung
creation.name_placeholder=Groß-/Kleinschreibung wird ignoriert, nur alphanumerische Zeichen oder Unterstriche, darf nicht mit GITEA_ oder GITHUB_ beginnen
creation.value_placeholder=Beliebigen Inhalt eingeben. Leerzeichen am Anfang und Ende werden weggelassen.
-creation.success=Das Secret "%s" wurde hinzugefügt.
-creation.failed=Secret konnte nicht hinzugefügt werden.
+
+
deletion=Secret entfernen
deletion.description=Das Entfernen eines Secrets kann nicht rückgängig gemacht werden. Fortfahren?
deletion.success=Das Secret wurde entfernt.
diff --git a/options/locale/locale_el-GR.ini b/options/locale/locale_el-GR.ini
index c2479bf342..444fbd26c9 100644
--- a/options/locale/locale_el-GR.ini
+++ b/options/locale/locale_el-GR.ini
@@ -3329,12 +3329,13 @@ owner.settings.chef.keypair.description=Ένα ζεύγος κλειδιών ε
secrets=Μυστικά
description=Τα μυστικά θα περάσουν σε ορισμένες δράσεις και δεν μπορούν να αναγνωστούν αλλού.
none=Δεν υπάρχουν ακόμα μυστικά.
-creation=Προσθήκη Μυστικού
+
+; These keys are also for "edit secret", the keys are kept as-is to avoid unnecessary re-translation
creation.description=Περιγραφή
creation.name_placeholder=αλφαριθμητικοί χαρακτήρες ή κάτω παύλες μόνο, δεν μπορούν να ξεκινούν με GITEA_ ή GITHUB_
creation.value_placeholder=Εισάγετε οποιοδήποτε περιεχόμενο. Τα κενά στην αρχή παραλείπονται.
-creation.success=Το μυστικό "%s" προστέθηκε.
-creation.failed=Αποτυχία δημιουργίας μυστικού.
+
+
deletion=Αφαίρεση μυστικού
deletion.description=Η αφαίρεση ενός μυστικού είναι μόνιμη και δεν μπορεί να αναιρεθεί. Συνέχεια;
deletion.success=Το μυστικό έχει αφαιρεθεί.
diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini
index 5f989f6acf..521583395e 100644
--- a/options/locale/locale_es-ES.ini
+++ b/options/locale/locale_es-ES.ini
@@ -3309,12 +3309,13 @@ owner.settings.chef.keypair.description=Un par de claves es necesario para auten
secrets=Secretos
description=Los secretos pasarán a ciertas acciones y no se podrán leer de otro modo.
none=Todavía no hay secretos.
-creation=Añadir secreto
+
+; These keys are also for "edit secret", the keys are kept as-is to avoid unnecessary re-translation
creation.description=Descripción
creation.name_placeholder=sin distinción de mayúsculas, solo carácteres alfanuméricos o guiones bajos, no puede empezar por GITEA_ o GITHUB_
creation.value_placeholder=Introduce cualquier contenido. Se omitirá el espacio en blanco en el inicio y el final.
-creation.success=El secreto "%s" ha sido añadido.
-creation.failed=Error al añadir secreto.
+
+
deletion=Eliminar secreto
deletion.description=Eliminar un secreto es permanente y no se puede deshacer. ¿Continuar?
deletion.success=El secreto ha sido eliminado.
diff --git a/options/locale/locale_fa-IR.ini b/options/locale/locale_fa-IR.ini
index 5d67f03bac..18abc0f401 100644
--- a/options/locale/locale_fa-IR.ini
+++ b/options/locale/locale_fa-IR.ini
@@ -2506,8 +2506,12 @@ conan.details.repository=مخزن
owner.settings.cleanuprules.enabled=فعال شده
[secrets]
+
+; These keys are also for "edit secret", the keys are kept as-is to avoid unnecessary re-translation
creation.description=شرح
+
+
[actions]
diff --git a/options/locale/locale_fi-FI.ini b/options/locale/locale_fi-FI.ini
index 69cee090fe..b925d6f43a 100644
--- a/options/locale/locale_fi-FI.ini
+++ b/options/locale/locale_fi-FI.ini
@@ -1692,8 +1692,12 @@ conan.details.repository=Repo
owner.settings.cleanuprules.enabled=Käytössä
[secrets]
+
+; These keys are also for "edit secret", the keys are kept as-is to avoid unnecessary re-translation
creation.description=Kuvaus
+
+
[actions]
diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini
index b9d550eee5..eeb5e31965 100644
--- a/options/locale/locale_fr-FR.ini
+++ b/options/locale/locale_fr-FR.ini
@@ -130,6 +130,7 @@ pin=Épingler
unpin=Désépingler
artifacts=Artefacts
+expired=Expiré
confirm_delete_artifact=Êtes-vous sûr de vouloir supprimer l‘artefact « %s » ?
archived=Archivé
@@ -450,6 +451,7 @@ use_scratch_code=Utiliser un code de secours
twofa_scratch_used=Vous avez utilisé votre code de secours. Vous avez été redirigé vers cette page de configuration afin de supprimer l'authentification à deux facteurs de votre appareil ou afin de générer un nouveau code de secours.
twofa_passcode_incorrect=Votre code d’accès n’est pas correct. Si vous avez égaré votre appareil, utilisez votre code de secours pour vous connecter.
twofa_scratch_token_incorrect=Votre code de secours est incorrect.
+twofa_required=Vous devez configurer l’authentification à deux facteurs pour avoir accès aux dépôts, ou essayer de vous reconnecter.
login_userpass=Connexion
login_openid=OpenID
oauth_signup_tab=Créer un compte
@@ -1878,6 +1880,7 @@ pulls.add_prefix=Ajouter le préfixe <strong>%s</strong>
pulls.remove_prefix=Enlever le préfixe <strong>%s</strong>
pulls.data_broken=Cette demande d’ajout est impossible par manque d'informations de bifurcation.
pulls.files_conflicted=Cette demande d'ajout contient des modifications en conflit avec la branche ciblée.
+pulls.is_checking=Recherche de conflits de fusion…
pulls.is_ancestor=Cette branche est déjà présente dans la branche ciblée. Il n'y a rien à fusionner.
pulls.is_empty=Les changements sur cette branche sont déjà sur la branche cible. Cette révision sera vide.
pulls.required_status_check_failed=Certains contrôles requis n'ont pas réussi.
@@ -3718,13 +3721,14 @@ owner.settings.chef.keypair.description=Une paire de clés est nécessaire pour
secrets=Secrets
description=Les secrets seront transmis à certaines actions et ne pourront pas être lus autrement.
none=Il n'y a pas encore de secrets.
-creation=Ajouter un secret
+
+; These keys are also for "edit secret", the keys are kept as-is to avoid unnecessary re-translation
creation.description=Description
creation.name_placeholder=Caractères alphanumériques ou tirets bas uniquement, insensibles à la casse, ne peut commencer par GITEA_ ou GITHUB_.
creation.value_placeholder=Entrez n’importe quoi. Les blancs cernant seront taillés.
creation.description_placeholder=Décrire brièvement votre dépôt (optionnel).
-creation.success=Le secret "%s" a été ajouté.
-creation.failed=Impossible d'ajouter le secret.
+
+
deletion=Supprimer le secret
deletion.description=La suppression d'un secret est permanente et irréversible. Continuer ?
deletion.success=Le secret a été supprimé.
diff --git a/options/locale/locale_ga-IE.ini b/options/locale/locale_ga-IE.ini
index ca9712b9e1..cdde7e015d 100644
--- a/options/locale/locale_ga-IE.ini
+++ b/options/locale/locale_ga-IE.ini
@@ -3721,13 +3721,14 @@ owner.settings.chef.keypair.description=Tá eochairphéire riachtanach le fíord
secrets=Rúin
description=Cuirfear rúin ar aghaidh chuig gníomhartha áirithe agus ní féidir iad a léamh ar mhalairt.
none=Níl aon rúin ann fós.
-creation=Cuir Rúnda leis
+
+; These keys are also for "edit secret", the keys are kept as-is to avoid unnecessary re-translation
creation.description=Cur síos
creation.name_placeholder=carachtair alfanumair nó íoslaghda amháin nach féidir a thosú le GITEA_ nó GITHUB_
creation.value_placeholder=Ionchur ábhar ar bith. Fágfar spás bán ag tús agus ag deireadh ar lár.
creation.description_placeholder=Cuir isteach cur síos gairid (roghnach).
-creation.success=Tá an rún "%s" curtha leis.
-creation.failed=Theip ar an rún a chur leis.
+
+
deletion=Bain rún
deletion.description=Is buan rún a bhaint agus ní féidir é a chealú. Lean ort?
deletion.success=Tá an rún bainte.
diff --git a/options/locale/locale_hu-HU.ini b/options/locale/locale_hu-HU.ini
index 0dae5505aa..ebc6d5c801 100644
--- a/options/locale/locale_hu-HU.ini
+++ b/options/locale/locale_hu-HU.ini
@@ -1592,8 +1592,12 @@ conan.details.repository=Tároló
owner.settings.cleanuprules.enabled=Engedélyezett
[secrets]
+
+; These keys are also for "edit secret", the keys are kept as-is to avoid unnecessary re-translation
creation.description=Leírás
+
+
[actions]
diff --git a/options/locale/locale_id-ID.ini b/options/locale/locale_id-ID.ini
index 808ebaa9ec..54b0499d96 100644
--- a/options/locale/locale_id-ID.ini
+++ b/options/locale/locale_id-ID.ini
@@ -1394,8 +1394,12 @@ conan.details.repository=Repositori
owner.settings.cleanuprules.enabled=Aktif
[secrets]
+
+; These keys are also for "edit secret", the keys are kept as-is to avoid unnecessary re-translation
creation.description=Deskripsi
+
+
[actions]
diff --git a/options/locale/locale_is-IS.ini b/options/locale/locale_is-IS.ini
index 999b21c608..42ecfabe22 100644
--- a/options/locale/locale_is-IS.ini
+++ b/options/locale/locale_is-IS.ini
@@ -1325,8 +1325,12 @@ npm.details.tag=Merki
pypi.requires=Þarfnast Python
[secrets]
+
+; These keys are also for "edit secret", the keys are kept as-is to avoid unnecessary re-translation
creation.description=Lýsing
+
+
[actions]
diff --git a/options/locale/locale_it-IT.ini b/options/locale/locale_it-IT.ini
index f4a6767ea4..569d3f54e1 100644
--- a/options/locale/locale_it-IT.ini
+++ b/options/locale/locale_it-IT.ini
@@ -2782,8 +2782,12 @@ settings.delete.error=Impossibile eliminare il pacchetto.
owner.settings.cleanuprules.enabled=Attivo
[secrets]
+
+; These keys are also for "edit secret", the keys are kept as-is to avoid unnecessary re-translation
creation.description=Descrizione
+
+
[actions]
diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini
index a6366565b2..7790dccd6b 100644
--- a/options/locale/locale_ja-JP.ini
+++ b/options/locale/locale_ja-JP.ini
@@ -3718,13 +3718,14 @@ owner.settings.chef.keypair.description=Chefレジストリの認証にはキー
secrets=シークレット
description=シークレットは特定のActionsに渡されます。 それ以外で読み出されることはありません。
none=シークレットはまだありません。
-creation=シークレットを追加
+
+; These keys are also for "edit secret", the keys are kept as-is to avoid unnecessary re-translation
creation.description=説明
creation.name_placeholder=大文字小文字の区別なし、英数字とアンダースコアのみ、GITEA_ や GITHUB_ で始まるものは不可
creation.value_placeholder=内容を入力してください。前後の空白は除去されます。
creation.description_placeholder=簡単な説明を入力してください。 (オプション)
-creation.success=シークレット "%s" を追加しました。
-creation.failed=シークレットの追加に失敗しました。
+
+
deletion=シークレットの削除
deletion.description=シークレットの削除は恒久的で元に戻すことはできません。 続行しますか?
deletion.success=シークレットを削除しました。
diff --git a/options/locale/locale_ko-KR.ini b/options/locale/locale_ko-KR.ini
index 08f6d723de..22bf3e1641 100644
--- a/options/locale/locale_ko-KR.ini
+++ b/options/locale/locale_ko-KR.ini
@@ -1542,8 +1542,12 @@ conan.details.repository=저장소
owner.settings.cleanuprules.enabled=활성화됨
[secrets]
+
+; These keys are also for "edit secret", the keys are kept as-is to avoid unnecessary re-translation
creation.description=설명
+
+
[actions]
diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini
index 718ca0594e..a746f8738c 100644
--- a/options/locale/locale_lv-LV.ini
+++ b/options/locale/locale_lv-LV.ini
@@ -3332,12 +3332,13 @@ owner.settings.chef.keypair.description=Atslēgu pāris ir nepieciešams, lai au
secrets=Noslēpumi
description=Noslēpumi tiks padoti atsevišķām darbībām un citādi nevar tikt nolasīti.
none=Pagaidām nav neviena noslēpuma.
-creation=Pievienot noslēpumu
+
+; These keys are also for "edit secret", the keys are kept as-is to avoid unnecessary re-translation
creation.description=Apraksts
creation.name_placeholder=reģistr-nejūtīgs, tikai burti, cipari un apakšsvītras, nevar sākties ar GITEA_ vai GITHUB_
creation.value_placeholder=Ievadiet jebkādu saturu. Atstarpes sākumā un beigā tiks noņemtas.
-creation.success=Noslēpums "%s" tika pievienots.
-creation.failed=Neizdevās pievienot noslēpumu.
+
+
deletion=Dzēst noslēpumu
deletion.description=Noslēpuma dzēšana ir neatgriezeniska. Vai turpināt?
deletion.success=Noslēpums tika izdzēsts.
diff --git a/options/locale/locale_nl-NL.ini b/options/locale/locale_nl-NL.ini
index eff4c1f85f..b6887ee9e0 100644
--- a/options/locale/locale_nl-NL.ini
+++ b/options/locale/locale_nl-NL.ini
@@ -2515,8 +2515,12 @@ settings.link.button=Repository link bijwerken
owner.settings.cleanuprules.enabled=Ingeschakeld
[secrets]
+
+; These keys are also for "edit secret", the keys are kept as-is to avoid unnecessary re-translation
creation.description=Omschrijving
+
+
[actions]
diff --git a/options/locale/locale_pl-PL.ini b/options/locale/locale_pl-PL.ini
index b45f0fc8e0..42a33f9ce4 100644
--- a/options/locale/locale_pl-PL.ini
+++ b/options/locale/locale_pl-PL.ini
@@ -2405,8 +2405,12 @@ conan.details.repository=Repozytorium
owner.settings.cleanuprules.enabled=Włączone
[secrets]
+
+; These keys are also for "edit secret", the keys are kept as-is to avoid unnecessary re-translation
creation.description=Opis
+
+
[actions]
diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini
index 75d425417c..8ee675e6e0 100644
--- a/options/locale/locale_pt-BR.ini
+++ b/options/locale/locale_pt-BR.ini
@@ -3269,12 +3269,13 @@ owner.settings.chef.keypair=Gerar par de chaves
secrets=Segredos
description=Os segredos serão passados a certas ações e não poderão ser lidos de outra forma.
none=Não há segredos ainda.
-creation=Adicionar Segredo
+
+; These keys are also for "edit secret", the keys are kept as-is to avoid unnecessary re-translation
creation.description=Descrição
creation.name_placeholder=apenas caracteres alfanuméricos ou underline (_), não pode começar com GITEA_ ou GITHUB_
creation.value_placeholder=Insira qualquer conteúdo. Espaços em branco no início e no fim serão omitidos.
-creation.success=O segredo "%s" foi adicionado.
-creation.failed=Falha ao adicionar segredo.
+
+
deletion=Excluir segredo
deletion.description=A exclusão de um segredo é permanente e não pode ser desfeita. Continuar?
deletion.success=O segredo foi excluído.
diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini
index 00fa30e2e1..2f04452a35 100644
--- a/options/locale/locale_pt-PT.ini
+++ b/options/locale/locale_pt-PT.ini
@@ -3721,13 +3721,14 @@ owner.settings.chef.keypair.description=É necessário um par de chaves para aut
secrets=Segredos
description=Os segredos serão transmitidos a certas operações e não poderão ser lidos de outra forma.
none=Ainda não há segredos.
-creation=Adicionar segredo
+
+; These keys are also for "edit secret", the keys are kept as-is to avoid unnecessary re-translation
creation.description=Descrição
creation.name_placeholder=Só sublinhados ou alfanuméricos sem distinguir maiúsculas, sem começar com GITEA_ nem GITHUB_
creation.value_placeholder=Insira um conteúdo qualquer. Espaços em branco no início ou no fim serão omitidos.
creation.description_placeholder=Escreva uma descrição curta (opcional).
-creation.success=O segredo "%s" foi adicionado.
-creation.failed=Falhou ao adicionar o segredo.
+
+
deletion=Remover segredo
deletion.description=Remover um segredo é permanente e não pode ser revertido. Continuar?
deletion.success=O segredo foi removido.
diff --git a/options/locale/locale_ru-RU.ini b/options/locale/locale_ru-RU.ini
index 879d7c6145..c65d08a4cf 100644
--- a/options/locale/locale_ru-RU.ini
+++ b/options/locale/locale_ru-RU.ini
@@ -3266,12 +3266,13 @@ owner.settings.chef.keypair=Создать пару ключей
secrets=Секреты
description=Секреты будут передаваться определенным действиям и не могут быть прочитаны иначе.
none=Секретов пока нет.
-creation=Добавить секрет
+
+; These keys are also for "edit secret", the keys are kept as-is to avoid unnecessary re-translation
creation.description=Описание
creation.name_placeholder=регистр не важен, только алфавитно-цифровые символы и подчёркивания, не может начинаться с GITEA_ или GITHUB_
creation.value_placeholder=Введите любое содержимое. Пробельные символы в начале и конце будут опущены.
-creation.success=Секрет «%s» добавлен.
-creation.failed=Не удалось добавить секрет.
+
+
deletion=Удалить секрет
deletion.description=Удаление секрета необратимо, его нельзя отменить. Продолжить?
deletion.success=Секрет удалён.
diff --git a/options/locale/locale_si-LK.ini b/options/locale/locale_si-LK.ini
index 042e8ad21b..a209187aff 100644
--- a/options/locale/locale_si-LK.ini
+++ b/options/locale/locale_si-LK.ini
@@ -2447,8 +2447,12 @@ conan.details.repository=කෝෂ්ඨය
owner.settings.cleanuprules.enabled=සබල කර ඇත
[secrets]
+
+; These keys are also for "edit secret", the keys are kept as-is to avoid unnecessary re-translation
creation.description=සවිස්තරය
+
+
[actions]
diff --git a/options/locale/locale_sk-SK.ini b/options/locale/locale_sk-SK.ini
index b1dae7c490..e461075e53 100644
--- a/options/locale/locale_sk-SK.ini
+++ b/options/locale/locale_sk-SK.ini
@@ -1321,6 +1321,10 @@ owner.settings.cleanuprules.enabled=Povolené
[secrets]
+; These keys are also for "edit secret", the keys are kept as-is to avoid unnecessary re-translation
+
+
+
[actions]
diff --git a/options/locale/locale_sv-SE.ini b/options/locale/locale_sv-SE.ini
index 6fb5a9c4cb..04428aeab2 100644
--- a/options/locale/locale_sv-SE.ini
+++ b/options/locale/locale_sv-SE.ini
@@ -1982,8 +1982,12 @@ conan.details.repository=Utvecklingskatalog
owner.settings.cleanuprules.enabled=Aktiv
[secrets]
+
+; These keys are also for "edit secret", the keys are kept as-is to avoid unnecessary re-translation
creation.description=Beskrivning
+
+
[actions]
diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini
index acd0892eba..d617598057 100644
--- a/options/locale/locale_tr-TR.ini
+++ b/options/locale/locale_tr-TR.ini
@@ -3525,12 +3525,13 @@ owner.settings.chef.keypair.description=Chef kütüğünde kimlik doğrulaması
secrets=Gizlilikler
description=Gizlilikler belirli işlemlere aktarılacaktır, bunun dışında okunamaz.
none=Henüz gizlilik yok.
-creation=Gizlilik Ekle
+
+; These keys are also for "edit secret", the keys are kept as-is to avoid unnecessary re-translation
creation.description=Açıklama
creation.name_placeholder=küçük-büyük harfe duyarlı değil, alfanümerik karakterler veya sadece alt tire, GITEA_ veya GITHUB_ ile başlayamaz
creation.value_placeholder=Herhangi bir içerik girin. Baştaki ve sondaki boşluklar ihmal edilecektir.
-creation.success=Gizlilik "%s" eklendi.
-creation.failed=Gizlilik eklenemedi.
+
+
deletion=Gizliliği kaldır
deletion.description=Bir gizliliği kaldırma kalıcıdır ve geri alınamaz. Devam edilsin mi?
deletion.success=Gizlilik kaldırıldı.
diff --git a/options/locale/locale_uk-UA.ini b/options/locale/locale_uk-UA.ini
index 3a6d1539fa..6aed70491b 100644
--- a/options/locale/locale_uk-UA.ini
+++ b/options/locale/locale_uk-UA.ini
@@ -2517,8 +2517,12 @@ conan.details.repository=Репозиторій
owner.settings.cleanuprules.enabled=Увімкнено
[secrets]
+
+; These keys are also for "edit secret", the keys are kept as-is to avoid unnecessary re-translation
creation.description=Опис
+
+
[actions]
diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini
index 0e7db6350c..f6d6183e52 100644
--- a/options/locale/locale_zh-CN.ini
+++ b/options/locale/locale_zh-CN.ini
@@ -3717,13 +3717,14 @@ owner.settings.chef.keypair.description=需要密钥对才能向 Chef 注册中
secrets=密钥
description=Secrets 将被传给特定的 Actions,其它情况将不能读取
none=还没有密钥。
-creation=添加密钥
+
+; These keys are also for "edit secret", the keys are kept as-is to avoid unnecessary re-translation
creation.description=组织描述
creation.name_placeholder=不区分大小写,字母数字或下划线不能以GITEA_ 或 GITHUB_ 开头。
creation.value_placeholder=输入任何内容,开头和结尾的空白都会被省略
creation.description_placeholder=输入简短描述(可选)。
-creation.success=您的密钥 '%s' 添加成功。
-creation.failed=添加密钥失败。
+
+
deletion=删除密钥
deletion.description=删除密钥是永久性的,无法撤消。继续吗?
deletion.success=此Secret已被删除。
diff --git a/options/locale/locale_zh-HK.ini b/options/locale/locale_zh-HK.ini
index b157a44c69..2874da3170 100644
--- a/options/locale/locale_zh-HK.ini
+++ b/options/locale/locale_zh-HK.ini
@@ -959,8 +959,12 @@ conan.details.repository=儲存庫
owner.settings.cleanuprules.enabled=已啟用
[secrets]
+
+; These keys are also for "edit secret", the keys are kept as-is to avoid unnecessary re-translation
creation.description=組織描述
+
+
[actions]
diff --git a/options/locale/locale_zh-TW.ini b/options/locale/locale_zh-TW.ini
index 3b25c81be3..a52e147415 100644
--- a/options/locale/locale_zh-TW.ini
+++ b/options/locale/locale_zh-TW.ini
@@ -3635,12 +3635,13 @@ owner.settings.chef.keypair.description=驗證 Chef 註冊中心需要一個密
secrets=Secret
description=Secret 會被傳給特定的 Action,其他情況無法讀取。
none=還沒有 Secret。
-creation=加入 Secret
+
+; These keys are also for "edit secret", the keys are kept as-is to avoid unnecessary re-translation
creation.description=描述
creation.name_placeholder=不區分大小寫,只能包含英文字母、數字、底線 ('_'),不能以 GITEA_ 或 GITHUB_ 開頭。
creation.value_placeholder=輸入任何內容,頭尾的空白都會被忽略。
-creation.success=已新增 Secret「%s」。
-creation.failed=加入 Secret 失敗。
+
+
deletion=移除 Secret
deletion.description=移除 Secret 是永久的且不可還原,是否繼續?
deletion.success=已移除此 Secret。
diff --git a/package-lock.json b/package-lock.json
index 4c5963d0c8..e61fe3472d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,7 +10,7 @@
"@citation-js/plugin-csl": "0.7.18",
"@citation-js/plugin-software-formats": "0.6.1",
"@github/markdown-toolbar-element": "2.2.3",
- "@github/relative-time-element": "4.4.7",
+ "@github/relative-time-element": "4.4.8",
"@github/text-expander-element": "2.9.1",
"@mcaptcha/vanilla-glue": "0.1.0-alpha-3",
"@primer/octicons": "19.15.1",
@@ -1146,9 +1146,9 @@
"license": "MIT"
},
"node_modules/@github/relative-time-element": {
- "version": "4.4.7",
- "resolved": "https://registry.npmjs.org/@github/relative-time-element/-/relative-time-element-4.4.7.tgz",
- "integrity": "sha512-NZCePEFYtV7qAUI/pHYuqZ8vRhcsfH/dziUZTY9YR5+JwzDCWtEokYSDbDLZjrRl+SAFr02YHUK+UdtP6hPcbQ==",
+ "version": "4.4.8",
+ "resolved": "https://registry.npmjs.org/@github/relative-time-element/-/relative-time-element-4.4.8.tgz",
+ "integrity": "sha512-FSLYm6F3TSQnqHE1EMQUVVgi2XjbCvsESwwXfugHFpBnhyF1uhJOtu0Psp/BB/qqazfdkk7f5fVcu7WuXl3t8Q==",
"license": "MIT"
},
"node_modules/@github/text-expander-element": {
diff --git a/package.json b/package.json
index 0202b92ff4..bc2c0c87f3 100644
--- a/package.json
+++ b/package.json
@@ -9,7 +9,7 @@
"@citation-js/plugin-csl": "0.7.18",
"@citation-js/plugin-software-formats": "0.6.1",
"@github/markdown-toolbar-element": "2.2.3",
- "@github/relative-time-element": "4.4.7",
+ "@github/relative-time-element": "4.4.8",
"@github/text-expander-element": "2.9.1",
"@mcaptcha/vanilla-glue": "0.1.0-alpha-3",
"@primer/octicons": "19.15.1",
diff --git a/routers/private/serv.go b/routers/private/serv.go
index 37fbc0730c..b879be0dc2 100644
--- a/routers/private/serv.go
+++ b/routers/private/serv.go
@@ -81,6 +81,7 @@ func ServCommand(ctx *context.PrivateContext) {
ownerName := ctx.PathParam("owner")
repoName := ctx.PathParam("repo")
mode := perm.AccessMode(ctx.FormInt("mode"))
+ verb := ctx.FormString("verb")
// Set the basic parts of the results to return
results := private.ServCommandResults{
@@ -295,8 +296,11 @@ func ServCommand(ctx *context.PrivateContext) {
return
}
} else {
- // Because of the special ref "refs/for" we will need to delay write permission check
- if git.DefaultFeatures().SupportProcReceive && unitType == unit.TypeCode {
+ // Because of the special ref "refs/for" (AGit) we will need to delay write permission check,
+ // AGit flow needs to write its own ref when the doer has "reader" permission (allowing to create PR).
+ // The real permission check is done in HookPreReceive (routers/private/hook_pre_receive.go).
+ // Here it should relax the permission check for "git push (git-receive-pack)", but not for others like LFS operations.
+ if git.DefaultFeatures().SupportProcReceive && unitType == unit.TypeCode && verb == git.CmdVerbReceivePack {
mode = perm.AccessModeRead
}
diff --git a/routers/web/feed/convert.go b/routers/web/feed/convert.go
index b04855fa6a..7c59132841 100644
--- a/routers/web/feed/convert.go
+++ b/routers/web/feed/convert.go
@@ -201,7 +201,7 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio
switch act.OpType {
case activities_model.ActionCommitRepo, activities_model.ActionMirrorSyncPush:
push := templates.ActionContent2Commits(act)
-
+ _ = act.LoadRepo(ctx)
for _, commit := range push.Commits {
if len(desc) != 0 {
desc += "\n\n"
@@ -209,7 +209,7 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio
desc += fmt.Sprintf("<a href=\"%s\">%s</a>\n%s",
html.EscapeString(fmt.Sprintf("%s/commit/%s", act.GetRepoAbsoluteLink(ctx), commit.Sha1)),
commit.Sha1,
- renderUtils.RenderCommitMessage(commit.Message, nil),
+ renderUtils.RenderCommitMessage(commit.Message, act.Repo),
)
}
diff --git a/routers/web/repo/actions/view.go b/routers/web/repo/actions/view.go
index 2ec6389263..dd18c8380d 100644
--- a/routers/web/repo/actions/view.go
+++ b/routers/web/repo/actions/view.go
@@ -200,13 +200,9 @@ func ViewPost(ctx *context_module.Context) {
}
}
- // TODO: "ComposeCommentMetas" (usually for comment) is not quite right, but it is still the same as what template "RenderCommitMessage" does.
- // need to be refactored together in the future
- metas := ctx.Repo.Repository.ComposeCommentMetas(ctx)
-
// the title for the "run" is from the commit message
resp.State.Run.Title = run.Title
- resp.State.Run.TitleHTML = templates.NewRenderUtils(ctx).RenderCommitMessage(run.Title, metas)
+ resp.State.Run.TitleHTML = templates.NewRenderUtils(ctx).RenderCommitMessage(run.Title, ctx.Repo.Repository)
resp.State.Run.Link = run.Link()
resp.State.Run.CanCancel = !run.Status.IsDone() && ctx.Repo.CanWrite(unit.TypeActions)
resp.State.Run.CanApprove = run.NeedApproval && ctx.Repo.CanWrite(unit.TypeActions)
diff --git a/templates/repo/branch/list.tmpl b/templates/repo/branch/list.tmpl
index aa38413ad7..fffe3a08cc 100644
--- a/templates/repo/branch/list.tmpl
+++ b/templates/repo/branch/list.tmpl
@@ -27,7 +27,7 @@
<button class="btn interact-fg tw-px-1" data-clipboard-text="{{.DefaultBranchBranch.DBBranch.Name}}" data-tooltip-content="{{ctx.Locale.Tr "copy_branch"}}">{{svg "octicon-copy" 14}}</button>
{{template "repo/commit_statuses" dict "Status" (index $.CommitStatus .DefaultBranchBranch.DBBranch.CommitID) "Statuses" (index $.CommitStatuses .DefaultBranchBranch.DBBranch.CommitID)}}
</div>
- <p class="info tw-flex tw-items-center tw-my-1">{{svg "octicon-git-commit" 16 "tw-mr-1"}}<a href="{{.RepoLink}}/commit/{{PathEscape .DefaultBranchBranch.DBBranch.CommitID}}">{{ShortSha .DefaultBranchBranch.DBBranch.CommitID}}</a> · <span class="commit-message">{{ctx.RenderUtils.RenderCommitMessage .DefaultBranchBranch.DBBranch.CommitMessage (.Repository.ComposeCommentMetas ctx)}}</span> · {{ctx.Locale.Tr "org.repo_updated"}} {{DateUtils.TimeSince .DefaultBranchBranch.DBBranch.CommitTime}}{{if .DefaultBranchBranch.DBBranch.Pusher}} &nbsp;{{template "shared/user/avatarlink" dict "user" .DefaultBranchBranch.DBBranch.Pusher}}{{template "shared/user/namelink" .DefaultBranchBranch.DBBranch.Pusher}}{{end}}</p>
+ <p class="info tw-flex tw-items-center tw-my-1">{{svg "octicon-git-commit" 16 "tw-mr-1"}}<a href="{{.RepoLink}}/commit/{{PathEscape .DefaultBranchBranch.DBBranch.CommitID}}">{{ShortSha .DefaultBranchBranch.DBBranch.CommitID}}</a> · <span class="commit-message">{{ctx.RenderUtils.RenderCommitMessage .DefaultBranchBranch.DBBranch.CommitMessage .Repository}}</span> · {{ctx.Locale.Tr "org.repo_updated"}} {{DateUtils.TimeSince .DefaultBranchBranch.DBBranch.CommitTime}}{{if .DefaultBranchBranch.DBBranch.Pusher}} &nbsp;{{template "shared/user/avatarlink" dict "user" .DefaultBranchBranch.DBBranch.Pusher}}{{template "shared/user/namelink" .DefaultBranchBranch.DBBranch.Pusher}}{{end}}</p>
</td>
{{/* FIXME: here and below, the tw-overflow-visible is not quite right but it is still needed the moment: to show the important buttons when the width is narrow */}}
<td class="tw-text-right tw-overflow-visible">
@@ -103,7 +103,7 @@
<button class="btn interact-fg tw-px-1" data-clipboard-text="{{.DBBranch.Name}}" data-tooltip-content="{{ctx.Locale.Tr "copy_branch"}}">{{svg "octicon-copy" 14}}</button>
{{template "repo/commit_statuses" dict "Status" (index $.CommitStatus .DBBranch.CommitID) "Statuses" (index $.CommitStatuses .DBBranch.CommitID)}}
</div>
- <p class="info tw-flex tw-items-center tw-my-1">{{svg "octicon-git-commit" 16 "tw-mr-1"}}<a href="{{$.RepoLink}}/commit/{{PathEscape .DBBranch.CommitID}}">{{ShortSha .DBBranch.CommitID}}</a> · <span class="commit-message">{{ctx.RenderUtils.RenderCommitMessage .DBBranch.CommitMessage ($.Repository.ComposeCommentMetas ctx)}}</span> · {{ctx.Locale.Tr "org.repo_updated"}} {{DateUtils.TimeSince .DBBranch.CommitTime}}{{if .DBBranch.Pusher}} &nbsp;{{template "shared/user/avatarlink" dict "user" .DBBranch.Pusher}} &nbsp;{{template "shared/user/namelink" .DBBranch.Pusher}}{{end}}</p>
+ <p class="info tw-flex tw-items-center tw-my-1">{{svg "octicon-git-commit" 16 "tw-mr-1"}}<a href="{{$.RepoLink}}/commit/{{PathEscape .DBBranch.CommitID}}">{{ShortSha .DBBranch.CommitID}}</a> · <span class="commit-message">{{ctx.RenderUtils.RenderCommitMessage .DBBranch.CommitMessage $.Repository}}</span> · {{ctx.Locale.Tr "org.repo_updated"}} {{DateUtils.TimeSince .DBBranch.CommitTime}}{{if .DBBranch.Pusher}} &nbsp;{{template "shared/user/avatarlink" dict "user" .DBBranch.Pusher}} &nbsp;{{template "shared/user/namelink" .DBBranch.Pusher}}{{end}}</p>
{{end}}
</td>
<td class="two wide ui">
diff --git a/templates/repo/commit_page.tmpl b/templates/repo/commit_page.tmpl
index 5639c87a82..7abd377108 100644
--- a/templates/repo/commit_page.tmpl
+++ b/templates/repo/commit_page.tmpl
@@ -5,7 +5,7 @@
<div class="ui container fluid padded">
<div class="ui top attached header clearing segment tw-relative commit-header">
<div class="tw-flex tw-mb-4 tw-gap-1">
- <h3 class="tw-mb-0 tw-flex-1"><span class="commit-summary" title="{{.Commit.Summary}}">{{ctx.RenderUtils.RenderCommitMessage .Commit.Message ($.Repository.ComposeCommentMetas ctx)}}</span>{{template "repo/commit_statuses" dict "Status" .CommitStatus "Statuses" .CommitStatuses}}</h3>
+ <h3 class="tw-mb-0 tw-flex-1"><span class="commit-summary" title="{{.Commit.Summary}}">{{ctx.RenderUtils.RenderCommitMessage .Commit.Message $.Repository}}</span>{{template "repo/commit_statuses" dict "Status" .CommitStatus "Statuses" .CommitStatuses}}</h3>
{{if not $.PageIsWiki}}
<div class="commit-header-buttons">
<a class="ui primary tiny button" href="{{.SourcePath}}">
@@ -122,7 +122,7 @@
{{end}}
</div>
{{if IsMultilineCommitMessage .Commit.Message}}
- <pre class="commit-body">{{ctx.RenderUtils.RenderCommitBody .Commit.Message ($.Repository.ComposeCommentMetas ctx)}}</pre>
+ <pre class="commit-body">{{ctx.RenderUtils.RenderCommitBody .Commit.Message $.Repository}}</pre>
{{end}}
{{template "repo/commit_load_branches_and_tags" .}}
</div>
diff --git a/templates/repo/commits_list.tmpl b/templates/repo/commits_list.tmpl
index 17c7240ee4..8a268a5d14 100644
--- a/templates/repo/commits_list.tmpl
+++ b/templates/repo/commits_list.tmpl
@@ -44,7 +44,7 @@
<span class="commit-summary {{if gt .ParentCount 1}} grey text{{end}}" title="{{.Summary}}">{{.Summary | ctx.RenderUtils.RenderEmoji}}</span>
{{else}}
{{$commitLink:= printf "%s/commit/%s" $commitRepoLink (PathEscape .ID.String)}}
- <span class="commit-summary {{if gt .ParentCount 1}} grey text{{end}}" title="{{.Summary}}">{{ctx.RenderUtils.RenderCommitMessageLinkSubject .Message $commitLink ($.Repository.ComposeCommentMetas ctx)}}</span>
+ <span class="commit-summary {{if gt .ParentCount 1}} grey text{{end}}" title="{{.Summary}}">{{ctx.RenderUtils.RenderCommitMessageLinkSubject .Message $commitLink $.Repository}}</span>
{{end}}
</span>
{{if IsMultilineCommitMessage .Message}}
@@ -52,7 +52,7 @@
{{end}}
{{template "repo/commit_statuses" dict "Status" .Status "Statuses" .Statuses}}
{{if IsMultilineCommitMessage .Message}}
- <pre class="commit-body tw-hidden">{{ctx.RenderUtils.RenderCommitBody .Message ($.Repository.ComposeCommentMetas ctx)}}</pre>
+ <pre class="commit-body tw-hidden">{{ctx.RenderUtils.RenderCommitBody .Message $.Repository}}</pre>
{{end}}
{{if $.CommitsTagsMap}}
{{range (index $.CommitsTagsMap .ID.String)}}
diff --git a/templates/repo/commits_list_small.tmpl b/templates/repo/commits_list_small.tmpl
index b054ce19a5..ee94ad7e58 100644
--- a/templates/repo/commits_list_small.tmpl
+++ b/templates/repo/commits_list_small.tmpl
@@ -15,7 +15,7 @@
{{$commitLink:= printf "%s/%s" $commitBaseLink (PathEscape .ID.String)}}
<span class="tw-flex-1 tw-font-mono gt-ellipsis" title="{{.Summary}}">
- {{- ctx.RenderUtils.RenderCommitMessageLinkSubject .Message $commitLink ($.comment.Issue.PullRequest.BaseRepo.ComposeCommentMetas ctx) -}}
+ {{- ctx.RenderUtils.RenderCommitMessageLinkSubject .Message $commitLink $.comment.Issue.PullRequest.BaseRepo -}}
</span>
{{if IsMultilineCommitMessage .Message}}
@@ -29,7 +29,7 @@
</div>
{{if IsMultilineCommitMessage .Message}}
<pre class="commit-body tw-ml-[33px] tw-hidden" data-singular-commit-body-for="{{$tag}}">
- {{- ctx.RenderUtils.RenderCommitBody .Message ($.comment.Issue.PullRequest.BaseRepo.ComposeCommentMetas ctx) -}}
+ {{- ctx.RenderUtils.RenderCommitBody .Message $.comment.Issue.PullRequest.BaseRepo -}}
</pre>
{{end}}
{{end}}
diff --git a/templates/repo/diff/compare.tmpl b/templates/repo/diff/compare.tmpl
index 6f16ce3bd8..4e8ad1326c 100644
--- a/templates/repo/diff/compare.tmpl
+++ b/templates/repo/diff/compare.tmpl
@@ -189,7 +189,7 @@
<div class="ui segment flex-text-block tw-gap-4">
{{template "shared/issueicon" .}}
<div class="issue-title tw-break-anywhere">
- {{ctx.RenderUtils.RenderIssueTitle .PullRequest.Issue.Title ($.Repository.ComposeCommentMetas ctx)}}
+ {{ctx.RenderUtils.RenderIssueTitle .PullRequest.Issue.Title $.Repository}}
<span class="index">#{{.PullRequest.Issue.Index}}</span>
</div>
<a href="{{$.RepoLink}}/pulls/{{.PullRequest.Issue.Index}}" class="ui compact button primary">
diff --git a/templates/repo/graph/commits.tmpl b/templates/repo/graph/commits.tmpl
index 630c4579ea..34167cadc0 100644
--- a/templates/repo/graph/commits.tmpl
+++ b/templates/repo/graph/commits.tmpl
@@ -8,7 +8,7 @@
{{template "repo/commit_sign_badge" dict "Commit" $commit.Commit "CommitBaseLink" (print $.RepoLink "/commit") "CommitSignVerification" $commit.Verification}}
<span class="message tw-inline-block gt-ellipsis">
- <span>{{ctx.RenderUtils.RenderCommitMessage $commit.Subject ($.Repository.ComposeCommentMetas ctx)}}</span>
+ <span>{{ctx.RenderUtils.RenderCommitMessage $commit.Subject $.Repository}}</span>
</span>
<span class="commit-refs flex-text-inline">
diff --git a/templates/repo/issue/view_title.tmpl b/templates/repo/issue/view_title.tmpl
index a4be598540..b8f28dfd9b 100644
--- a/templates/repo/issue/view_title.tmpl
+++ b/templates/repo/issue/view_title.tmpl
@@ -13,7 +13,7 @@
{{$canEditIssueTitle := and (or .HasIssuesOrPullsWritePermission .IsIssuePoster) (not .Repository.IsArchived)}}
<div class="issue-title" id="issue-title-display">
<h1 class="tw-break-anywhere">
- {{ctx.RenderUtils.RenderIssueTitle .Issue.Title ($.Repository.ComposeCommentMetas ctx)}}
+ {{ctx.RenderUtils.RenderIssueTitle .Issue.Title $.Repository}}
<span class="index">#{{.Issue.Index}}</span>
</h1>
<div class="issue-title-buttons">
diff --git a/templates/repo/latest_commit.tmpl b/templates/repo/latest_commit.tmpl
index da457e423a..cff338949f 100644
--- a/templates/repo/latest_commit.tmpl
+++ b/templates/repo/latest_commit.tmpl
@@ -21,10 +21,10 @@
{{template "repo/commit_statuses" dict "Status" .LatestCommitStatus "Statuses" .LatestCommitStatuses}}
{{$commitLink:= printf "%s/commit/%s" .RepoLink (PathEscape .LatestCommit.ID.String)}}
- <span class="grey commit-summary" title="{{.LatestCommit.Summary}}"><span class="message-wrapper">{{ctx.RenderUtils.RenderCommitMessageLinkSubject .LatestCommit.Message $commitLink ($.Repository.ComposeCommentMetas ctx)}}</span>
+ <span class="grey commit-summary" title="{{.LatestCommit.Summary}}"><span class="message-wrapper">{{ctx.RenderUtils.RenderCommitMessageLinkSubject .LatestCommit.Message $commitLink $.Repository}}</span>
{{if IsMultilineCommitMessage .LatestCommit.Message}}
<button class="ui button ellipsis-button" aria-expanded="false" data-global-click="onRepoEllipsisButtonClick">...</button>
- <pre class="commit-body tw-hidden">{{ctx.RenderUtils.RenderCommitBody .LatestCommit.Message ($.Repository.ComposeCommentMetas ctx)}}</pre>
+ <pre class="commit-body tw-hidden">{{ctx.RenderUtils.RenderCommitBody .LatestCommit.Message $.Repository}}</pre>
{{end}}
</span>
{{end}}
diff --git a/templates/repo/view_list.tmpl b/templates/repo/view_list.tmpl
index cd832498b4..c8ee059e89 100644
--- a/templates/repo/view_list.tmpl
+++ b/templates/repo/view_list.tmpl
@@ -47,7 +47,7 @@
<div class="repo-file-cell message loading-icon-2px">
{{if $commit}}
{{$commitLink := printf "%s/commit/%s" $.RepoLink (PathEscape $commit.ID.String)}}
- {{ctx.RenderUtils.RenderCommitMessageLinkSubject $commit.Message $commitLink ($.Repository.ComposeCommentMetas ctx)}}
+ {{ctx.RenderUtils.RenderCommitMessageLinkSubject $commit.Message $commitLink $.Repository}}
{{else}}
… {{/* will be loaded again by LastCommitLoaderURL */}}
{{end}}
diff --git a/templates/user/dashboard/feeds.tmpl b/templates/user/dashboard/feeds.tmpl
index 97291fc42d..4ee12fa783 100644
--- a/templates/user/dashboard/feeds.tmpl
+++ b/templates/user/dashboard/feeds.tmpl
@@ -94,7 +94,7 @@
<img alt class="ui avatar" src="{{$push.AvatarLink ctx .AuthorEmail}}" title="{{.AuthorName}}" width="16" height="16">
<a class="ui sha label" href="{{$commitLink}}">{{ShortSha .Sha1}}</a>
<span class="text truncate">
- {{ctx.RenderUtils.RenderCommitMessage .Message ($repo.ComposeCommentMetas ctx)}}
+ {{ctx.RenderUtils.RenderCommitMessage .Message $repo}}
</span>
</div>
{{end}}
diff --git a/tests/integration/git_general_test.go b/tests/integration/git_general_test.go
index 34fe212d50..ed60bdb58a 100644
--- a/tests/integration/git_general_test.go
+++ b/tests/integration/git_general_test.go
@@ -11,8 +11,10 @@ import (
"net/http"
"net/url"
"os"
+ "os/exec"
"path"
"path/filepath"
+ "slices"
"strconv"
"testing"
"time"
@@ -30,6 +32,7 @@ import (
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/tests"
+ "github.com/kballard/go-shellquote"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -105,7 +108,12 @@ func testGitGeneral(t *testing.T, u *url.URL) {
// Setup key the user ssh key
withKeyFile(t, keyname, func(keyFile string) {
- t.Run("CreateUserKey", doAPICreateUserKey(sshContext, "test-key", keyFile))
+ var keyID int64
+ t.Run("CreateUserKey", doAPICreateUserKey(sshContext, "test-key", keyFile, func(t *testing.T, key api.PublicKey) {
+ keyID = key.ID
+ }))
+ assert.NotZero(t, keyID)
+ t.Run("LFSAccessTest", doSSHLFSAccessTest(sshContext, keyID))
// Setup remote link
// TODO: get url from api
@@ -136,6 +144,36 @@ func testGitGeneral(t *testing.T, u *url.URL) {
})
}
+func doSSHLFSAccessTest(_ APITestContext, keyID int64) func(*testing.T) {
+ return func(t *testing.T) {
+ sshCommand := os.Getenv("GIT_SSH_COMMAND") // it is set in withKeyFile
+ sshCmdParts, err := shellquote.Split(sshCommand) // and parse the ssh command to construct some mocked arguments
+ require.NoError(t, err)
+
+ t.Run("User2AccessOwned", func(t *testing.T) {
+ sshCmdUser2Self := append(slices.Clone(sshCmdParts),
+ "-p", strconv.Itoa(setting.SSH.ListenPort), "git@"+setting.SSH.ListenHost,
+ "git-lfs-authenticate", "user2/repo1.git", "upload", // accessible to own repo
+ )
+ cmd := exec.CommandContext(t.Context(), sshCmdUser2Self[0], sshCmdUser2Self[1:]...)
+ _, err := cmd.Output()
+ assert.NoError(t, err) // accessible, no error
+ })
+
+ t.Run("User2AccessOther", func(t *testing.T) {
+ sshCmdUser2Other := append(slices.Clone(sshCmdParts),
+ "-p", strconv.Itoa(setting.SSH.ListenPort), "git@"+setting.SSH.ListenHost,
+ "git-lfs-authenticate", "user5/repo4.git", "upload", // inaccessible to other's (user5/repo4)
+ )
+ cmd := exec.CommandContext(t.Context(), sshCmdUser2Other[0], sshCmdUser2Other[1:]...)
+ _, err := cmd.Output()
+ var errExit *exec.ExitError
+ require.ErrorAs(t, err, &errExit) // inaccessible, error
+ assert.Contains(t, string(errExit.Stderr), fmt.Sprintf("User: 2:user2 with Key: %d:test-key is not authorized to write to user5/repo4.", keyID))
+ })
+ }
+}
+
func ensureAnonymousClone(t *testing.T, u *url.URL) {
dstLocalPath := t.TempDir()
t.Run("CloneAnonymous", doGitClone(dstLocalPath, u))
diff --git a/web_src/css/editor/combomarkdowneditor.css b/web_src/css/editor/combomarkdowneditor.css
index 835286b795..046010c6c8 100644
--- a/web_src/css/editor/combomarkdowneditor.css
+++ b/web_src/css/editor/combomarkdowneditor.css
@@ -100,67 +100,3 @@
border-bottom: 1px solid var(--color-secondary);
padding-bottom: 1rem;
}
-
-text-expander {
- display: block;
- position: relative;
-}
-
-text-expander .suggestions {
- position: absolute;
- min-width: 180px;
- padding: 0;
- margin-top: 24px;
- list-style: none;
- background: var(--color-box-body);
- border-radius: var(--border-radius);
- border: 1px solid var(--color-secondary);
- box-shadow: 0 .5rem 1rem var(--color-shadow);
- z-index: 100; /* needs to be > 20 to be on top of dropzone's .dz-details */
-}
-
-text-expander .suggestions li {
- display: flex;
- align-items: center;
- cursor: pointer;
- padding: 4px 8px;
- font-weight: var(--font-weight-medium);
-}
-
-text-expander .suggestions li + li {
- border-top: 1px solid var(--color-secondary-alpha-40);
-}
-
-text-expander .suggestions li:first-child {
- border-radius: var(--border-radius) var(--border-radius) 0 0;
-}
-
-text-expander .suggestions li:last-child {
- border-radius: 0 0 var(--border-radius) var(--border-radius);
-}
-
-text-expander .suggestions li:only-child {
- border-radius: var(--border-radius);
-}
-
-text-expander .suggestions li:hover {
- background: var(--color-hover);
-}
-
-text-expander .suggestions .fullname {
- font-weight: var(--font-weight-normal);
- margin-left: 4px;
- color: var(--color-text-light-1);
-}
-
-text-expander .suggestions li[aria-selected="true"],
-text-expander .suggestions li[aria-selected="true"] span {
- background: var(--color-primary);
- color: var(--color-primary-contrast);
-}
-
-text-expander .suggestions img {
- width: 24px;
- height: 24px;
- margin-right: 8px;
-}
diff --git a/web_src/css/features/expander.css b/web_src/css/features/expander.css
new file mode 100644
index 0000000000..f560b2a9fd
--- /dev/null
+++ b/web_src/css/features/expander.css
@@ -0,0 +1,96 @@
+text-expander .suggestions,
+.tribute-container {
+ position: absolute;
+ max-height: min(300px, 95vh);
+ max-width: min(500px, 95vw);
+ overflow-x: hidden;
+ overflow-y: auto;
+ white-space: nowrap;
+ background: var(--color-menu);
+ box-shadow: 0 6px 18px var(--color-shadow);
+ border-radius: var(--border-radius);
+ border: 1px solid var(--color-secondary);
+ z-index: 100; /* needs to be > 20 to be on top of dropzone's .dz-details */
+}
+
+text-expander {
+ display: block;
+ position: relative;
+}
+
+text-expander .suggestions {
+ padding: 0;
+ margin-top: 24px;
+ list-style: none;
+}
+
+text-expander .suggestions li,
+.tribute-item {
+ display: flex;
+ align-items: center;
+ cursor: pointer;
+ gap: 6px;
+ font-weight: var(--font-weight-medium);
+}
+
+text-expander .suggestions li,
+.tribute-container li {
+ padding: 3px 6px;
+}
+
+text-expander .suggestions li + li,
+.tribute-container li + li {
+ border-top: 1px solid var(--color-secondary);
+}
+
+text-expander .suggestions li:first-child {
+ border-radius: var(--border-radius) var(--border-radius) 0 0;
+}
+
+text-expander .suggestions li:last-child {
+ border-radius: 0 0 var(--border-radius) var(--border-radius);
+}
+
+text-expander .suggestions li:only-child {
+ border-radius: var(--border-radius);
+}
+
+text-expander .suggestions .fullname,
+.tribute-container li .fullname {
+ font-weight: var(--font-weight-normal);
+ color: var(--color-text-light-1);
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+text-expander .suggestions li:hover,
+text-expander .suggestions li:hover *,
+text-expander .suggestions li[aria-selected="true"],
+text-expander .suggestions li[aria-selected="true"] *,
+.tribute-container li.highlight,
+.tribute-container li.highlight * {
+ background: var(--color-primary);
+ color: var(--color-primary-contrast);
+}
+
+text-expander .suggestions img,
+.tribute-item img {
+ width: 21px;
+ height: 21px;
+ object-fit: contain;
+ aspect-ratio: 1;
+}
+
+.tribute-container {
+ display: block;
+}
+
+.tribute-container ul {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+.tribute-container li.no-match {
+ cursor: default;
+}
diff --git a/web_src/css/features/tribute.css b/web_src/css/features/tribute.css
deleted file mode 100644
index 99a026b9bc..0000000000
--- a/web_src/css/features/tribute.css
+++ /dev/null
@@ -1,32 +0,0 @@
-@import "tributejs/dist/tribute.css";
-
-.tribute-container {
- box-shadow: 0 0.25rem 0.5rem rgba(0, 0, 0, 0.25);
- border-radius: var(--border-radius);
-}
-
-.tribute-container ul {
- margin-top: 0 !important;
- background: var(--color-body) !important;
-}
-
-.tribute-container li {
- padding: 3px 0.5rem !important;
-}
-
-.tribute-container li span.fullname {
- font-weight: var(--font-weight-normal);
- font-size: 0.8rem;
-}
-
-.tribute-container li.highlight,
-.tribute-container li:hover {
- background: var(--color-primary) !important;
- color: var(--color-primary-contrast) !important;
-}
-
-.tribute-item {
- display: flex;
- align-items: center;
- gap: 6px;
-}
diff --git a/web_src/css/index.css b/web_src/css/index.css
index 84795d6d27..c20aa028e4 100644
--- a/web_src/css/index.css
+++ b/web_src/css/index.css
@@ -39,7 +39,7 @@
@import "./features/imagediff.css";
@import "./features/codeeditor.css";
@import "./features/projects.css";
-@import "./features/tribute.css";
+@import "./features/expander.css";
@import "./features/cropper.css";
@import "./features/console.css";
diff --git a/web_src/js/features/comp/TextExpander.ts b/web_src/js/features/comp/TextExpander.ts
index 5be234629d..2d79fe5029 100644
--- a/web_src/js/features/comp/TextExpander.ts
+++ b/web_src/js/features/comp/TextExpander.ts
@@ -97,6 +97,7 @@ export function initTextExpander(expander: TextExpanderElement) {
li.append(img);
const nameSpan = document.createElement('span');
+ nameSpan.classList.add('name');
nameSpan.textContent = name;
li.append(nameSpan);