diff options
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}} {{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}} {{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}} {{template "shared/user/avatarlink" dict "user" .DBBranch.Pusher}} {{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}} {{template "shared/user/avatarlink" dict "user" .DBBranch.Pusher}} {{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); |