diff --git a/.eslintrc.yaml b/.eslintrc.yaml index 72039a601380a..eeb3e20cb8c65 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -119,7 +119,7 @@ rules: "@stylistic/js/arrow-spacing": [2, {before: true, after: true}] "@stylistic/js/block-spacing": [0] "@stylistic/js/brace-style": [2, 1tbs, {allowSingleLine: true}] - "@stylistic/js/comma-dangle": [2, only-multiline] + "@stylistic/js/comma-dangle": [2, always-multiline] "@stylistic/js/comma-spacing": [2, {before: false, after: true}] "@stylistic/js/comma-style": [2, last] "@stylistic/js/computed-property-spacing": [2, never] diff --git a/.stylelintrc.yaml b/.stylelintrc.yaml index c7725159f10ab..60cce7dbf75ea 100644 --- a/.stylelintrc.yaml +++ b/.stylelintrc.yaml @@ -30,7 +30,7 @@ rules: "@stylistic/block-opening-brace-newline-after": null "@stylistic/block-opening-brace-newline-before": null "@stylistic/block-opening-brace-space-after": null - "@stylistic/block-opening-brace-space-before": null + "@stylistic/block-opening-brace-space-before": always "@stylistic/color-hex-case": lower "@stylistic/declaration-bang-space-after": never "@stylistic/declaration-bang-space-before": null @@ -140,7 +140,7 @@ rules: function-disallowed-list: null function-linear-gradient-no-nonstandard-direction: true function-name-case: lower - function-no-unknown: null + function-no-unknown: true function-url-no-scheme-relative: null function-url-quotes: always function-url-scheme-allowed-list: null @@ -168,7 +168,7 @@ rules: no-duplicate-selectors: true no-empty-source: true no-invalid-double-slash-comments: true - no-invalid-position-at-import-rule: null + no-invalid-position-at-import-rule: [true, ignoreAtRules: [tailwind]] no-irregular-whitespace: true no-unknown-animations: null no-unknown-custom-properties: null @@ -181,6 +181,7 @@ rules: rule-empty-line-before: null rule-selector-property-disallowed-list: null scale-unlimited/declaration-strict-value: [[/color$/, font-weight], {ignoreValues: /^(inherit|transparent|unset|initial|currentcolor|none)$/, ignoreFunctions: false, disableFix: true, expandShorthand: true}] + selector-anb-no-unmatchable: true selector-attribute-name-disallowed-list: null selector-attribute-operator-allowed-list: null selector-attribute-operator-disallowed-list: null diff --git a/docs/content/contributing/guidelines-frontend.en-us.md b/docs/content/contributing/guidelines-frontend.en-us.md index 2c0aaaed4a36b..eec4a88fd04b5 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-df`), 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-mono`), 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 b5fb8964b3427..040dba3d765e7 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-df`),Gitea 自身的私有框架级 CSS 类使用 `g-` 前缀(`g-modal-confirm`)。 +12. 建议使用 Tailwind CSS,它可以通过 `tw-` 前缀获得,例如 `tw-relative`. Gitea 自身的助手类 CSS 使用 `gt-` 前缀(`gt-mono`),Gitea 自身的私有框架级 CSS 类使用 `g-` 前缀(`g-modal-confirm`)。 13. 尽量避免内联脚本和样式,建议将JS代码放入JS文件中并使用CSS类。如果内联脚本和样式不可避免,请解释无法避免的原因。 ### 可访问性 / ARIA diff --git a/models/asymkey/ssh_key_authorized_keys.go b/models/asymkey/ssh_key_authorized_keys.go index 7621994866e3f..2e4cd62e5cf76 100644 --- a/models/asymkey/ssh_key_authorized_keys.go +++ b/models/asymkey/ssh_key_authorized_keys.go @@ -139,6 +139,8 @@ func RegeneratePublicKeys(ctx context.Context, t io.StringWriter) error { if err != nil { return err } + defer f.Close() + scanner := bufio.NewScanner(f) for scanner.Scan() { line := scanner.Text() @@ -148,15 +150,12 @@ func RegeneratePublicKeys(ctx context.Context, t io.StringWriter) error { } _, err = t.WriteString(line + "\n") if err != nil { - f.Close() return err } } - err = scanner.Err() - if err != nil { - return fmt.Errorf("scan: %w", err) + if err = scanner.Err(); err != nil { + return fmt.Errorf("RegeneratePublicKeys scan: %w", err) } - f.Close() } return nil } diff --git a/models/avatars/avatar.go b/models/avatars/avatar.go index bbe16483bf7f6..9c56e0f9a0fba 100644 --- a/models/avatars/avatar.go +++ b/models/avatars/avatar.go @@ -24,7 +24,7 @@ import ( const ( // DefaultAvatarClass is the default class of a rendered avatar - DefaultAvatarClass = "ui avatar gt-vm" + DefaultAvatarClass = "ui avatar tw-align-middle" // DefaultAvatarPixelSize is the default size in pixels of a rendered avatar DefaultAvatarPixelSize = 28 ) diff --git a/models/organization/org.go b/models/organization/org.go index a3082e9ac7458..ba0fd756e38f6 100644 --- a/models/organization/org.go +++ b/models/organization/org.go @@ -319,8 +319,9 @@ func CreateOrganization(ctx context.Context, org *Organization, owner *user_mode // Add initial creator to organization and owner team. if err = db.Insert(ctx, &OrgUser{ - UID: owner.ID, - OrgID: org.ID, + UID: owner.ID, + OrgID: org.ID, + IsPublic: setting.Service.DefaultOrgMemberVisible, }); err != nil { return fmt.Errorf("insert org-user relation: %w", err) } diff --git a/modules/actions/log.go b/modules/actions/log.go index cdf18646aaf02..c38082b5dc14f 100644 --- a/modules/actions/log.go +++ b/modules/actions/log.go @@ -100,7 +100,7 @@ func ReadLogs(ctx context.Context, inStorage bool, filename string, offset, limi } if err := scanner.Err(); err != nil { - return nil, fmt.Errorf("scan: %w", err) + return nil, fmt.Errorf("ReadLogs scan: %w", err) } return rows, nil diff --git a/modules/git/commit.go b/modules/git/commit.go index 789a2e8f6927f..ef2676762c174 100644 --- a/modules/git/commit.go +++ b/modules/git/commit.go @@ -397,9 +397,8 @@ func (c *Commit) GetSubModules() (*ObjectCache, error) { } } } - err = scanner.Err() - if err != nil { - return nil, fmt.Errorf("scan: %w", err) + if err = scanner.Err(); err != nil { + return nil, fmt.Errorf("GetSubModules scan: %w", err) } return c.submoduleCache, nil diff --git a/modules/git/repo_stats.go b/modules/git/repo_stats.go index ce82946873e1e..83220104bd68f 100644 --- a/modules/git/repo_stats.go +++ b/modules/git/repo_stats.go @@ -124,9 +124,9 @@ func (repo *Repository) GetCodeActivityStats(fromTime time.Time, branch string) } } } - err = scanner.Err() - if err != nil { - return fmt.Errorf("scan: %w", err) + if err = scanner.Err(); err != nil { + _ = stdoutReader.Close() + return fmt.Errorf("GetCodeActivityStats scan: %w", err) } a := make([]*CodeActivityAuthor, 0, len(authors)) for _, v := range authors { diff --git a/modules/indexer/code/bleve/bleve.go b/modules/indexer/code/bleve/bleve.go index d7f735e957db9..c607d780ef968 100644 --- a/modules/indexer/code/bleve/bleve.go +++ b/modules/indexer/code/bleve/bleve.go @@ -39,6 +39,8 @@ import ( const ( unicodeNormalizeName = "unicodeNormalize" maxBatchSize = 16 + // fuzzyDenominator determines the levenshtein distance per each character of a keyword + fuzzyDenominator = 4 ) func addUnicodeNormalizeTokenFilter(m *mapping.IndexMappingImpl) error { @@ -239,15 +241,12 @@ func (b *Indexer) Search(ctx context.Context, opts *internal.SearchOptions) (int keywordQuery query.Query ) + phraseQuery := bleve.NewMatchPhraseQuery(opts.Keyword) + phraseQuery.FieldVal = "Content" + phraseQuery.Analyzer = repoIndexerAnalyzer + keywordQuery = phraseQuery if opts.IsKeywordFuzzy { - phraseQuery := bleve.NewMatchPhraseQuery(opts.Keyword) - phraseQuery.FieldVal = "Content" - phraseQuery.Analyzer = repoIndexerAnalyzer - keywordQuery = phraseQuery - } else { - prefixQuery := bleve.NewPrefixQuery(opts.Keyword) - prefixQuery.FieldVal = "Content" - keywordQuery = prefixQuery + phraseQuery.Fuzziness = len(opts.Keyword) / fuzzyDenominator } if len(opts.RepoIDs) > 0 { diff --git a/modules/indexer/internal/bleve/query.go b/modules/indexer/internal/bleve/query.go index b96875343e5ea..21422b281c498 100644 --- a/modules/indexer/internal/bleve/query.go +++ b/modules/indexer/internal/bleve/query.go @@ -20,17 +20,11 @@ func NumericEqualityQuery(value int64, field string) *query.NumericRangeQuery { } // MatchPhraseQuery generates a match phrase query for the given phrase, field and analyzer -func MatchPhraseQuery(matchPhrase, field, analyzer string) *query.MatchPhraseQuery { +func MatchPhraseQuery(matchPhrase, field, analyzer string, fuzziness int) *query.MatchPhraseQuery { q := bleve.NewMatchPhraseQuery(matchPhrase) q.FieldVal = field q.Analyzer = analyzer - return q -} - -// PrefixQuery generates a match prefix query for the given prefix and field -func PrefixQuery(matchPrefix, field string) *query.PrefixQuery { - q := bleve.NewPrefixQuery(matchPrefix) - q.FieldVal = field + q.Fuzziness = fuzziness return q } diff --git a/modules/indexer/issues/bleve/bleve.go b/modules/indexer/issues/bleve/bleve.go index 927ad58cd4c57..1f54be721b37c 100644 --- a/modules/indexer/issues/bleve/bleve.go +++ b/modules/indexer/issues/bleve/bleve.go @@ -35,7 +35,11 @@ func addUnicodeNormalizeTokenFilter(m *mapping.IndexMappingImpl) error { }) } -const maxBatchSize = 16 +const ( + maxBatchSize = 16 + // fuzzyDenominator determines the levenshtein distance per each character of a keyword + fuzzyDenominator = 4 +) // IndexerData an update to the issue indexer type IndexerData internal.IndexerData @@ -156,19 +160,16 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) ( var queries []query.Query if options.Keyword != "" { + fuzziness := 0 if options.IsFuzzyKeyword { - queries = append(queries, bleve.NewDisjunctionQuery([]query.Query{ - inner_bleve.MatchPhraseQuery(options.Keyword, "title", issueIndexerAnalyzer), - inner_bleve.MatchPhraseQuery(options.Keyword, "content", issueIndexerAnalyzer), - inner_bleve.MatchPhraseQuery(options.Keyword, "comments", issueIndexerAnalyzer), - }...)) - } else { - queries = append(queries, bleve.NewDisjunctionQuery([]query.Query{ - inner_bleve.PrefixQuery(options.Keyword, "title"), - inner_bleve.PrefixQuery(options.Keyword, "content"), - inner_bleve.PrefixQuery(options.Keyword, "comments"), - }...)) + fuzziness = len(options.Keyword) / fuzzyDenominator } + + queries = append(queries, bleve.NewDisjunctionQuery([]query.Query{ + inner_bleve.MatchPhraseQuery(options.Keyword, "title", issueIndexerAnalyzer, fuzziness), + inner_bleve.MatchPhraseQuery(options.Keyword, "content", issueIndexerAnalyzer, fuzziness), + inner_bleve.MatchPhraseQuery(options.Keyword, "comments", issueIndexerAnalyzer, fuzziness), + }...)) } if len(options.RepoIDs) > 0 || options.AllPublic { diff --git a/modules/indexer/issues/internal/tests/tests.go b/modules/indexer/issues/internal/tests/tests.go index 91aafd589c768..2209377c2f573 100644 --- a/modules/indexer/issues/internal/tests/tests.go +++ b/modules/indexer/issues/internal/tests/tests.go @@ -515,10 +515,8 @@ var cases = []*testIndexerCase{ { Name: "SortByCreatedDesc", SearchOptions: &internal.SearchOptions{ - Paginator: &db.ListOptions{ - ListAll: true, - }, - SortBy: internal.SortByCreatedDesc, + Paginator: &db.ListOptionsAll, + SortBy: internal.SortByCreatedDesc, }, Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) { assert.Equal(t, len(data), len(result.Hits)) @@ -533,10 +531,8 @@ var cases = []*testIndexerCase{ { Name: "SortByUpdatedDesc", SearchOptions: &internal.SearchOptions{ - Paginator: &db.ListOptions{ - ListAll: true, - }, - SortBy: internal.SortByUpdatedDesc, + Paginator: &db.ListOptionsAll, + SortBy: internal.SortByUpdatedDesc, }, Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) { assert.Equal(t, len(data), len(result.Hits)) @@ -551,10 +547,8 @@ var cases = []*testIndexerCase{ { Name: "SortByCommentsDesc", SearchOptions: &internal.SearchOptions{ - Paginator: &db.ListOptions{ - ListAll: true, - }, - SortBy: internal.SortByCommentsDesc, + Paginator: &db.ListOptionsAll, + SortBy: internal.SortByCommentsDesc, }, Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) { assert.Equal(t, len(data), len(result.Hits)) @@ -569,10 +563,8 @@ var cases = []*testIndexerCase{ { Name: "SortByDeadlineDesc", SearchOptions: &internal.SearchOptions{ - Paginator: &db.ListOptions{ - ListAll: true, - }, - SortBy: internal.SortByDeadlineDesc, + Paginator: &db.ListOptionsAll, + SortBy: internal.SortByDeadlineDesc, }, Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) { assert.Equal(t, len(data), len(result.Hits)) @@ -587,10 +579,8 @@ var cases = []*testIndexerCase{ { Name: "SortByCreatedAsc", SearchOptions: &internal.SearchOptions{ - Paginator: &db.ListOptions{ - ListAll: true, - }, - SortBy: internal.SortByCreatedAsc, + Paginator: &db.ListOptionsAll, + SortBy: internal.SortByCreatedAsc, }, Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) { assert.Equal(t, len(data), len(result.Hits)) @@ -605,10 +595,8 @@ var cases = []*testIndexerCase{ { Name: "SortByUpdatedAsc", SearchOptions: &internal.SearchOptions{ - Paginator: &db.ListOptions{ - ListAll: true, - }, - SortBy: internal.SortByUpdatedAsc, + Paginator: &db.ListOptionsAll, + SortBy: internal.SortByUpdatedAsc, }, Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) { assert.Equal(t, len(data), len(result.Hits)) @@ -623,10 +611,8 @@ var cases = []*testIndexerCase{ { Name: "SortByCommentsAsc", SearchOptions: &internal.SearchOptions{ - Paginator: &db.ListOptions{ - ListAll: true, - }, - SortBy: internal.SortByCommentsAsc, + Paginator: &db.ListOptionsAll, + SortBy: internal.SortByCommentsAsc, }, Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) { assert.Equal(t, len(data), len(result.Hits)) @@ -641,10 +627,8 @@ var cases = []*testIndexerCase{ { Name: "SortByDeadlineAsc", SearchOptions: &internal.SearchOptions{ - Paginator: &db.ListOptions{ - ListAll: true, - }, - SortBy: internal.SortByDeadlineAsc, + Paginator: &db.ListOptionsAll, + SortBy: internal.SortByDeadlineAsc, }, Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) { assert.Equal(t, len(data), len(result.Hits)) diff --git a/modules/indexer/issues/util.go b/modules/indexer/issues/util.go index 510b4060b293a..9861c808dcf6d 100644 --- a/modules/indexer/issues/util.go +++ b/modules/indexer/issues/util.go @@ -61,9 +61,7 @@ func getIssueIndexerData(ctx context.Context, issueID int64) (*internal.IndexerD ) { reviews, err := issue_model.FindReviews(ctx, issue_model.FindReviewOptions{ - ListOptions: db.ListOptions{ - ListAll: true, - }, + ListOptions: db.ListOptionsAll, IssueID: issueID, OfficialOnly: false, }) diff --git a/modules/markup/csv/csv.go b/modules/markup/csv/csv.go index 50bb918442686..1dd26eb8acdba 100644 --- a/modules/markup/csv/csv.go +++ b/modules/markup/csv/csv.go @@ -124,9 +124,8 @@ func (Renderer) fallbackRender(input io.Reader, tmpBlock *bufio.Writer) error { return err } } - err = scan.Err() - if err != nil { - return fmt.Errorf("scan: %w", err) + if err = scan.Err(); err != nil { + return fmt.Errorf("fallbackRender scan: %w", err) } _, err = tmpBlock.WriteString("") diff --git a/modules/markup/markdown/goldmark.go b/modules/markup/markdown/goldmark.go index bdb774824700a..b61299c4808b3 100644 --- a/modules/markup/markdown/goldmark.go +++ b/modules/markup/markdown/goldmark.go @@ -27,7 +27,21 @@ import ( ) // ASTTransformer is a default transformer of the goldmark tree. -type ASTTransformer struct{} +type ASTTransformer struct { + AttentionTypes container.Set[string] +} + +func NewASTTransformer() *ASTTransformer { + return &ASTTransformer{ + AttentionTypes: container.SetOf("note", "tip", "important", "warning", "caution"), + } +} + +func (g *ASTTransformer) applyElementDir(n ast.Node) { + if markup.DefaultProcessorHelper.ElementDir != "" { + n.SetAttributeString("dir", []byte(markup.DefaultProcessorHelper.ElementDir)) + } +} // Transform transforms the given AST tree. func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc parser.Context) { @@ -45,12 +59,6 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa tocMode = rc.TOC } - applyElementDir := func(n ast.Node) { - if markup.DefaultProcessorHelper.ElementDir != "" { - n.SetAttributeString("dir", []byte(markup.DefaultProcessorHelper.ElementDir)) - } - } - _ = ast.Walk(node, func(n ast.Node, entering bool) (ast.WalkStatus, error) { if !entering { return ast.WalkContinue, nil @@ -72,9 +80,9 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa header.ID = util.BytesToReadOnlyString(id.([]byte)) } tocList = append(tocList, header) - applyElementDir(v) + g.applyElementDir(v) case *ast.Paragraph: - applyElementDir(v) + g.applyElementDir(v) case *ast.Image: // Images need two things: // @@ -174,7 +182,7 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa v.AppendChild(v, newChild) } } - applyElementDir(v) + g.applyElementDir(v) case *ast.Text: if v.SoftLineBreak() && !v.HardLineBreak() { if ctx.Metas["mode"] != "document" { @@ -189,51 +197,7 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa v.AppendChild(v, NewColorPreview(colorContent)) } case *ast.Blockquote: - // We only want attention blockquotes when the AST looks like: - // Text: "[" - // Text: "!TYPE" - // Text(SoftLineBreak): "]" - - // grab these nodes and make sure we adhere to the attention blockquote structure - firstParagraph := v.FirstChild() - if firstParagraph.ChildCount() < 3 { - return ast.WalkContinue, nil - } - firstTextNode, ok := firstParagraph.FirstChild().(*ast.Text) - if !ok || string(firstTextNode.Segment.Value(reader.Source())) != "[" { - return ast.WalkContinue, nil - } - secondTextNode, ok := firstTextNode.NextSibling().(*ast.Text) - if !ok || !attentionTypeRE.MatchString(string(secondTextNode.Segment.Value(reader.Source()))) { - return ast.WalkContinue, nil - } - thirdTextNode, ok := secondTextNode.NextSibling().(*ast.Text) - if !ok || string(thirdTextNode.Segment.Value(reader.Source())) != "]" { - return ast.WalkContinue, nil - } - - // grab attention type from markdown source - attentionType := strings.ToLower(strings.TrimPrefix(string(secondTextNode.Segment.Value(reader.Source())), "!")) - - // color the blockquote - v.SetAttributeString("class", []byte("attention-header attention-"+attentionType)) - - // create an emphasis to make it bold - attentionParagraph := ast.NewParagraph() - emphasis := ast.NewEmphasis(2) - emphasis.SetAttributeString("class", []byte("attention-"+attentionType)) - - // capitalize first letter - attentionText := ast.NewString([]byte(strings.ToUpper(string(attentionType[0])) + attentionType[1:])) - - // replace the ![TYPE] with a dedicated paragraph of icon+Type - emphasis.AppendChild(emphasis, attentionText) - attentionParagraph.AppendChild(attentionParagraph, NewAttention(attentionType)) - attentionParagraph.AppendChild(attentionParagraph, emphasis) - firstParagraph.Parent().InsertBefore(firstParagraph.Parent(), firstParagraph, attentionParagraph) - firstParagraph.RemoveChild(firstParagraph, firstTextNode) - firstParagraph.RemoveChild(firstParagraph, secondTextNode) - firstParagraph.RemoveChild(firstParagraph, thirdTextNode) + return g.transformBlockquote(v, reader) } return ast.WalkContinue, nil }) @@ -268,7 +232,7 @@ func (p *prefixedIDs) Generate(value []byte, kind ast.NodeKind) []byte { return p.GenerateWithDefault(value, dft) } -// Generate generates a new element id. +// GenerateWithDefault generates a new element id. func (p *prefixedIDs) GenerateWithDefault(value, dft []byte) []byte { result := common.CleanValue(value) if len(result) == 0 { @@ -303,7 +267,8 @@ func newPrefixedIDs() *prefixedIDs { // in the gitea form. func NewHTMLRenderer(opts ...html.Option) renderer.NodeRenderer { r := &HTMLRenderer{ - Config: html.NewConfig(), + Config: html.NewConfig(), + reValidName: regexp.MustCompile("^[a-z ]+$"), } for _, opt := range opts { opt.SetHTMLOption(&r.Config) @@ -315,6 +280,7 @@ func NewHTMLRenderer(opts ...html.Option) renderer.NodeRenderer { // renders gitea specific features. type HTMLRenderer struct { html.Config + reValidName *regexp.Regexp } // RegisterFuncs implements renderer.NodeRenderer.RegisterFuncs. @@ -442,11 +408,6 @@ func (r *HTMLRenderer) renderSummary(w util.BufWriter, source []byte, node ast.N return ast.WalkContinue, nil } -var ( - validNameRE = regexp.MustCompile("^[a-z ]+$") - attentionTypeRE = regexp.MustCompile("^!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)$") -) - func (r *HTMLRenderer) renderIcon(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { if !entering { return ast.WalkContinue, nil @@ -461,7 +422,7 @@ func (r *HTMLRenderer) renderIcon(w util.BufWriter, source []byte, node ast.Node return ast.WalkContinue, nil } - if !validNameRE.MatchString(name) { + if !r.reValidName.MatchString(name) { // skip this return ast.WalkContinue, nil } diff --git a/modules/markup/markdown/markdown.go b/modules/markup/markdown/markdown.go index 4cca71d511f35..db4e5706f6dda 100644 --- a/modules/markup/markdown/markdown.go +++ b/modules/markup/markdown/markdown.go @@ -126,7 +126,7 @@ func SpecializedMarkdown() goldmark.Markdown { parser.WithAttribute(), parser.WithAutoHeadingID(), parser.WithASTTransformers( - util.Prioritized(&ASTTransformer{}, 10000), + util.Prioritized(NewASTTransformer(), 10000), ), ), goldmark.WithRendererOptions( diff --git a/modules/markup/markdown/markdown_test.go b/modules/markup/markdown/markdown_test.go index a12bd4f9e7c23..ebac3fbe9e8e0 100644 --- a/modules/markup/markdown/markdown_test.go +++ b/modules/markup/markdown/markdown_test.go @@ -16,9 +16,12 @@ import ( "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/svg" "code.gitea.io/gitea/modules/util" "github.com/stretchr/testify/assert" + "golang.org/x/text/cases" + "golang.org/x/text/language" ) const ( @@ -957,3 +960,36 @@ space
assert.Equal(t, template.HTML(c.Expected), result, "Unexpected result in testcase %v", i) } } + +func TestAttention(t *testing.T) { + defer svg.MockIcon("octicon-info")() + defer svg.MockIcon("octicon-light-bulb")() + defer svg.MockIcon("octicon-report")() + defer svg.MockIcon("octicon-alert")() + defer svg.MockIcon("octicon-stop")() + + renderAttention := func(attention, icon string) string { + tmpl := `") + + test(`> [!note]`, renderAttention("note", "octicon-info")+"\n") + test(`> [!tip]`, renderAttention("tip", "octicon-light-bulb")+"\n") + test(`> [!important]`, renderAttention("important", "octicon-report")+"\n") + test(`> [!warning]`, renderAttention("warning", "octicon-alert")+"\n") + test(`> [!caution]`, renderAttention("caution", "octicon-stop")+"\n") +} diff --git a/modules/markup/markdown/transform_blockquote.go b/modules/markup/markdown/transform_blockquote.go new file mode 100644 index 0000000000000..d685cfd1c5a40 --- /dev/null +++ b/modules/markup/markdown/transform_blockquote.go @@ -0,0 +1,67 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package markdown + +import ( + "strings" + + "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/text" + "golang.org/x/text/cases" + "golang.org/x/text/language" +) + +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("]") + + // grab these nodes and make sure we adhere to the attention blockquote structure + firstParagraph := v.FirstChild() + g.applyElementDir(firstParagraph) + if firstParagraph.ChildCount() < 3 { + return ast.WalkContinue, nil + } + node1, ok1 := firstParagraph.FirstChild().(*ast.Text) + node2, ok2 := node1.NextSibling().(*ast.Text) + node3, ok3 := node2.NextSibling().(*ast.Text) + if !ok1 || !ok2 || !ok3 { + return ast.WalkContinue, 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 + } + + // grab attention type from markdown source + attentionType := strings.ToLower(val2[1:]) + if !g.AttentionTypes.Contains(attentionType) { + return ast.WalkContinue, nil + } + + // color the blockquote + v.SetAttributeString("class", []byte("attention-header attention-"+attentionType)) + + // create an emphasis to make it bold + attentionParagraph := ast.NewParagraph() + g.applyElementDir(attentionParagraph) + emphasis := ast.NewEmphasis(2) + emphasis.SetAttributeString("class", []byte("attention-"+attentionType)) + + attentionAstString := ast.NewString([]byte(cases.Title(language.English).String(attentionType))) + + // replace the ![TYPE] with a dedicated paragraph of icon+Type + emphasis.AppendChild(emphasis, attentionAstString) + 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) + if firstParagraph.ChildCount() == 0 { + firstParagraph.Parent().RemoveChild(firstParagraph.Parent(), firstParagraph) + } + return ast.WalkContinue, nil +} diff --git a/modules/svg/svg.go b/modules/svg/svg.go index 016e1dc08bb34..8132978caca99 100644 --- a/modules/svg/svg.go +++ b/modules/svg/svg.go @@ -41,6 +41,21 @@ func Init() error { return nil } +func MockIcon(icon string) func() { + if svgIcons == nil { + svgIcons = make(map[string]string) + } + orig, exist := svgIcons[icon] + svgIcons[icon] = fmt.Sprintf(``, icon, defaultSize, defaultSize) + return func() { + if exist { + svgIcons[icon] = orig + } else { + delete(svgIcons, icon) + } + } +} + // RenderHTML renders icons - arguments icon name (string), size (int), class (string) func RenderHTML(icon string, others ...any) template.HTML { size, class := gitea_html.ParseSizeAndClass(defaultSize, "", others...) @@ -55,5 +70,6 @@ func RenderHTML(icon string, others ...any) template.HTML { } return template.HTML(svgStr) } - return "" + // during test (or something wrong happens), there is no SVG loaded, so use a dummy span to tell that the icon is missing + return template.HTML(fmt.Sprintf("%s(%d/%s)", template.HTMLEscapeString(icon), size, template.HTMLEscapeString(class))) } diff --git a/playwright.config.js b/playwright.config.js index b7badf1cc00f3..bdd303ae25341 100644 --- a/playwright.config.js +++ b/playwright.config.js @@ -20,7 +20,7 @@ export default { * Maximum time expect() should wait for the condition to be met. * For example in `await expect(locator).toHaveText();` */ - timeout: 2000 + timeout: 2000, }, /* Fail the build on CI if you accidentally left test.only in the source code. */ diff --git a/routers/web/admin/users.go b/routers/web/admin/users.go index 6dfcfc3d9a1a7..b93668c5a24ec 100644 --- a/routers/web/admin/users.go +++ b/routers/web/admin/users.go @@ -275,9 +275,7 @@ func ViewUser(ctx *context.Context) { } repos, count, err := repo_model.SearchRepository(ctx, &repo_model.SearchRepoOptions{ - ListOptions: db.ListOptions{ - ListAll: true, - }, + ListOptions: db.ListOptionsAll, OwnerID: u.ID, OrderBy: db.SearchOrderByAlphabetically, Private: true, @@ -300,9 +298,7 @@ func ViewUser(ctx *context.Context) { ctx.Data["EmailsTotal"] = len(emails) orgs, err := db.Find[org_model.Organization](ctx, org_model.FindOrgOptions{ - ListOptions: db.ListOptions{ - ListAll: true, - }, + ListOptions: db.ListOptionsAll, UserID: u.ID, IncludePrivate: true, }) diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go index d66de782f4d94..8543fa44cc712 100644 --- a/routers/web/repo/commit.go +++ b/routers/web/repo/commit.go @@ -351,7 +351,7 @@ func Diff(ctx *context.Context) { ctx.Data["Commit"] = commit ctx.Data["Diff"] = diff - statuses, _, err := git_model.GetLatestCommitStatus(ctx, ctx.Repo.Repository.ID, commitID, db.ListOptions{ListAll: true}) + statuses, _, err := git_model.GetLatestCommitStatus(ctx, ctx.Repo.Repository.ID, commitID, db.ListOptionsAll) if err != nil { log.Error("GetLatestCommitStatus: %v", err) } diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go index bf42b77b66a4b..cfb0e859bd7c8 100644 --- a/routers/web/repo/compare.go +++ b/routers/web/repo/compare.go @@ -697,10 +697,8 @@ func getBranchesAndTagsForRepo(ctx gocontext.Context, repo *repo_model.Repositor defer gitRepo.Close() branches, err = git_model.FindBranchNames(ctx, git_model.FindBranchOptions{ - RepoID: repo.ID, - ListOptions: db.ListOptions{ - ListAll: true, - }, + RepoID: repo.ID, + ListOptions: db.ListOptionsAll, IsDeletedBranch: optional.Some(false), }) if err != nil { @@ -754,10 +752,8 @@ func CompareDiff(ctx *context.Context) { } headBranches, err := git_model.FindBranchNames(ctx, git_model.FindBranchOptions{ - RepoID: ci.HeadRepo.ID, - ListOptions: db.ListOptions{ - ListAll: true, - }, + RepoID: ci.HeadRepo.ID, + ListOptions: db.ListOptionsAll, IsDeletedBranch: optional.Some(false), }) if err != nil { @@ -980,9 +976,8 @@ func getExcerptLines(commit *git.Commit, filePath string, idxLeft, idxRight, chu } diffLines = append(diffLines, diffLine) } - err = scanner.Err() - if err != nil { - return nil, fmt.Errorf("scan: %w", err) + if err = scanner.Err(); err != nil { + return nil, fmt.Errorf("getExcerptLines scan: %w", err) } return diffLines, nil } diff --git a/routers/web/repo/editor.go b/routers/web/repo/editor.go index 29395b40130ea..082666276ae00 100644 --- a/routers/web/repo/editor.go +++ b/routers/web/repo/editor.go @@ -333,9 +333,9 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b ctx.Error(http.StatusInternalServerError, err.Error()) } } else if models.IsErrCommitIDDoesNotMatch(err) { - ctx.RenderWithErr(ctx.Tr("repo.editor.commit_id_not_matching", ctx.Repo.RepoLink+"/compare/"+util.PathEscapeSegments(form.LastCommit)+"..."+util.PathEscapeSegments(ctx.Repo.CommitID)), tplEditFile, &form) + ctx.RenderWithErr(ctx.Tr("repo.editor.commit_id_not_matching"), tplEditFile, &form) } else if git.IsErrPushOutOfDate(err) { - ctx.RenderWithErr(ctx.Tr("repo.editor.push_out_of_date", ctx.Repo.RepoLink+"/compare/"+util.PathEscapeSegments(form.LastCommit)+"..."+util.PathEscapeSegments(form.NewBranchName)), tplEditFile, &form) + ctx.RenderWithErr(ctx.Tr("repo.editor.push_out_of_date"), tplEditFile, &form) } else if git.IsErrPushRejected(err) { errPushRej := err.(*git.ErrPushRejected) if len(errPushRej.Message) == 0 { diff --git a/routers/web/repo/find.go b/routers/web/repo/find.go index 07b372279882f..9da4237c1edd3 100644 --- a/routers/web/repo/find.go +++ b/routers/web/repo/find.go @@ -7,6 +7,7 @@ import ( "net/http" "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/services/context" ) @@ -17,7 +18,7 @@ const ( // FindFiles render the page to find repository files func FindFiles(ctx *context.Context) { path := ctx.Params("*") - ctx.Data["TreeLink"] = ctx.Repo.RepoLink + "/src/" + path - ctx.Data["DataLink"] = ctx.Repo.RepoLink + "/tree-list/" + path + ctx.Data["TreeLink"] = ctx.Repo.RepoLink + "/src/" + util.PathEscapeSegments(path) + ctx.Data["DataLink"] = ctx.Repo.RepoLink + "/tree-list/" + util.PathEscapeSegments(path) ctx.HTML(http.StatusOK, tplFindFiles) } diff --git a/routers/web/repo/fork.go b/routers/web/repo/fork.go index 60e37476eefd4..27e42a8f98e44 100644 --- a/routers/web/repo/fork.go +++ b/routers/web/repo/fork.go @@ -101,10 +101,8 @@ func getForkRepository(ctx *context.Context) *repo_model.Repository { } branches, err := git_model.FindBranchNames(ctx, git_model.FindBranchOptions{ - RepoID: ctx.Repo.Repository.ID, - ListOptions: db.ListOptions{ - ListAll: true, - }, + RepoID: ctx.Repo.Repository.ID, + ListOptions: db.ListOptionsAll, IsDeletedBranch: optional.Some(false), // Add it as the first option ExcludeBranchNames: []string{ctx.Repo.Repository.DefaultBranch}, diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index 447781602d884..2422be39b8e92 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -278,7 +278,7 @@ func PrepareMergedViewPullInfo(ctx *context.Context, issue *issues_model.Issue) if len(compareInfo.Commits) != 0 { sha := compareInfo.Commits[0].ID.String() - commitStatuses, _, err := git_model.GetLatestCommitStatus(ctx, ctx.Repo.Repository.ID, sha, db.ListOptions{ListAll: true}) + commitStatuses, _, err := git_model.GetLatestCommitStatus(ctx, ctx.Repo.Repository.ID, sha, db.ListOptionsAll) if err != nil { ctx.ServerError("GetLatestCommitStatus", err) return nil @@ -340,7 +340,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C ctx.ServerError(fmt.Sprintf("GetRefCommitID(%s)", pull.GetGitRefName()), err) return nil } - commitStatuses, _, err := git_model.GetLatestCommitStatus(ctx, repo.ID, sha, db.ListOptions{ListAll: true}) + commitStatuses, _, err := git_model.GetLatestCommitStatus(ctx, repo.ID, sha, db.ListOptionsAll) if err != nil { ctx.ServerError("GetLatestCommitStatus", err) return nil @@ -432,7 +432,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C return nil } - commitStatuses, _, err := git_model.GetLatestCommitStatus(ctx, repo.ID, sha, db.ListOptions{ListAll: true}) + commitStatuses, _, err := git_model.GetLatestCommitStatus(ctx, repo.ID, sha, db.ListOptionsAll) if err != nil { ctx.ServerError("GetLatestCommitStatus", err) return nil diff --git a/routers/web/repo/release.go b/routers/web/repo/release.go index dbc190928f946..7ba23f0701193 100644 --- a/routers/web/repo/release.go +++ b/routers/web/repo/release.go @@ -136,7 +136,7 @@ func getReleaseInfos(ctx *context.Context, opts *repo_model.FindReleasesOptions) } if canReadActions { - statuses, _, err := git_model.GetLatestCommitStatus(ctx, r.Repo.ID, r.Sha1, db.ListOptions{ListAll: true}) + statuses, _, err := git_model.GetLatestCommitStatus(ctx, r.Repo.ID, r.Sha1, db.ListOptionsAll) if err != nil { return nil, err } diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go index 0490feb621de6..4e448933c794e 100644 --- a/routers/web/repo/repo.go +++ b/routers/web/repo/repo.go @@ -688,9 +688,7 @@ func GetBranchesList(ctx *context.Context) { branchOpts := git_model.FindBranchOptions{ RepoID: ctx.Repo.Repository.ID, IsDeletedBranch: optional.Some(false), - ListOptions: db.ListOptions{ - ListAll: true, - }, + ListOptions: db.ListOptionsAll, } branches, err := git_model.FindBranchNames(ctx, branchOpts) if err != nil { @@ -723,9 +721,7 @@ func PrepareBranchList(ctx *context.Context) { branchOpts := git_model.FindBranchOptions{ RepoID: ctx.Repo.Repository.ID, IsDeletedBranch: optional.Some(false), - ListOptions: db.ListOptions{ - ListAll: true, - }, + ListOptions: db.ListOptionsAll, } brs, err := git_model.FindBranchNames(ctx, branchOpts) if err != nil { diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index 712d12705e950..b9e623919aa18 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -359,7 +359,7 @@ func loadLatestCommitData(ctx *context.Context, latestCommit *git.Commit) bool { ctx.Data["LatestCommitVerification"] = verification ctx.Data["LatestCommitUser"] = user_model.ValidateCommitWithEmail(ctx, latestCommit) - statuses, _, err := git_model.GetLatestCommitStatus(ctx, ctx.Repo.Repository.ID, latestCommit.ID.String(), db.ListOptions{ListAll: true}) + statuses, _, err := git_model.GetLatestCommitStatus(ctx, ctx.Repo.Repository.ID, latestCommit.ID.String(), db.ListOptionsAll) if err != nil { log.Error("GetLatestCommitStatus: %v", err) } diff --git a/services/actions/commit_status.go b/services/actions/commit_status.go index edd1fd1568754..42365539271be 100644 --- a/services/actions/commit_status.go +++ b/services/actions/commit_status.go @@ -79,7 +79,7 @@ func createCommitStatus(ctx context.Context, job *actions_model.ActionRunJob) er } ctxname := fmt.Sprintf("%s / %s (%s)", runName, job.Name, event) state := toCommitStatus(job.Status) - if statuses, _, err := git_model.GetLatestCommitStatus(ctx, repo.ID, sha, db.ListOptions{ListAll: true}); err == nil { + if statuses, _, err := git_model.GetLatestCommitStatus(ctx, repo.ID, sha, db.ListOptionsAll); err == nil { for _, v := range statuses { if v.Context == ctxname { if v.State == state { diff --git a/services/asymkey/ssh_key_authorized_principals.go b/services/asymkey/ssh_key_authorized_principals.go index 822dd0ffe7a00..2838bb5fc719b 100644 --- a/services/asymkey/ssh_key_authorized_principals.go +++ b/services/asymkey/ssh_key_authorized_principals.go @@ -109,6 +109,8 @@ func regeneratePrincipalKeys(ctx context.Context, t io.StringWriter) error { if err != nil { return err } + defer f.Close() + scanner := bufio.NewScanner(f) for scanner.Scan() { line := scanner.Text() @@ -118,15 +120,12 @@ func regeneratePrincipalKeys(ctx context.Context, t io.StringWriter) error { } _, err = t.WriteString(line + "\n") if err != nil { - f.Close() return err } } - err = scanner.Err() - if err != nil { - return fmt.Errorf("scan: %w", err) + if err = scanner.Err(); err != nil { + return fmt.Errorf("regeneratePrincipalKeys scan: %w", err) } - f.Close() } return nil } diff --git a/services/doctor/authorizedkeys.go b/services/doctor/authorizedkeys.go index bc0266c4bc78b..8d6fc9cb5e806 100644 --- a/services/doctor/authorizedkeys.go +++ b/services/doctor/authorizedkeys.go @@ -51,11 +51,11 @@ func checkAuthorizedKeys(ctx context.Context, logger log.Logger, autofix bool) e } linesInAuthorizedKeys.Add(line) } - err = scanner.Err() - if err != nil { + if err = scanner.Err(); err != nil { return fmt.Errorf("scan: %w", err) } - f.Close() + // although there is a "defer close" above, here close explicitly before the generating, because it needs to open the file for writing again + _ = f.Close() // now we regenerate and check if there are any lines missing regenerated := &bytes.Buffer{} diff --git a/services/pull/commit_status.go b/services/pull/commit_status.go index 653bfe6bcb38b..aa1ad7cd665b8 100644 --- a/services/pull/commit_status.go +++ b/services/pull/commit_status.go @@ -152,7 +152,7 @@ func GetPullRequestCommitStatusState(ctx context.Context, pr *issues_model.PullR return "", errors.Wrap(err, "LoadBaseRepo") } - commitStatuses, _, err := git_model.GetLatestCommitStatus(ctx, pr.BaseRepo.ID, sha, db.ListOptions{ListAll: true}) + commitStatuses, _, err := git_model.GetLatestCommitStatus(ctx, pr.BaseRepo.ID, sha, db.ListOptionsAll) if err != nil { return "", errors.Wrap(err, "GetLatestCommitStatus") } diff --git a/services/pull/pull.go b/services/pull/pull.go index 8a9c6db91764e..4289e2e6e1de5 100644 --- a/services/pull/pull.go +++ b/services/pull/pull.go @@ -883,7 +883,7 @@ func getAllCommitStatus(ctx context.Context, gitRepo *git.Repository, pr *issues return nil, nil, shaErr } - statuses, _, err = git_model.GetLatestCommitStatus(ctx, pr.BaseRepo.ID, sha, db.ListOptions{ListAll: true}) + statuses, _, err = git_model.GetLatestCommitStatus(ctx, pr.BaseRepo.ID, sha, db.ListOptionsAll) lastStatus = git_model.CalcCommitStatus(statuses) return statuses, lastStatus, err } diff --git a/services/pull/review.go b/services/pull/review.go index 8900ae2ab14a9..de1021c5c0c84 100644 --- a/services/pull/review.go +++ b/services/pull/review.go @@ -52,9 +52,7 @@ func InvalidateCodeComments(ctx context.Context, prs issues_model.PullRequestLis issueIDs := prs.GetIssueIDs() codeComments, err := db.Find[issues_model.Comment](ctx, issues_model.FindCommentsOptions{ - ListOptions: db.ListOptions{ - ListAll: true, - }, + ListOptions: db.ListOptionsAll, Type: issues_model.CommentTypeCode, Invalidated: optional.Some(false), IssueIDs: issueIDs, @@ -322,12 +320,10 @@ func SubmitReview(ctx context.Context, doer *user_model.User, gitRepo *git.Repos // DismissApprovalReviews dismiss all approval reviews because of new commits func DismissApprovalReviews(ctx context.Context, doer *user_model.User, pull *issues_model.PullRequest) error { reviews, err := issues_model.FindReviews(ctx, issues_model.FindReviewOptions{ - ListOptions: db.ListOptions{ - ListAll: true, - }, - IssueID: pull.IssueID, - Type: issues_model.ReviewTypeApprove, - Dismissed: optional.Some(false), + ListOptions: db.ListOptionsAll, + IssueID: pull.IssueID, + Type: issues_model.ReviewTypeApprove, + Dismissed: optional.Some(false), }) if err != nil { return err diff --git a/services/repository/adopt.go b/services/repository/adopt.go index 0ac3c774b7ae9..b337eac38ac38 100644 --- a/services/repository/adopt.go +++ b/services/repository/adopt.go @@ -144,10 +144,8 @@ func adoptRepository(ctx context.Context, repoPath string, u *user_model.User, r } branches, _ := git_model.FindBranchNames(ctx, git_model.FindBranchOptions{ - RepoID: repo.ID, - ListOptions: db.ListOptions{ - ListAll: true, - }, + RepoID: repo.ID, + ListOptions: db.ListOptionsAll, IsDeletedBranch: optional.Some(false), }) diff --git a/tailwind.config.js b/tailwind.config.js index e2e8f23656263..0754ab363189d 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -66,5 +66,30 @@ export default { '3xl': '24px', 'full': 'var(--border-radius-circle)', // 50% }, + fontWeight: { + light: 'var(--font-weight-light)', + normal: 'var(--font-weight-normal)', + medium: 'var(--font-weight-medium)', + semibold: 'var(--font-weight-semibold)', + bold: 'var(--font-weight-bold)', + }, + fontSize: { // not using `rem` units because our root is currently 14px + 'xs': '12px', + 'sm': '14px', + 'base': '16px', + 'lg': '18px', + 'xl': '20px', + '2xl': '24px', + '3xl': '30px', + '4xl': '36px', + '5xl': '48px', + '6xl': '60px', + '7xl': '72px', + '8xl': '96px', + '9xl': '128px', + ...Object.fromEntries(Array.from({length: 100}, (_, i) => { + return [`${i}`, `${i === 0 ? '0' : `${i}px`}`]; + })), + }, }, }; diff --git a/templates/admin/emails/list.tmpl b/templates/admin/emails/list.tmpl index 660df55999ebf..b72aef8f35d43 100644 --- a/templates/admin/emails/list.tmpl +++ b/templates/admin/emails/list.tmpl @@ -4,8 +4,8 @@ {{ctx.Locale.Tr "admin.emails.email_manage_panel"}} ({{ctx.Locale.Tr "admin.total" .Total}}){Attention}
` + tmpl = strings.ReplaceAll(tmpl, "{attention}", attention) + tmpl = strings.ReplaceAll(tmpl, "{icon}", icon) + tmpl = strings.ReplaceAll(tmpl, "{Attention}", cases.Title(language.English).String(attention)) + return tmpl + } + + test := func(input, expected string) { + result, err := markdown.RenderString(&markup.RenderContext{Ctx: context.Background()}, input) + assert.NoError(t, err) + assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(result))) + } + + test(` +> [!NOTE] +> text +`, renderAttention("note", "octicon-info")+"\ntext
\n