From 433963e52ccbe2f469c83a0252ea4cab9b34a467 Mon Sep 17 00:00:00 2001 From: Yarden Shoham Date: Tue, 4 Jun 2024 06:01:06 +0300 Subject: [PATCH 01/12] Bump `@github/relative-time-element` to v4.4.1 (#31232) I tested and all timestamps work as before. Signed-off-by: Yarden Shoham --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 90cedd63d5d6e..8b1ba766d51f1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "@citation-js/plugin-csl": "0.7.11", "@citation-js/plugin-software-formats": "0.6.1", "@github/markdown-toolbar-element": "2.2.3", - "@github/relative-time-element": "4.4.0", + "@github/relative-time-element": "4.4.1", "@github/text-expander-element": "2.6.1", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", "@primer/octicons": "19.9.0", @@ -1028,9 +1028,9 @@ "integrity": "sha512-AlquKGee+IWiAMYVB0xyHFZRMnu4n3X4HTvJHu79GiVJ1ojTukCWyxMlF5NMsecoLcBKsuBhx3QPv2vkE/zQ0A==" }, "node_modules/@github/relative-time-element": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@github/relative-time-element/-/relative-time-element-4.4.0.tgz", - "integrity": "sha512-CrI6oAecoahG7PF5dsgjdvlF5kCtusVMjg810EULD81TvnDsP+k/FRi/ClFubWLgBo4EGpr2EfvmumtqQFo7ow==" + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@github/relative-time-element/-/relative-time-element-4.4.1.tgz", + "integrity": "sha512-E2vRcIgDj8AHv/iHpQMLJ/RqKOJ704OXkKw6+Zdhk3X+kVQhOf3Wj8KVz4DfCQ1eOJR8XxY6XVv73yd+pjMfXA==" }, "node_modules/@github/text-expander-element": { "version": "2.6.1", diff --git a/package.json b/package.json index d7588e093f9a1..5add488bb68a6 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "@citation-js/plugin-csl": "0.7.11", "@citation-js/plugin-software-formats": "0.6.1", "@github/markdown-toolbar-element": "2.2.3", - "@github/relative-time-element": "4.4.0", + "@github/relative-time-element": "4.4.1", "@github/text-expander-element": "2.6.1", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", "@primer/octicons": "19.9.0", From 93570de4968b7ea843f669b173c373c6fbd1c64a Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 4 Jun 2024 14:00:44 +0900 Subject: [PATCH 02/12] Update air package path (#31233) --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f273cac3a84ff..e9dc945206094 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ COMMA := , XGO_VERSION := go-1.22.x -AIR_PACKAGE ?= github.com/cosmtrek/air@v1 +AIR_PACKAGE ?= github.com/air-verse/air@v1 EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@2.7.0 GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.6.0 GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.59.0 From a7557494cad5aa850536e17cdaf93988f7daa56e Mon Sep 17 00:00:00 2001 From: silverwind Date: Tue, 4 Jun 2024 07:34:34 +0200 Subject: [PATCH 03/12] Update chroma to v2.14.0 (#31177) https://github.com/alecthomas/chroma/releases/tag/v2.14.0 Tested it with a typescript file. --- go.mod | 2 +- go.sum | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 87f2b00e6ae4a..6f739ed6e9830 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 github.com/ProtonMail/go-crypto v1.0.0 github.com/PuerkitoBio/goquery v1.9.1 - github.com/alecthomas/chroma/v2 v2.13.0 + github.com/alecthomas/chroma/v2 v2.14.0 github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb github.com/blevesearch/bleve/v2 v2.3.10 github.com/buildkite/terminal-to-html/v3 v3.11.0 diff --git a/go.sum b/go.sum index 84f7121908b35..543bd70866681 100644 --- a/go.sum +++ b/go.sum @@ -82,11 +82,11 @@ github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06 github.com/RoaringBitmap/roaring v0.7.1/go.mod h1:jdT9ykXwHFNdJbEtxePexlFYH9LXucApeS0/+/g+p1I= github.com/RoaringBitmap/roaring v1.9.0 h1:lwKhr90/j0jVXJyh5X+vQN1VVn77rQFfYnh6RDRGCcE= github.com/RoaringBitmap/roaring v1.9.0/go.mod h1:6AXUsoIEzDTFFQCe1RbGA6uFONMhvejWj5rqITANK90= -github.com/alecthomas/assert/v2 v2.6.0 h1:o3WJwILtexrEUk3cUVal3oiQY2tfgr/FHWiz/v2n4FU= -github.com/alecthomas/assert/v2 v2.6.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= +github.com/alecthomas/assert/v2 v2.7.0 h1:QtqSACNS3tF7oasA8CU6A6sXZSBDqnm7RfpLl9bZqbE= +github.com/alecthomas/assert/v2 v2.7.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs= -github.com/alecthomas/chroma/v2 v2.13.0 h1:VP72+99Fb2zEcYM0MeaWJmV+xQvz5v5cxRHd+ooU1lI= -github.com/alecthomas/chroma/v2 v2.13.0/go.mod h1:BUGjjsD+ndS6eX37YgTchSEG+Jg9Jv1GiZs9sqPqztk= +github.com/alecthomas/chroma/v2 v2.14.0 h1:R3+wzpnUArGcQz7fCETQBzO5n9IMNi13iIs46aU4V9E= +github.com/alecthomas/chroma/v2 v2.14.0/go.mod h1:QolEbTfmUHIMVpBqxeDnNBj2uoeI4EbYP4i6n68SG4I= github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8= github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= From 4f9b8b397c1acb6f6d26c55e224aafcb5474a85b Mon Sep 17 00:00:00 2001 From: silverwind Date: Tue, 4 Jun 2024 08:10:04 +0200 Subject: [PATCH 04/12] Fix overflow on notifications (#31178) Fixes https://github.com/go-gitea/gitea/issues/31170. image --- templates/user/notification/notification_div.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/user/notification/notification_div.tmpl b/templates/user/notification/notification_div.tmpl index bf3b51ee3baa0..9790a7087a9c4 100644 --- a/templates/user/notification/notification_div.tmpl +++ b/templates/user/notification/notification_div.tmpl @@ -44,14 +44,14 @@ {{end}} -
+
{{.Repository.FullName}} {{if .Issue}}#{{.Issue.Index}}{{end}} {{if eq .Status 3}} {{svg "octicon-pin" 13 "text blue tw-mt-0.5 tw-ml-1"}} {{end}}
- + {{if .Issue}} {{.Issue.Title | RenderEmoji $.Context | RenderCodeBlock}} {{else}} From c888c933a930ee2ba4e7bb0bf6678aaf45a9778a Mon Sep 17 00:00:00 2001 From: Thomas Desveaux Date: Tue, 4 Jun 2024 08:45:56 +0200 Subject: [PATCH 05/12] Fix NuGet Package API for $filter with Id equality (#31188) Fixes issue when running `choco info pkgname` where `pkgname` is also a substring of another package Id. Relates to #31168 --- This might fix the issue linked, but I'd like to test it with more choco commands before closing the issue in case I find other problems if that's ok. --------- Co-authored-by: KN4CK3R --- routers/api/packages/nuget/nuget.go | 48 +++++---- tests/integration/api_packages_nuget_test.go | 102 ++++++++++++++++--- 2 files changed, 115 insertions(+), 35 deletions(-) diff --git a/routers/api/packages/nuget/nuget.go b/routers/api/packages/nuget/nuget.go index 26b0ae226e45b..3633d0d00704c 100644 --- a/routers/api/packages/nuget/nuget.go +++ b/routers/api/packages/nuget/nuget.go @@ -96,20 +96,34 @@ func FeedCapabilityResource(ctx *context.Context) { xmlResponse(ctx, http.StatusOK, Metadata) } -var searchTermExtract = regexp.MustCompile(`'([^']+)'`) +var ( + searchTermExtract = regexp.MustCompile(`'([^']+)'`) + searchTermExact = regexp.MustCompile(`\s+eq\s+'`) +) -func getSearchTerm(ctx *context.Context) string { +func getSearchTerm(ctx *context.Context) packages_model.SearchValue { searchTerm := strings.Trim(ctx.FormTrim("searchTerm"), "'") - if searchTerm == "" { - // $filter contains a query like: - // (((Id ne null) and substringof('microsoft',tolower(Id))) - // We don't support these queries, just extract the search term. - match := searchTermExtract.FindStringSubmatch(ctx.FormTrim("$filter")) - if len(match) == 2 { - searchTerm = strings.TrimSpace(match[1]) + if searchTerm != "" { + return packages_model.SearchValue{ + Value: searchTerm, + ExactMatch: false, + } + } + + // $filter contains a query like: + // (((Id ne null) and substringof('microsoft',tolower(Id))) + // https://www.odata.org/documentation/odata-version-2-0/uri-conventions/ section 4.5 + // We don't support these queries, just extract the search term. + filter := ctx.FormTrim("$filter") + match := searchTermExtract.FindStringSubmatch(filter) + if len(match) == 2 { + return packages_model.SearchValue{ + Value: strings.TrimSpace(match[1]), + ExactMatch: searchTermExact.MatchString(filter), } } - return searchTerm + + return packages_model.SearchValue{} } // https://github.com/NuGet/NuGet.Client/blob/dev/src/NuGet.Core/NuGet.Protocol/LegacyFeed/V2FeedQueryBuilder.cs @@ -118,11 +132,9 @@ func SearchServiceV2(ctx *context.Context) { paginator := db.NewAbsoluteListOptions(skip, take) pvs, total, err := packages_model.SearchLatestVersions(ctx, &packages_model.PackageSearchOptions{ - OwnerID: ctx.Package.Owner.ID, - Type: packages_model.TypeNuGet, - Name: packages_model.SearchValue{ - Value: getSearchTerm(ctx), - }, + OwnerID: ctx.Package.Owner.ID, + Type: packages_model.TypeNuGet, + Name: getSearchTerm(ctx), IsInternal: optional.Some(false), Paginator: paginator, }) @@ -169,10 +181,8 @@ func SearchServiceV2(ctx *context.Context) { // http://docs.oasis-open.org/odata/odata/v4.0/errata03/os/complete/part2-url-conventions/odata-v4.0-errata03-os-part2-url-conventions-complete.html#_Toc453752351 func SearchServiceV2Count(ctx *context.Context) { count, err := nuget_model.CountPackages(ctx, &packages_model.PackageSearchOptions{ - OwnerID: ctx.Package.Owner.ID, - Name: packages_model.SearchValue{ - Value: getSearchTerm(ctx), - }, + OwnerID: ctx.Package.Owner.ID, + Name: getSearchTerm(ctx), IsInternal: optional.Some(false), }) if err != nil { diff --git a/tests/integration/api_packages_nuget_test.go b/tests/integration/api_packages_nuget_test.go index 83947ff9671ec..630b4de3f92b6 100644 --- a/tests/integration/api_packages_nuget_test.go +++ b/tests/integration/api_packages_nuget_test.go @@ -429,22 +429,33 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`) t.Run("SearchService", func(t *testing.T) { cases := []struct { - Query string - Skip int - Take int - ExpectedTotal int64 - ExpectedResults int + Query string + Skip int + Take int + ExpectedTotal int64 + ExpectedResults int + ExpectedExactMatch bool }{ - {"", 0, 0, 1, 1}, - {"", 0, 10, 1, 1}, - {"gitea", 0, 10, 0, 0}, - {"test", 0, 10, 1, 1}, - {"test", 1, 10, 1, 0}, + {"", 0, 0, 4, 4, false}, + {"", 0, 10, 4, 4, false}, + {"gitea", 0, 10, 0, 0, false}, + {"test", 0, 10, 1, 1, false}, + {"test", 1, 10, 1, 0, false}, + {"almost.similar", 0, 0, 3, 3, true}, } - req := NewRequestWithBody(t, "PUT", url, createPackage(packageName, "1.0.99")). - AddBasicAuth(user.Name) - MakeRequest(t, req, http.StatusCreated) + fakePackages := []string{ + packageName, + "almost.similar.dependency", + "almost.similar", + "almost.similar.dependant", + } + + for _, fakePackageName := range fakePackages { + req := NewRequestWithBody(t, "PUT", url, createPackage(fakePackageName, "1.0.99")). + AddBasicAuth(user.Name) + MakeRequest(t, req, http.StatusCreated) + } t.Run("v2", func(t *testing.T) { t.Run("Search()", func(t *testing.T) { @@ -491,6 +502,63 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`) } }) + t.Run("Packages()", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + + t.Run("substringof", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + + for i, c := range cases { + req := NewRequest(t, "GET", fmt.Sprintf("%s/Packages()?$filter=substringof('%s',tolower(Id))&$skip=%d&$top=%d", url, c.Query, c.Skip, c.Take)). + AddBasicAuth(user.Name) + resp := MakeRequest(t, req, http.StatusOK) + + var result FeedResponse + decodeXML(t, resp, &result) + + assert.Equal(t, c.ExpectedTotal, result.Count, "case %d: unexpected total hits", i) + assert.Len(t, result.Entries, c.ExpectedResults, "case %d: unexpected result count", i) + + req = NewRequest(t, "GET", fmt.Sprintf("%s/Packages()/$count?$filter=substringof('%s',tolower(Id))&$skip=%d&$top=%d", url, c.Query, c.Skip, c.Take)). + AddBasicAuth(user.Name) + resp = MakeRequest(t, req, http.StatusOK) + + assert.Equal(t, strconv.FormatInt(c.ExpectedTotal, 10), resp.Body.String(), "case %d: unexpected total hits", i) + } + }) + + t.Run("IdEq", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + + for i, c := range cases { + if c.Query == "" { + // Ignore the `tolower(Id) eq ''` as it's unlikely to happen + continue + } + req := NewRequest(t, "GET", fmt.Sprintf("%s/Packages()?$filter=(tolower(Id) eq '%s')&$skip=%d&$top=%d", url, c.Query, c.Skip, c.Take)). + AddBasicAuth(user.Name) + resp := MakeRequest(t, req, http.StatusOK) + + var result FeedResponse + decodeXML(t, resp, &result) + + expectedCount := 0 + if c.ExpectedExactMatch { + expectedCount = 1 + } + + assert.Equal(t, int64(expectedCount), result.Count, "case %d: unexpected total hits", i) + assert.Len(t, result.Entries, expectedCount, "case %d: unexpected result count", i) + + req = NewRequest(t, "GET", fmt.Sprintf("%s/Packages()/$count?$filter=(tolower(Id) eq '%s')&$skip=%d&$top=%d", url, c.Query, c.Skip, c.Take)). + AddBasicAuth(user.Name) + resp = MakeRequest(t, req, http.StatusOK) + + assert.Equal(t, strconv.FormatInt(int64(expectedCount), 10), resp.Body.String(), "case %d: unexpected total hits", i) + } + }) + }) + t.Run("Next", func(t *testing.T) { req := NewRequest(t, "GET", fmt.Sprintf("%s/Search()?searchTerm='test'&$skip=0&$top=1", url)). AddBasicAuth(user.Name) @@ -548,9 +616,11 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`) }) }) - req = NewRequest(t, "DELETE", fmt.Sprintf("%s/%s/%s", url, packageName, "1.0.99")). - AddBasicAuth(user.Name) - MakeRequest(t, req, http.StatusNoContent) + for _, fakePackageName := range fakePackages { + req := NewRequest(t, "DELETE", fmt.Sprintf("%s/%s/%s", url, fakePackageName, "1.0.99")). + AddBasicAuth(user.Name) + MakeRequest(t, req, http.StatusNoContent) + } }) t.Run("RegistrationService", func(t *testing.T) { From 1f8ac27b31b52791396f198b665a1d6bbdcfd8b3 Mon Sep 17 00:00:00 2001 From: silverwind Date: Tue, 4 Jun 2024 09:14:24 +0200 Subject: [PATCH 06/12] Fix overflow on push notification (#31179) Fixes: https://github.com/go-gitea/gitea/issues/30063 Screenshot 2024-05-30 at 14 43 24 --- templates/repo/code/recently_pushed_new_branches.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/repo/code/recently_pushed_new_branches.tmpl b/templates/repo/code/recently_pushed_new_branches.tmpl index 7f613fcba7eae..025cc1a403d8e 100644 --- a/templates/repo/code/recently_pushed_new_branches.tmpl +++ b/templates/repo/code/recently_pushed_new_branches.tmpl @@ -1,6 +1,6 @@ {{range .RecentlyPushedNewBranches}} -
-
+
+
{{$timeSince := TimeSince .CommitTime.AsTime ctx.Locale}} {{$branchLink := HTMLFormat `%s` .BranchLink .BranchDisplayName}} {{ctx.Locale.Tr "repo.pulls.recently_pushed_new_branches" $branchLink $timeSince}} From 4ca65fabdad75e39f9948b9a2a18e32edc98ec02 Mon Sep 17 00:00:00 2001 From: silverwind Date: Tue, 4 Jun 2024 09:46:05 +0200 Subject: [PATCH 07/12] Remove .segment from .project-column (#31204) Using `.segment` on the project columns is a major abuse of that class, so remove it and instead set the border-radius directly on it. Fixes: https://github.com/go-gitea/gitea/issues/31129 --- templates/projects/view.tmpl | 2 +- web_src/css/features/projects.css | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/templates/projects/view.tmpl b/templates/projects/view.tmpl index 45c8461218877..6d331caba7ebf 100644 --- a/templates/projects/view.tmpl +++ b/templates/projects/view.tmpl @@ -66,7 +66,7 @@
{{range .Columns}} -
+
{{.NumIssues ctx}} diff --git a/web_src/css/features/projects.css b/web_src/css/features/projects.css index e25182051a291..151b0a23d9dc7 100644 --- a/web_src/css/features/projects.css +++ b/web_src/css/features/projects.css @@ -9,6 +9,7 @@ .project-column { background-color: var(--color-project-column-bg) !important; border: 1px solid var(--color-secondary) !important; + border-radius: var(--border-radius); margin: 0 0.5rem !important; padding: 0.5rem !important; width: 320px; From 90008111181b874ac018455d8d7a2f8bfe6bc71e Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Tue, 4 Jun 2024 20:19:41 +0800 Subject: [PATCH 08/12] Make pasted "img" tag has the same behavior as markdown image (#31235) Fix #31230 --------- Co-authored-by: Lunny Xiao --- modules/markup/html.go | 60 ++++++++++++++++++++-------- modules/markup/html_internal_test.go | 19 +++++---- modules/markup/html_test.go | 51 ++++++++++------------- modules/markup/renderer.go | 2 +- web_src/js/features/comp/Paste.js | 6 ++- 5 files changed, 79 insertions(+), 59 deletions(-) diff --git a/modules/markup/html.go b/modules/markup/html.go index 0af74d2680621..8dbc9582990b6 100644 --- a/modules/markup/html.go +++ b/modules/markup/html.go @@ -372,7 +372,42 @@ func postProcess(ctx *RenderContext, procs []processor, input io.Reader, output return nil } -func visitNode(ctx *RenderContext, procs []processor, node *html.Node) { +func handleNodeImg(ctx *RenderContext, img *html.Node) { + for i, attr := range img.Attr { + if attr.Key != "src" { + continue + } + + if attr.Val != "" && !IsFullURLString(attr.Val) && !strings.HasPrefix(attr.Val, "/") { + attr.Val = util.URLJoin(ctx.Links.ResolveMediaLink(ctx.IsWiki), attr.Val) + + // By default, the "" tag should also be clickable, + // because frontend use `` to paste the re-scaled image into the markdown, + // so it must match the default markdown image behavior. + hasParentAnchor := false + for p := img.Parent; p != nil; p = p.Parent { + if hasParentAnchor = p.Type == html.ElementNode && p.Data == "a"; hasParentAnchor { + break + } + } + if !hasParentAnchor { + imgA := &html.Node{Type: html.ElementNode, Data: "a", Attr: []html.Attribute{ + {Key: "href", Val: attr.Val}, + {Key: "target", Val: "_blank"}, + }} + parent := img.Parent + imgNext := img.NextSibling + parent.RemoveChild(img) + parent.InsertBefore(imgA, imgNext) + imgA.AppendChild(img) + } + } + attr.Val = camoHandleLink(attr.Val) + img.Attr[i] = attr + } +} + +func visitNode(ctx *RenderContext, procs []processor, node *html.Node) *html.Node { // Add user-content- to IDs and "#" links if they don't already have them for idx, attr := range node.Attr { val := strings.TrimPrefix(attr.Val, "#") @@ -397,21 +432,14 @@ func visitNode(ctx *RenderContext, procs []processor, node *html.Node) { textNode(ctx, procs, node) case html.ElementNode: if node.Data == "img" { - for i, attr := range node.Attr { - if attr.Key != "src" { - continue - } - if len(attr.Val) > 0 && !IsFullURLString(attr.Val) && !strings.HasPrefix(attr.Val, "data:image/") { - attr.Val = util.URLJoin(ctx.Links.ResolveMediaLink(ctx.IsWiki), attr.Val) - } - attr.Val = camoHandleLink(attr.Val) - node.Attr[i] = attr - } + next := node.NextSibling + handleNodeImg(ctx, node) + return next } else if node.Data == "a" { // Restrict text in links to emojis procs = emojiProcessors } else if node.Data == "code" || node.Data == "pre" { - return + return node.NextSibling } else if node.Data == "i" { for _, attr := range node.Attr { if attr.Key != "class" { @@ -434,11 +462,11 @@ func visitNode(ctx *RenderContext, procs []processor, node *html.Node) { } } } - for n := node.FirstChild; n != nil; n = n.NextSibling { - visitNode(ctx, procs, n) + for n := node.FirstChild; n != nil; { + n = visitNode(ctx, procs, n) } } - // ignore everything else + return node.NextSibling } // textNode runs the passed node through various processors, in order to handle @@ -851,7 +879,7 @@ func issueIndexPatternProcessor(ctx *RenderContext, node *html.Node) { // FIXME: the use of "mode" is quite dirty and hacky, for example: what is a "document"? how should it be rendered? // The "mode" approach should be refactored to some other more clear&reliable way. - crossLinkOnly := (ctx.Metas["mode"] == "document" && !ctx.IsWiki) + crossLinkOnly := ctx.Metas["mode"] == "document" && !ctx.IsWiki var ( found bool diff --git a/modules/markup/html_internal_test.go b/modules/markup/html_internal_test.go index 3ff0597851bba..9aa9c22d701f4 100644 --- a/modules/markup/html_internal_test.go +++ b/modules/markup/html_internal_test.go @@ -18,8 +18,7 @@ import ( const ( TestAppURL = "http://localhost:3000/" - TestOrgRepo = "gogits/gogs" - TestRepoURL = TestAppURL + TestOrgRepo + "/" + TestRepoURL = TestAppURL + "test-owner/test-repo/" ) // externalIssueLink an HTML link to an alphanumeric-style issue @@ -64,8 +63,8 @@ var regexpMetas = map[string]string{ // these values should match the TestOrgRepo const above var localMetas = map[string]string{ - "user": "gogits", - "repo": "gogs", + "user": "test-owner", + "repo": "test-repo", } func TestRender_IssueIndexPattern(t *testing.T) { @@ -362,12 +361,12 @@ func TestRender_FullIssueURLs(t *testing.T) { `Look here person/repo#4`) test("http://localhost:3000/person/repo/issues/4#issuecomment-1234", `person/repo#4 (comment)`) - test("http://localhost:3000/gogits/gogs/issues/4", - `#4`) - test("http://localhost:3000/gogits/gogs/issues/4 test", - `#4 test`) - test("http://localhost:3000/gogits/gogs/issues/4?a=1&b=2#comment-123 test", - `#4 (comment) test`) + test("http://localhost:3000/test-owner/test-repo/issues/4", + `#4`) + test("http://localhost:3000/test-owner/test-repo/issues/4 test", + `#4 test`) + test("http://localhost:3000/test-owner/test-repo/issues/4?a=1&b=2#comment-123 test", + `#4 (comment) test`) test("http://localhost:3000/testOrg/testOrgRepo/pulls/2/files#issuecomment-24", "http://localhost:3000/testOrg/testOrgRepo/pulls/2/files#issuecomment-24") test("http://localhost:3000/testOrg/testOrgRepo/pulls/2/files", diff --git a/modules/markup/html_test.go b/modules/markup/html_test.go index e2d08692e4c3e..df3c2609ef4a3 100644 --- a/modules/markup/html_test.go +++ b/modules/markup/html_test.go @@ -120,8 +120,8 @@ func TestRender_CrossReferences(t *testing.T) { } test( - "gogits/gogs#12345", - `

gogits/gogs#12345

`) + "test-owner/test-repo#12345", + `

test-owner/test-repo#12345

`) test( "go-gitea/gitea#12345", `

go-gitea/gitea#12345

`) @@ -530,43 +530,31 @@ func TestRender_ShortLinks(t *testing.T) { } func TestRender_RelativeImages(t *testing.T) { - setting.AppURL = markup.TestAppURL - - test := func(input, expected, expectedWiki string) { + render := func(input string, isWiki bool, links markup.Links) string { buffer, err := markdown.RenderString(&markup.RenderContext{ - Ctx: git.DefaultContext, - Links: markup.Links{ - Base: markup.TestRepoURL, - BranchPath: "master", - }, - Metas: localMetas, - }, input) - assert.NoError(t, err) - assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer))) - buffer, err = markdown.RenderString(&markup.RenderContext{ - Ctx: git.DefaultContext, - Links: markup.Links{ - Base: markup.TestRepoURL, - }, + Ctx: git.DefaultContext, + Links: links, Metas: localMetas, - IsWiki: true, + IsWiki: isWiki, }, input) assert.NoError(t, err) - assert.Equal(t, strings.TrimSpace(expectedWiki), strings.TrimSpace(string(buffer))) + return strings.TrimSpace(string(buffer)) } - rawwiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw") - mediatree := util.URLJoin(markup.TestRepoURL, "media", "master") + out := render(``, false, markup.Links{Base: "/test-owner/test-repo"}) + assert.Equal(t, ``, out) - test( - ``, - ``, - ``) + out = render(``, true, markup.Links{Base: "/test-owner/test-repo"}) + assert.Equal(t, ``, out) - test( - ``, - ``, - ``) + out = render(``, false, markup.Links{Base: "/test-owner/test-repo", BranchPath: "test-branch"}) + assert.Equal(t, ``, out) + + out = render(``, true, markup.Links{Base: "/test-owner/test-repo", BranchPath: "test-branch"}) + assert.Equal(t, ``, out) + + out = render(``, true, markup.Links{Base: "/test-owner/test-repo", BranchPath: "test-branch"}) + assert.Equal(t, ``, out) } func Test_ParseClusterFuzz(t *testing.T) { @@ -719,5 +707,6 @@ func TestIssue18471(t *testing.T) { func TestIsFullURL(t *testing.T) { assert.True(t, markup.IsFullURLString("https://example.com")) assert.True(t, markup.IsFullURLString("mailto:test@example.com")) + assert.True(t, markup.IsFullURLString("data:image/11111")) assert.False(t, markup.IsFullURLString("/foo:bar")) } diff --git a/modules/markup/renderer.go b/modules/markup/renderer.go index 44dedf638bc60..66e8cf611d468 100644 --- a/modules/markup/renderer.go +++ b/modules/markup/renderer.go @@ -74,7 +74,7 @@ type RenderContext struct { Type string IsWiki bool Links Links - Metas map[string]string + Metas map[string]string // user, repo, mode(comment/document) DefaultLink string GitRepo *git.Repository Repo gitrepo.Repository diff --git a/web_src/js/features/comp/Paste.js b/web_src/js/features/comp/Paste.js index b26296d1fc967..35a7ceaef8be2 100644 --- a/web_src/js/features/comp/Paste.js +++ b/web_src/js/features/comp/Paste.js @@ -100,13 +100,17 @@ async function handleClipboardImages(editor, dropzone, images, e) { const {uuid} = await uploadFile(img, uploadUrl); const {width, dppx} = await imageInfo(img); - const url = `/attachments/${uuid}`; let text; if (width > 0 && dppx > 1) { // Scale down images from HiDPI monitors. This uses the tag because it's the only // method to change image size in Markdown that is supported by all implementations. + // Make the image link relative to the repo path, then the final URL is "/sub-path/owner/repo/attachments/{uuid}" + const url = `attachments/${uuid}`; text = `${htmlEscape(name)}`; } else { + // Markdown always renders the image with a relative path, so the final URL is "/sub-path/owner/repo/attachments/{uuid}" + // TODO: it should also use relative path for consistency, because absolute is ambiguous for "/sub-path/attachments" or "/attachments" + const url = `/attachments/${uuid}`; text = `![${name}](${url})`; } editor.replacePlaceholder(placeholder, text); From 138e946c3d8e2731f11a3e3b6876889694822f46 Mon Sep 17 00:00:00 2001 From: silverwind Date: Tue, 4 Jun 2024 15:57:11 +0200 Subject: [PATCH 09/12] Replace `gt-word-break` with `tw-break-anywhere` (#31183) `overflow-wrap: anywhere` is a superior alternative to `word-wrap: break-word` and we were already setting it in the class. I tested a few cases, all look good. --- docs/content/contributing/guidelines-frontend.en-us.md | 2 +- docs/content/contributing/guidelines-frontend.zh-cn.md | 2 +- templates/admin/repo/list.tmpl | 4 ++-- templates/package/content/container.tmpl | 4 ++-- templates/package/settings.tmpl | 2 +- templates/projects/view.tmpl | 2 +- templates/repo/home.tmpl | 2 +- templates/repo/issue/list.tmpl | 2 +- templates/repo/issue/view_content/conversation.tmpl | 2 +- templates/repo/release/list.tmpl | 2 +- templates/repo/settings/options.tmpl | 2 +- templates/repo/wiki/revision.tmpl | 2 +- templates/shared/user/org_profile_avatar.tmpl | 2 +- templates/shared/user/profile_big_avatar.tmpl | 4 ++-- web_src/css/helpers.css | 5 ----- web_src/js/features/repo-issue.js | 2 +- 16 files changed, 18 insertions(+), 23 deletions(-) diff --git a/docs/content/contributing/guidelines-frontend.en-us.md b/docs/content/contributing/guidelines-frontend.en-us.md index efeaf38bb2bb2..a08098a93152b 100644 --- a/docs/content/contributing/guidelines-frontend.en-us.md +++ b/docs/content/contributing/guidelines-frontend.en-us.md @@ -47,7 +47,7 @@ We recommend [Google HTML/CSS Style Guide](https://google.github.io/styleguide/h 9. Avoid unnecessary `!important` in CSS, add comments to explain why it's necessary if it can't be avoided. 10. Avoid mixing different events in one event listener, prefer to use individual event listeners for every event. 11. Custom event names are recommended to use `ce-` prefix. -12. Prefer using Tailwind CSS which is available via `tw-` prefix, e.g. `tw-relative`. Gitea's helper CSS classes use `gt-` prefix (`gt-word-break`), while Gitea's own private framework-level CSS classes use `g-` prefix (`g-modal-confirm`). +12. Prefer using Tailwind CSS which is available via `tw-` prefix, e.g. `tw-relative`. Gitea's helper CSS classes use `gt-` prefix (`gt-ellipsis`), while Gitea's own private framework-level CSS classes use `g-` prefix (`g-modal-confirm`). 13. Avoid inline scripts & styles as much as possible, it's recommended to put JS code into JS files and use CSS classes. If inline scripts & styles are unavoidable, explain the reason why it can't be avoided. ### Accessibility / ARIA diff --git a/docs/content/contributing/guidelines-frontend.zh-cn.md b/docs/content/contributing/guidelines-frontend.zh-cn.md index 394097b259fda..198e1227e539e 100644 --- a/docs/content/contributing/guidelines-frontend.zh-cn.md +++ b/docs/content/contributing/guidelines-frontend.zh-cn.md @@ -47,7 +47,7 @@ HTML 页面由[Go HTML Template](https://pkg.go.dev/html/template)渲染。 9. 避免在 CSS 中使用不必要的`!important`,如果无法避免,添加注释解释为什么需要它。 10. 避免在一个事件监听器中混合不同的事件,优先为每个事件使用独立的事件监听器。 11. 推荐使用自定义事件名称前缀`ce-`。 -12. 建议使用 Tailwind CSS,它可以通过 `tw-` 前缀获得,例如 `tw-relative`. Gitea 自身的助手类 CSS 使用 `gt-` 前缀(`gt-word-break`),Gitea 自身的私有框架级 CSS 类使用 `g-` 前缀(`g-modal-confirm`)。 +12. 建议使用 Tailwind CSS,它可以通过 `tw-` 前缀获得,例如 `tw-relative`. Gitea 自身的助手类 CSS 使用 `gt-` 前缀(`gt-ellipsis`),Gitea 自身的私有框架级 CSS 类使用 `g-` 前缀(`g-modal-confirm`)。 13. 尽量避免内联脚本和样式,建议将JS代码放入JS文件中并使用CSS类。如果内联脚本和样式不可避免,请解释无法避免的原因。 ### 可访问性 / ARIA diff --git a/templates/admin/repo/list.tmpl b/templates/admin/repo/list.tmpl index 4b27d87a4552f..69031e42ebe76 100644 --- a/templates/admin/repo/list.tmpl +++ b/templates/admin/repo/list.tmpl @@ -47,13 +47,13 @@ {{.ID}} - {{.Owner.Name}} + {{.Owner.Name}} {{if .Owner.Visibility.IsPrivate}} {{svg "octicon-lock"}} {{end}} - {{.Name}} + {{.Name}} {{if .IsArchived}} {{ctx.Locale.Tr "repo.desc.archived"}} {{end}} diff --git a/templates/package/content/container.tmpl b/templates/package/content/container.tmpl index fe393f4388968..138fedecb3fc3 100644 --- a/templates/package/content/container.tmpl +++ b/templates/package/content/container.tmpl @@ -54,7 +54,7 @@ {{end}} {{if .PackageDescriptor.Metadata.ImageLayers}}

{{ctx.Locale.Tr "packages.container.layers"}}

-
+
{{range .PackageDescriptor.Metadata.ImageLayers}} @@ -80,7 +80,7 @@ {{range $key, $value := .PackageDescriptor.Metadata.Labels}} - + {{end}} diff --git a/templates/package/settings.tmpl b/templates/package/settings.tmpl index 9424baf4939ef..4b8773477b4af 100644 --- a/templates/package/settings.tmpl +++ b/templates/package/settings.tmpl @@ -59,7 +59,7 @@ {{ctx.Locale.Tr "packages.settings.delete"}}
-
+
{{ctx.Locale.Tr "packages.settings.delete.notice" .PackageDescriptor.Package.Name .PackageDescriptor.Version.Version}}
diff --git a/templates/projects/view.tmpl b/templates/projects/view.tmpl index 6d331caba7ebf..584462d2a24dd 100644 --- a/templates/projects/view.tmpl +++ b/templates/projects/view.tmpl @@ -152,7 +152,7 @@
{{range (index $.IssuesMap .ID)}} -
+
{{template "repo/issue/card" (dict "Issue" . "Page" $)}}
{{end}} diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl index ef76f3ed5d46b..ff82f2ca80360 100644 --- a/templates/repo/home.tmpl +++ b/templates/repo/home.tmpl @@ -5,7 +5,7 @@ {{template "base/alert" .}} {{template "repo/code/recently_pushed_new_branches" .}} {{if and (not .HideRepoInfo) (not .IsBlame)}} -
+
{{- $description := .Repository.DescriptionHTML ctx -}} {{if $description}}{{$description | RenderCodeBlock}}{{end}} {{if .Repository.Website}}{{.Repository.Website}}{{end}} diff --git a/templates/repo/issue/list.tmpl b/templates/repo/issue/list.tmpl index 30edf825f1224..01b610b39db0b 100644 --- a/templates/repo/issue/list.tmpl +++ b/templates/repo/issue/list.tmpl @@ -7,7 +7,7 @@ {{if .PinnedIssues}}
{{range .PinnedIssues}} -
+
{{template "repo/issue/card" (dict "Issue" . "Page" $ "isPinnedIssueCard" true)}}
{{end}} diff --git a/templates/repo/issue/view_content/conversation.tmpl b/templates/repo/issue/view_content/conversation.tmpl index 43ec9d75c4176..ccea9b690d7e8 100644 --- a/templates/repo/issue/view_content/conversation.tmpl +++ b/templates/repo/issue/view_content/conversation.tmpl @@ -8,7 +8,7 @@
- {{$comment.TreePath}} + {{$comment.TreePath}} {{if $invalid}} {{ctx.Locale.Tr "repo.issues.review.outdated"}} diff --git a/templates/repo/release/list.tmpl b/templates/repo/release/list.tmpl index 34548672b5dff..e5bf23faacf12 100644 --- a/templates/repo/release/list.tmpl +++ b/templates/repo/release/list.tmpl @@ -17,7 +17,7 @@
-

+

{{if $.PageIsSingleTag}}{{$release.Title}}{{else}}{{$release.Title}}{{end}} {{template "repo/commit_statuses" dict "Status" $info.CommitStatus "Statuses" $info.CommitStatuses "AdditionalClasses" "tw-flex"}} {{if $release.IsDraft}} diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl index 6c49f00094622..4f98133df3679 100644 --- a/templates/repo/settings/options.tmpl +++ b/templates/repo/settings/options.tmpl @@ -217,7 +217,7 @@

{{range .PushMirrors}} - +
{{$key}}{{$value}}{{$value}}
{{.RemoteAddress}}{{.RemoteAddress}} {{ctx.Locale.Tr "repo.settings.mirror_settings.direction.push"}} {{if .LastUpdateUnix}}{{DateTime "full" .LastUpdateUnix}}{{else}}{{ctx.Locale.Tr "never"}}{{end}} {{if .LastError}}
{{ctx.Locale.Tr "error"}}
{{end}}
diff --git a/templates/repo/wiki/revision.tmpl b/templates/repo/wiki/revision.tmpl index 8e0060d4b3adb..7fca703843293 100644 --- a/templates/repo/wiki/revision.tmpl +++ b/templates/repo/wiki/revision.tmpl @@ -8,7 +8,7 @@
{{.revision}} {{svg "octicon-home"}} {{$title}} -
+
{{$timeSince := TimeSince .Author.When ctx.Locale}} {{ctx.Locale.Tr "repo.wiki.last_commit_info" .Author.Name $timeSince}}
diff --git a/templates/shared/user/org_profile_avatar.tmpl b/templates/shared/user/org_profile_avatar.tmpl index d67f133abf62c..c0abcabff1b9d 100644 --- a/templates/shared/user/org_profile_avatar.tmpl +++ b/templates/shared/user/org_profile_avatar.tmpl @@ -2,7 +2,7 @@
-
+
{{ctx.AvatarUtils.Avatar . 100}} {{.DisplayName}} diff --git a/templates/shared/user/profile_big_avatar.tmpl b/templates/shared/user/profile_big_avatar.tmpl index 868f8d5a1305f..29c6eb0eb0bd8 100644 --- a/templates/shared/user/profile_big_avatar.tmpl +++ b/templates/shared/user/profile_big_avatar.tmpl @@ -11,7 +11,7 @@ {{end}}
-
+
{{if .ContextUser.FullName}}{{.ContextUser.FullName}}{{end}} {{.ContextUser.Name}} {{if .IsAdmin}} @@ -25,7 +25,7 @@ {{end}}
-
+
    {{if .UserBlocking}}
  • {{svg "octicon-circle-slash"}} {{ctx.Locale.Tr "user.block.blocked"}}
  • diff --git a/web_src/css/helpers.css b/web_src/css/helpers.css index 15df9f3a4532e..42d06e2e66a7d 100644 --- a/web_src/css/helpers.css +++ b/web_src/css/helpers.css @@ -3,11 +3,6 @@ Gitea's tailwind-style CSS helper classes have `gt-` prefix. Gitea's private styles use `g-` prefix. */ -.gt-word-break { - word-wrap: break-word !important; - overflow-wrap: anywhere; -} - .gt-ellipsis { overflow: hidden !important; white-space: nowrap !important; diff --git a/web_src/js/features/repo-issue.js b/web_src/js/features/repo-issue.js index 519db34934b65..95910e34bc9af 100644 --- a/web_src/js/features/repo-issue.js +++ b/web_src/js/features/repo-issue.js @@ -125,7 +125,7 @@ export function initRepoIssueSidebarList() { } filteredResponse.results.push({ name: `
    #${issue.number} ${htmlEscape(issue.title)}
    -
    ${htmlEscape(issue.repository.full_name)}
    `, +
    ${htmlEscape(issue.repository.full_name)}
    `, value: issue.id, }); }); From fcc061ae4435f251d14a6750a0f5713800dca637 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Tue, 4 Jun 2024 23:06:21 +0800 Subject: [PATCH 10/12] Fix admin oauth2 custom URL settings (#31246) Fix #31244 --- web_src/js/features/admin/common.js | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/web_src/js/features/admin/common.js b/web_src/js/features/admin/common.js index b35502d52f9fa..3c90b546b86b9 100644 --- a/web_src/js/features/admin/common.js +++ b/web_src/js/features/admin/common.js @@ -67,39 +67,44 @@ export function initAdminCommon() { input.removeAttribute('required'); } - const provider = document.getElementById('oauth2_provider')?.value; + const provider = document.getElementById('oauth2_provider').value; switch (provider) { case 'openidConnect': - for (const input of document.querySelectorAll('.open_id_connect_auto_discovery_url input')) { - input.setAttribute('required', 'required'); - } + document.querySelector('.open_id_connect_auto_discovery_url input').setAttribute('required', 'required'); showElem('.open_id_connect_auto_discovery_url'); break; - default: - if (document.getElementById(`#${provider}_customURLSettings`)?.getAttribute('data-required')) { - document.getElementById('oauth2_use_custom_url')?.setAttribute('checked', 'checked'); + default: { + const elProviderCustomUrlSettings = document.querySelector(`#${provider}_customURLSettings`); + if (!elProviderCustomUrlSettings) break; // some providers do not have custom URL settings + const couldChangeCustomURLs = elProviderCustomUrlSettings.getAttribute('data-available') === 'true'; + const mustProvideCustomURLs = elProviderCustomUrlSettings.getAttribute('data-required') === 'true'; + if (couldChangeCustomURLs) { + showElem('.oauth2_use_custom_url'); // show the checkbox } - if (document.getElementById(`#${provider}_customURLSettings`)?.getAttribute('data-available')) { - showElem('.oauth2_use_custom_url'); + if (mustProvideCustomURLs) { + document.querySelector('#oauth2_use_custom_url').checked = true; // make the checkbox checked } + break; + } } onOAuth2UseCustomURLChange(applyDefaultValues); } function onOAuth2UseCustomURLChange(applyDefaultValues) { - const provider = document.getElementById('oauth2_provider')?.value; + const provider = document.getElementById('oauth2_provider').value; hideElem('.oauth2_use_custom_url_field'); for (const input of document.querySelectorAll('.oauth2_use_custom_url_field input[required]')) { input.removeAttribute('required'); } - if (document.getElementById('oauth2_use_custom_url')?.checked) { + const elProviderCustomUrlSettings = document.querySelector(`#${provider}_customURLSettings`); + if (elProviderCustomUrlSettings && document.getElementById('oauth2_use_custom_url').checked) { for (const custom of ['token_url', 'auth_url', 'profile_url', 'email_url', 'tenant']) { if (applyDefaultValues) { document.getElementById(`oauth2_${custom}`).value = document.getElementById(`${provider}_${custom}`).value; } const customInput = document.getElementById(`${provider}_${custom}`); - if (customInput && customInput.getAttribute('data-available')) { + if (customInput && customInput.getAttribute('data-available') === 'true') { for (const input of document.querySelectorAll(`.oauth2_${custom} input`)) { input.setAttribute('required', 'required'); } From bd80225ec3688cfa89767cc352835d8d5093f764 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Tue, 4 Jun 2024 23:35:29 +0800 Subject: [PATCH 11/12] Make blockquote attention recognize more syntaxes (#31240) Fix #31214 --- modules/markup/markdown/markdown_test.go | 6 ++ modules/markup/markdown/math/block_parser.go | 10 ++- .../markup/markdown/transform_blockquote.go | 89 +++++++++++++++---- 3 files changed, 86 insertions(+), 19 deletions(-) diff --git a/modules/markup/markdown/markdown_test.go b/modules/markup/markdown/markdown_test.go index b4a7efa8dd876..8c41ec12e3fb1 100644 --- a/modules/markup/markdown/markdown_test.go +++ b/modules/markup/markdown/markdown_test.go @@ -1019,4 +1019,10 @@ func TestAttention(t *testing.T) { test(`> [!important]`, renderAttention("important", "octicon-report")+"\n") test(`> [!warning]`, renderAttention("warning", "octicon-alert")+"\n") test(`> [!caution]`, renderAttention("caution", "octicon-stop")+"\n") + + // escaped by mdformat + test(`> \[!NOTE\]`, renderAttention("note", "octicon-info")+"\n") + + // legacy GitHub style + test(`> **warning**`, renderAttention("warning", "octicon-alert")+"\n") } diff --git a/modules/markup/markdown/math/block_parser.go b/modules/markup/markdown/math/block_parser.go index 7f714d7239292..37f6caf11ce2c 100644 --- a/modules/markup/markdown/math/block_parser.go +++ b/modules/markup/markdown/math/block_parser.go @@ -31,10 +31,16 @@ func (b *blockParser) Open(parent ast.Node, reader text.Reader, pc parser.Contex return nil, parser.NoChildren } - dollars := false + var dollars bool if b.parseDollars && line[pos] == '$' && line[pos+1] == '$' { dollars = true - } else if line[pos] != '\\' || line[pos+1] != '[' { + } else if line[pos] == '\\' && line[pos+1] == '[' { + if len(line[pos:]) >= 3 && line[pos+2] == '!' && bytes.Contains(line[pos:], []byte(`\]`)) { + // do not process escaped attention block: "> \[!NOTE\]" + return nil, parser.NoChildren + } + dollars = false + } else { return nil, parser.NoChildren } diff --git a/modules/markup/markdown/transform_blockquote.go b/modules/markup/markdown/transform_blockquote.go index 933f0e5c59384..d2dc025052d00 100644 --- a/modules/markup/markdown/transform_blockquote.go +++ b/modules/markup/markdown/transform_blockquote.go @@ -15,7 +15,7 @@ import ( "golang.org/x/text/language" ) -// renderAttention renders a quote marked with i.e. "> **Note**" or "> **Warning**" with a corresponding svg +// renderAttention renders a quote marked with i.e. "> **Note**" or "> [!Warning]" with a corresponding svg func (r *HTMLRenderer) renderAttention(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { if entering { n := node.(*Attention) @@ -37,38 +37,93 @@ func (r *HTMLRenderer) renderAttention(w util.BufWriter, source []byte, node ast return ast.WalkContinue, nil } -func (g *ASTTransformer) transformBlockquote(v *ast.Blockquote, reader text.Reader) (ast.WalkStatus, error) { - // We only want attention blockquotes when the AST looks like: - // > Text("[") Text("!TYPE") Text("]") +func (g *ASTTransformer) extractBlockquoteAttentionEmphasis(firstParagraph ast.Node, reader text.Reader) (string, []ast.Node) { + if firstParagraph.ChildCount() < 1 { + return "", nil + } + node1, ok := firstParagraph.FirstChild().(*ast.Emphasis) + if !ok { + return "", nil + } + val1 := string(node1.Text(reader.Source())) + attentionType := strings.ToLower(val1) + if g.attentionTypes.Contains(attentionType) { + return attentionType, []ast.Node{node1} + } + return "", nil +} - // grab these nodes and make sure we adhere to the attention blockquote structure - firstParagraph := v.FirstChild() - g.applyElementDir(firstParagraph) +func (g *ASTTransformer) extractBlockquoteAttention2(firstParagraph ast.Node, reader text.Reader) (string, []ast.Node) { + if firstParagraph.ChildCount() < 2 { + return "", nil + } + node1, ok := firstParagraph.FirstChild().(*ast.Text) + if !ok { + return "", nil + } + node2, ok := node1.NextSibling().(*ast.Text) + if !ok { + return "", nil + } + val1 := string(node1.Segment.Value(reader.Source())) + val2 := string(node2.Segment.Value(reader.Source())) + if strings.HasPrefix(val1, `\[!`) && val2 == `\]` { + attentionType := strings.ToLower(val1[3:]) + if g.attentionTypes.Contains(attentionType) { + return attentionType, []ast.Node{node1, node2} + } + } + return "", nil +} + +func (g *ASTTransformer) extractBlockquoteAttention3(firstParagraph ast.Node, reader text.Reader) (string, []ast.Node) { if firstParagraph.ChildCount() < 3 { - return ast.WalkContinue, nil + return "", nil } node1, ok := firstParagraph.FirstChild().(*ast.Text) if !ok { - return ast.WalkContinue, nil + return "", nil } node2, ok := node1.NextSibling().(*ast.Text) if !ok { - return ast.WalkContinue, nil + return "", nil } node3, ok := node2.NextSibling().(*ast.Text) if !ok { - return ast.WalkContinue, nil + return "", nil } val1 := string(node1.Segment.Value(reader.Source())) val2 := string(node2.Segment.Value(reader.Source())) val3 := string(node3.Segment.Value(reader.Source())) if val1 != "[" || val3 != "]" || !strings.HasPrefix(val2, "!") { - return ast.WalkContinue, nil + return "", nil } - // grab attention type from markdown source attentionType := strings.ToLower(val2[1:]) - if !g.attentionTypes.Contains(attentionType) { + if g.attentionTypes.Contains(attentionType) { + return attentionType, []ast.Node{node1, node2, node3} + } + return "", nil +} + +func (g *ASTTransformer) transformBlockquote(v *ast.Blockquote, reader text.Reader) (ast.WalkStatus, error) { + // We only want attention blockquotes when the AST looks like: + // > Text("[") Text("!TYPE") Text("]") + // > Text("\[!TYPE") TEXT("\]") + // > Text("**TYPE**") + + // grab these nodes and make sure we adhere to the attention blockquote structure + firstParagraph := v.FirstChild() + g.applyElementDir(firstParagraph) + + attentionType, processedNodes := g.extractBlockquoteAttentionEmphasis(firstParagraph, reader) + if attentionType == "" { + attentionType, processedNodes = g.extractBlockquoteAttention2(firstParagraph, reader) + } + if attentionType == "" { + attentionType, processedNodes = g.extractBlockquoteAttention3(firstParagraph, reader) + } + if attentionType == "" { return ast.WalkContinue, nil } @@ -88,9 +143,9 @@ func (g *ASTTransformer) transformBlockquote(v *ast.Blockquote, reader text.Read attentionParagraph.AppendChild(attentionParagraph, NewAttention(attentionType)) attentionParagraph.AppendChild(attentionParagraph, emphasis) firstParagraph.Parent().InsertBefore(firstParagraph.Parent(), firstParagraph, attentionParagraph) - firstParagraph.RemoveChild(firstParagraph, node1) - firstParagraph.RemoveChild(firstParagraph, node2) - firstParagraph.RemoveChild(firstParagraph, node3) + for _, processed := range processedNodes { + firstParagraph.RemoveChild(firstParagraph, processed) + } if firstParagraph.ChildCount() == 0 { firstParagraph.Parent().RemoveChild(firstParagraph.Parent(), firstParagraph) } From 816222243af523316041692622be6f48ef068693 Mon Sep 17 00:00:00 2001 From: silverwind Date: Wed, 5 Jun 2024 03:22:38 +0200 Subject: [PATCH 12/12] Add `lint-go-gopls` (#30729) Uses `gopls check ` as a linter. Tested locally and brings up 149 errors currently for me. I don't think I want to fix them in this PR, but I would like at least to get this analysis running on CI. List of errors: ``` modules/indexer/code/indexer.go:181:11: impossible condition: nil != nil routers/private/hook_post_receive.go:120:15: tautological condition: nil == nil services/auth/source/oauth2/providers.go:185:9: tautological condition: nil == nil services/convert/issue.go:216:11: tautological condition: non-nil != nil tests/integration/git_test.go:332:9: impossible condition: nil != nil services/migrations/migrate.go:179:24-43: unused parameter: ctx services/repository/transfer.go:288:48-69: unused parameter: doer tests/integration/api_repo_tags_test.go:75:41-61: unused parameter: session tests/integration/git_test.go:696:64-74: unused parameter: baseBranch tests/integration/gpg_git_test.go:265:27-39: unused parameter: t tests/integration/gpg_git_test.go:284:23-29: unused parameter: tmpDir tests/integration/gpg_git_test.go:284:31-35: unused parameter: name tests/integration/gpg_git_test.go:284:37-42: unused parameter: email ``` --- Makefile | 10 +++++++++- services/migrations/migrate.go | 2 +- services/repository/transfer.go | 4 ++-- tests/integration/api_repo_tags_test.go | 4 ++-- tests/integration/dump_restore_test.go | 2 +- tests/integration/gpg_git_test.go | 6 +++--- tools/lint-go-gopls.sh | 23 +++++++++++++++++++++++ 7 files changed, 41 insertions(+), 10 deletions(-) create mode 100755 tools/lint-go-gopls.sh diff --git a/Makefile b/Makefile index e9dc945206094..d97360c9f49ec 100644 --- a/Makefile +++ b/Makefile @@ -36,6 +36,7 @@ XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1 GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1 ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1 +GOPLS_PACKAGE ?= golang.org/x/tools/gopls@v0.15.3 DOCKER_IMAGE ?= gitea/gitea DOCKER_TAG ?= latest @@ -213,6 +214,7 @@ help: @echo " - lint-go lint go files" @echo " - lint-go-fix lint go files and fix issues" @echo " - lint-go-vet lint go files with vet" + @echo " - lint-go-gopls lint go files with gopls" @echo " - lint-js lint js files" @echo " - lint-js-fix lint js files and fix issues" @echo " - lint-css lint css files" @@ -366,7 +368,7 @@ lint-frontend: lint-js lint-css lint-frontend-fix: lint-js-fix lint-css-fix .PHONY: lint-backend -lint-backend: lint-go lint-go-vet lint-editorconfig +lint-backend: lint-go lint-go-vet lint-go-gopls lint-editorconfig .PHONY: lint-backend-fix lint-backend-fix: lint-go-fix lint-go-vet lint-editorconfig @@ -424,6 +426,11 @@ lint-go-vet: @GOOS= GOARCH= $(GO) build code.gitea.io/gitea-vet @$(GO) vet -vettool=gitea-vet ./... +.PHONY: lint-go-gopls +lint-go-gopls: + @echo "Running gopls check..." + @GO=$(GO) GOPLS_PACKAGE=$(GOPLS_PACKAGE) tools/lint-go-gopls.sh $(GO_SOURCES_NO_BINDATA) + .PHONY: lint-editorconfig lint-editorconfig: @$(GO) run $(EDITORCONFIG_CHECKER_PACKAGE) $(EDITORCONFIG_FILES) @@ -864,6 +871,7 @@ deps-tools: $(GO) install $(GO_LICENSES_PACKAGE) $(GO) install $(GOVULNCHECK_PACKAGE) $(GO) install $(ACTIONLINT_PACKAGE) + $(GO) install $(GOPLS_PACKAGE) node_modules: package-lock.json npm install --no-save diff --git a/services/migrations/migrate.go b/services/migrations/migrate.go index 5bb3056161290..21bdc68e73208 100644 --- a/services/migrations/migrate.go +++ b/services/migrations/migrate.go @@ -176,7 +176,7 @@ func newDownloader(ctx context.Context, ownerName string, opts base.MigrateOptio // migrateRepository will download information and then upload it to Uploader, this is a simple // process for small repository. For a big repository, save all the data to disk // before upload is better -func migrateRepository(ctx context.Context, doer *user_model.User, downloader base.Downloader, uploader base.Uploader, opts base.MigrateOptions, messenger base.Messenger) error { +func migrateRepository(_ context.Context, doer *user_model.User, downloader base.Downloader, uploader base.Uploader, opts base.MigrateOptions, messenger base.Messenger) error { if messenger == nil { messenger = base.NilMessenger } diff --git a/services/repository/transfer.go b/services/repository/transfer.go index 3d0bce18d01d3..9e0ff7ae1405a 100644 --- a/services/repository/transfer.go +++ b/services/repository/transfer.go @@ -285,7 +285,7 @@ func transferOwnership(ctx context.Context, doer *user_model.User, newOwnerName } // changeRepositoryName changes all corresponding setting from old repository name to new one. -func changeRepositoryName(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, newRepoName string) (err error) { +func changeRepositoryName(ctx context.Context, repo *repo_model.Repository, newRepoName string) (err error) { oldRepoName := repo.Name newRepoName = strings.ToLower(newRepoName) if err = repo_model.IsUsableRepoName(newRepoName); err != nil { @@ -347,7 +347,7 @@ func ChangeRepositoryName(ctx context.Context, doer *user_model.User, repo *repo // local copy's origin accordingly. repoWorkingPool.CheckIn(fmt.Sprint(repo.ID)) - if err := changeRepositoryName(ctx, doer, repo, newRepoName); err != nil { + if err := changeRepositoryName(ctx, repo, newRepoName); err != nil { repoWorkingPool.CheckOut(fmt.Sprint(repo.ID)) return err } diff --git a/tests/integration/api_repo_tags_test.go b/tests/integration/api_repo_tags_test.go index c6eeb404c02c4..a7f021ca4fbfa 100644 --- a/tests/integration/api_repo_tags_test.go +++ b/tests/integration/api_repo_tags_test.go @@ -42,7 +42,7 @@ func TestAPIRepoTags(t *testing.T) { assert.Equal(t, setting.AppURL+"user2/repo1/archive/v1.1.zip", tags[0].ZipballURL) assert.Equal(t, setting.AppURL+"user2/repo1/archive/v1.1.tar.gz", tags[0].TarballURL) - newTag := createNewTagUsingAPI(t, session, token, user.Name, repoName, "gitea/22", "", "nice!\nand some text") + newTag := createNewTagUsingAPI(t, token, user.Name, repoName, "gitea/22", "", "nice!\nand some text") resp = MakeRequest(t, req, http.StatusOK) DecodeJSON(t, resp, &tags) assert.Len(t, tags, 2) @@ -72,7 +72,7 @@ func TestAPIRepoTags(t *testing.T) { MakeRequest(t, req, http.StatusNotFound) } -func createNewTagUsingAPI(t *testing.T, session *TestSession, token, ownerName, repoName, name, target, msg string) *api.Tag { +func createNewTagUsingAPI(t *testing.T, token, ownerName, repoName, name, target, msg string) *api.Tag { urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/tags", ownerName, repoName) req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateTagOption{ TagName: name, diff --git a/tests/integration/dump_restore_test.go b/tests/integration/dump_restore_test.go index bed245305447d..47bb6f76e9791 100644 --- a/tests/integration/dump_restore_test.go +++ b/tests/integration/dump_restore_test.go @@ -237,7 +237,7 @@ func (c *compareDump) assertLoadFiles(beforeFilename, afterFilename string, t re // // Given []Something{} create afterPtr, beforePtr []*Something{} // - sliceType := reflect.SliceOf(reflect.PtrTo(t.Elem())) + sliceType := reflect.SliceOf(reflect.PointerTo(t.Elem())) beforeSlice := reflect.MakeSlice(sliceType, 0, 10) beforePtr = reflect.New(beforeSlice.Type()) beforePtr.Elem().Set(beforeSlice) diff --git a/tests/integration/gpg_git_test.go b/tests/integration/gpg_git_test.go index 3ba4a5882cf96..047c049c7f45d 100644 --- a/tests/integration/gpg_git_test.go +++ b/tests/integration/gpg_git_test.go @@ -35,7 +35,7 @@ func TestGPGGit(t *testing.T) { defer os.Setenv("GNUPGHOME", oldGNUPGHome) // Need to create a root key - rootKeyPair, err := importTestingKey(tmpDir, "gitea", "gitea@fake.local") + rootKeyPair, err := importTestingKey() if !assert.NoError(t, err, "importTestingKey") { return } @@ -262,7 +262,7 @@ func TestGPGGit(t *testing.T) { }) } -func crudActionCreateFile(t *testing.T, ctx APITestContext, user *user_model.User, from, to, path string, callback ...func(*testing.T, api.FileResponse)) func(*testing.T) { +func crudActionCreateFile(_ *testing.T, ctx APITestContext, user *user_model.User, from, to, path string, callback ...func(*testing.T, api.FileResponse)) func(*testing.T) { return doAPICreateFile(ctx, path, &api.CreateFileOptions{ FileOptions: api.FileOptions{ BranchName: from, @@ -281,7 +281,7 @@ func crudActionCreateFile(t *testing.T, ctx APITestContext, user *user_model.Use }, callback...) } -func importTestingKey(tmpDir, name, email string) (*openpgp.Entity, error) { +func importTestingKey() (*openpgp.Entity, error) { if _, _, err := process.GetManager().Exec("gpg --import tests/integration/private-testing.key", "gpg", "--import", "tests/integration/private-testing.key"); err != nil { return nil, err } diff --git a/tools/lint-go-gopls.sh b/tools/lint-go-gopls.sh new file mode 100755 index 0000000000000..4bb69f4c16c1a --- /dev/null +++ b/tools/lint-go-gopls.sh @@ -0,0 +1,23 @@ +#!/bin/bash +set -uo pipefail + +cd "$(dirname -- "${BASH_SOURCE[0]}")" && cd .. + +IGNORE_PATTERNS=( + "is deprecated" # TODO: fix these +) + +# lint all go files with 'gopls check' and look for lines starting with the +# current absolute path, indicating a error was found. This is neccessary +# because the tool does not set non-zero exit code when errors are found. +# ref: https://github.com/golang/go/issues/67078 +ERROR_LINES=$("$GO" run "$GOPLS_PACKAGE" check "$@" 2>/dev/null | grep -E "^$PWD" | grep -vFf <(printf '%s\n' "${IGNORE_PATTERNS[@]}")); +NUM_ERRORS=$(echo -n "$ERROR_LINES" | wc -l) + +if [ "$NUM_ERRORS" -eq "0" ]; then + exit 0; +else + echo "$ERROR_LINES" + echo "Found $NUM_ERRORS 'gopls check' errors" + exit 1; +fi