Compare commits

...

4 Commits

Author SHA1 Message Date
Yarden Shoham
e17dfce61b Upgrade htmx to 2.0.6 (#34887)
Some checks failed
release-nightly / nightly-binary (push) Has been cancelled
release-nightly / nightly-docker-rootful (push) Has been cancelled
release-nightly / nightly-docker-rootless (push) Has been cancelled
cron-translations / crowdin-pull (push) Has been cancelled
Release notes:
https://github.com/bigskysoftware/htmx/releases/tag/v2.0.6

Tested Star, Watch, and the admin dashboard page. All functionality
remains unchanged.

Signed-off-by: Yarden Shoham <git@yardenshoham.com>
2025-06-27 15:21:52 -04:00
Kerwin Bryant
69fc5619c4 Optimize flex layout of release attachment area (#34885)
before:

![b975dce7-d5b1-43e0-b6f4-94557758e30e](https://github.com/user-attachments/assets/c33f3fd0-ce1a-457c-97fe-942b86cf09c1)

after:

![682ce03c-9d2c-4b5d-9ba0-fb759fd98088](https://github.com/user-attachments/assets/55304b19-a3c3-4a91-b07a-0c9868dbe3eb)
2025-06-27 16:45:39 +00:00
silverwind
1e50cec0b3 Improve labels-list rendering (#34846)
Make labels list use consistent gap

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-06-27 23:12:25 +08:00
TheFox0x7
aa9d86745a enforce explanation for necessary nolints and fix bugs (#34883)
Follows up https://github.com/go-gitea/gitea/pull/34851

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-06-27 21:48:03 +08:00
71 changed files with 279 additions and 281 deletions

View File

@@ -46,7 +46,8 @@ linters:
- pkg: gitea.com/go-chi/cache
desc: do not use the go-chi cache package, use gitea's cache system
nolintlint:
# require-explanation: true
allow-unused: false
require-explanation: true
require-specific: true
gocritic:
disabled-checks:

View File

@@ -295,16 +295,14 @@ func collectAssetFilesByPattern(c *cli.Command, globs []glob.Glob, path string,
}
}
func compileCollectPatterns(args []string) ([]glob.Glob, error) {
func compileCollectPatterns(args []string) (_ []glob.Glob, err error) {
if len(args) == 0 {
args = []string{"**"}
}
pat := make([]glob.Glob, len(args))
for i := range args {
if g, err := glob.Compile(args[i], '/'); err != nil {
return nil, fmt.Errorf("'%s': Invalid glob pattern: %w", args[i], err)
} else { //nolint:revive
pat[i] = g
if pat[i], err = glob.Compile(args[i], '/'); err != nil {
return nil, fmt.Errorf("invalid glob patterh %q: %w", args[i], err)
}
}
return pat, nil

View File

@@ -1,7 +1,7 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
//nolint:forbidigo
//nolint:forbidigo // use of print functions is allowed in cli
package main
import (

View File

@@ -278,14 +278,13 @@ func CreateTaskForRunner(ctx context.Context, runner *ActionRunner) (*ActionTask
return nil, false, err
}
var workflowJob *jobparser.Job
if gots, err := jobparser.Parse(job.WorkflowPayload); err != nil {
parsedWorkflows, err := jobparser.Parse(job.WorkflowPayload)
if err != nil {
return nil, false, fmt.Errorf("parse workflow of job %d: %w", job.ID, err)
} else if len(gots) != 1 {
} else if len(parsedWorkflows) != 1 {
return nil, false, fmt.Errorf("workflow of job %d: not single workflow", job.ID)
} else { //nolint:revive
_, workflowJob = gots[0].Job()
}
_, workflowJob := parsedWorkflows[0].Job()
if _, err := e.Insert(task); err != nil {
return nil, false, err

View File

@@ -15,7 +15,7 @@ import (
var ErrAuthTokenNotExist = util.NewNotExistErrorf("auth token does not exist")
type AuthToken struct { //nolint:revive
type AuthToken struct { //nolint:revive // export stutter
ID string `xorm:"pk"`
TokenHash string
UserID int64 `xorm:"INDEX"`

View File

@@ -39,7 +39,7 @@ func (d *postgresSchemaDriver) Open(name string) (driver.Conn, error) {
// golangci lint is incorrect here - there is no benefit to using driver.ExecerContext here
// and in any case pq does not implement it
if execer, ok := conn.(driver.Execer); ok { //nolint:staticcheck
if execer, ok := conn.(driver.Execer); ok { //nolint:staticcheck // see above
_, err := execer.Exec(`SELECT set_config(
'search_path',
$1 || ',' || current_setting('search_path'),
@@ -64,7 +64,7 @@ func (d *postgresSchemaDriver) Open(name string) (driver.Conn, error) {
// driver.String.ConvertValue will never return err for string
// golangci lint is incorrect here - there is no benefit to using stmt.ExecWithContext here
_, err = stmt.Exec([]driver.Value{schemaValue}) //nolint:staticcheck
_, err = stmt.Exec([]driver.Value{schemaValue}) //nolint:staticcheck // see above
if err != nil {
_ = conn.Close()
return nil, err

View File

@@ -1,7 +1,6 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
//nolint:forbidigo
package base
import (
@@ -106,7 +105,7 @@ func MainTest(m *testing.M) {
giteaConf := os.Getenv("GITEA_CONF")
if giteaConf == "" {
giteaConf = filepath.Join(filepath.Dir(setting.AppPath), "tests/sqlite.ini")
fmt.Printf("Environment variable $GITEA_CONF not set - defaulting to %s\n", giteaConf)
_, _ = fmt.Fprintf(os.Stderr, "Environment variable $GITEA_CONF not set - defaulting to %s\n", giteaConf)
}
if !filepath.IsAbs(giteaConf) {
@@ -134,7 +133,7 @@ func MainTest(m *testing.M) {
exitStatus := m.Run()
if err := removeAllWithRetry(setting.RepoRootPath); err != nil {
fmt.Fprintf(os.Stderr, "os.RemoveAll: %v\n", err)
_, _ = fmt.Fprintf(os.Stderr, "os.RemoveAll: %v\n", err)
}
os.Exit(exitStatus)
}

View File

@@ -4,9 +4,9 @@
package v1_11
import (
"fmt"
"path/filepath"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
@@ -31,7 +31,7 @@ func RemoveAttachmentMissedRepo(x *xorm.Engine) error {
for i := 0; i < len(attachments); i++ {
uuid := attachments[i].UUID
if err = util.RemoveAll(filepath.Join(setting.Attachment.Storage.Path, uuid[0:1], uuid[1:2], uuid)); err != nil {
fmt.Printf("Error: %v", err) //nolint:forbidigo
log.Warn("Unable to remove attachment file by UUID %s: %v", uuid, err)
}
}

View File

@@ -21,12 +21,7 @@ func FixLanguageStatsToSaveSize(x *xorm.Engine) error {
// RepoIndexerType specifies the repository indexer type
type RepoIndexerType int
const (
// RepoIndexerTypeCode code indexer - 0
RepoIndexerTypeCode RepoIndexerType = iota //nolint:unused
// RepoIndexerTypeStats repository stats indexer - 1
RepoIndexerTypeStats
)
const RepoIndexerTypeStats RepoIndexerType = 1
// RepoIndexerStatus see models/repo_indexer.go
type RepoIndexerStatus struct {

View File

@@ -8,17 +8,6 @@ import (
)
func FixRepoTopics(x *xorm.Engine) error {
type Topic struct { //nolint:unused
ID int64 `xorm:"pk autoincr"`
Name string `xorm:"UNIQUE VARCHAR(25)"`
RepoCount int
}
type RepoTopic struct { //nolint:unused
RepoID int64 `xorm:"pk"`
TopicID int64 `xorm:"pk"`
}
type Repository struct {
ID int64 `xorm:"pk autoincr"`
Topics []string `xorm:"TEXT JSON"`

View File

@@ -16,10 +16,7 @@ func ConvertHookTaskTypeToVarcharAndTrim(x *xorm.Engine) error {
return nil
}
type HookTask struct { //nolint:unused
Typ string `xorm:"VARCHAR(16) index"`
}
// HookTask: Typ string `xorm:"VARCHAR(16) index"`
if err := base.ModifyColumn(x, "hook_task", &schemas.Column{
Name: "typ",
SQLType: schemas.SQLType{
@@ -42,10 +39,7 @@ func ConvertHookTaskTypeToVarcharAndTrim(x *xorm.Engine) error {
return err
}
type Webhook struct { //nolint:unused
Type string `xorm:"VARCHAR(16) index"`
}
// Webhook: Type string `xorm:"VARCHAR(16) index"`
if err := base.ModifyColumn(x, "webhook", &schemas.Column{
Name: "type",
SQLType: schemas.SQLType{

View File

@@ -19,7 +19,7 @@ type Badge struct {
}
// UserBadge represents a user badge
type UserBadge struct { //nolint:revive
type UserBadge struct { //nolint:revive // export stutter
ID int64 `xorm:"pk autoincr"`
BadgeID int64
UserID int64 `xorm:"INDEX"`

View File

@@ -18,7 +18,7 @@ func parseIntParam(value, param, algorithmName, config string, previousErr error
return parsed, previousErr // <- Keep the previous error as this function should still return an error once everything has been checked if any call failed
}
func parseUIntParam(value, param, algorithmName, config string, previousErr error) (uint64, error) { //nolint:unparam
func parseUIntParam(value, param, algorithmName, config string, previousErr error) (uint64, error) { //nolint:unparam // algorithmName is always argon2
parsed, err := strconv.ParseUint(value, 10, 64)
if err != nil {
log.Error("invalid integer for %s representation in %s hash spec %s", param, algorithmName, config)

View File

@@ -11,7 +11,7 @@ import (
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/nosql"
"gitea.com/go-chi/cache" //nolint:depguard
"gitea.com/go-chi/cache" //nolint:depguard // we wrap this package here
"github.com/redis/go-redis/v9"
)

View File

@@ -10,7 +10,7 @@ import (
"code.gitea.io/gitea/modules/json"
mc "gitea.com/go-chi/cache" //nolint:depguard
mc "gitea.com/go-chi/cache" //nolint:depguard // we wrap this package here
lru "github.com/hashicorp/golang-lru/v2"
)

View File

@@ -11,7 +11,7 @@ import (
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
chi_cache "gitea.com/go-chi/cache" //nolint:depguard
chi_cache "gitea.com/go-chi/cache" //nolint:depguard // we wrap this package here
)
type GetJSONError struct {

View File

@@ -41,8 +41,7 @@ func (g *Manager) start() {
// Make SVC process
run := svc.Run
//lint:ignore SA1019 We use IsAnInteractiveSession because IsWindowsService has a different permissions profile
isAnInteractiveSession, err := svc.IsAnInteractiveSession() //nolint:staticcheck
isAnInteractiveSession, err := svc.IsAnInteractiveSession() //nolint:staticcheck // must use IsAnInteractiveSession because IsWindowsService has a different permissions profile
if err != nil {
log.Error("Unable to ascertain if running as an Windows Service: %v", err)
return

View File

@@ -42,6 +42,8 @@ func HTMLFormat(s template.HTML, rawArgs ...any) template.HTML {
// for most basic types (including template.HTML which is safe), just do nothing and use it
case string:
args[i] = template.HTMLEscapeString(v)
case template.URL:
args[i] = template.HTMLEscapeString(string(v))
case fmt.Stringer:
args[i] = template.HTMLEscapeString(v.String())
default:

View File

@@ -10,6 +10,15 @@ import (
"github.com/stretchr/testify/assert"
)
type testStringer struct{}
func (t testStringer) String() string {
return "&StringMethod"
}
func TestHTMLFormat(t *testing.T) {
assert.Equal(t, template.HTML("<a>&lt; < 1</a>"), HTMLFormat("<a>%s %s %d</a>", "<", template.HTML("<"), 1))
assert.Equal(t, template.HTML("%!s(<nil>)"), HTMLFormat("%s", nil))
assert.Equal(t, template.HTML("&lt;&gt;"), HTMLFormat("%s", template.URL("<>")))
assert.Equal(t, template.HTML("&amp;StringMethod &amp;StringMethod"), HTMLFormat("%s %s", testStringer{}, &testStringer{}))
}

View File

@@ -3,11 +3,10 @@
package json
// Allow "encoding/json" import.
import (
"bytes"
"encoding/binary"
"encoding/json" //nolint:depguard
"encoding/json" //nolint:depguard // this package wraps it
"io"
jsoniter "github.com/json-iterator/go"

View File

@@ -45,6 +45,6 @@ type Logger interface {
LevelLogger
}
type LogStringer interface { //nolint:revive
type LogStringer interface { //nolint:revive // export stutter
LogString() string
}

View File

@@ -46,7 +46,7 @@ func (g *ASTTransformer) extractBlockquoteAttentionEmphasis(firstParagraph ast.N
if !ok {
return "", nil
}
val1 := string(node1.Text(reader.Source())) //nolint:staticcheck
val1 := string(node1.Text(reader.Source())) //nolint:staticcheck // Text is deprecated
attentionType := strings.ToLower(val1)
if g.attentionTypes.Contains(attentionType) {
return attentionType, []ast.Node{node1}

View File

@@ -68,7 +68,7 @@ func cssColorHandler(value string) bool {
}
func (g *ASTTransformer) transformCodeSpan(_ *markup.RenderContext, v *ast.CodeSpan, reader text.Reader) {
colorContent := v.Text(reader.Source()) //nolint:staticcheck
colorContent := v.Text(reader.Source()) //nolint:staticcheck // Text is deprecated
if cssColorHandler(string(colorContent)) {
v.AppendChild(v, NewColorPreview(colorContent))
}

View File

@@ -19,7 +19,7 @@ func (g *ASTTransformer) transformHeading(_ *markup.RenderContext, v *ast.Headin
v.SetAttribute(attr.Name, fmt.Appendf(nil, "%v", attr.Value))
}
}
txt := v.Text(reader.Source()) //nolint:staticcheck
txt := v.Text(reader.Source()) //nolint:staticcheck // Text is deprecated
header := Header{
Text: util.UnsafeBytesToString(txt),
Level: v.Level,

View File

@@ -46,7 +46,7 @@ func (r *stripRenderer) Render(w io.Writer, source []byte, doc ast.Node) error {
coalesce := prevSibIsText
r.processString(
w,
v.Text(source), //nolint:staticcheck
v.Text(source), //nolint:staticcheck // Text is deprecated
coalesce)
if v.SoftLineBreak() {
r.doubleSpace(w)

View File

@@ -4,7 +4,7 @@
package optional_test
import (
std_json "encoding/json" //nolint:depguard
std_json "encoding/json" //nolint:depguard // for testing purpose
"testing"
"code.gitea.io/gitea/modules/json"

View File

@@ -97,7 +97,7 @@ func decodeEnvSectionKey(encoded string) (ok bool, section, key string) {
// decodeEnvironmentKey decode the environment key to section and key
// The environment key is in the form of GITEA__SECTION__KEY or GITEA__SECTION__KEY__FILE
func decodeEnvironmentKey(prefixGitea, suffixFile, envKey string) (ok bool, section, key string, useFileValue bool) { //nolint:unparam
func decodeEnvironmentKey(prefixGitea, suffixFile, envKey string) (ok bool, section, key string, useFileValue bool) {
if !strings.HasPrefix(envKey, prefixGitea) {
return false, "", "", false
}

View File

@@ -73,6 +73,9 @@ func TestDecodeEnvironmentKey(t *testing.T) {
assert.Equal(t, "sec", section)
assert.Equal(t, "KEY", key)
assert.True(t, file)
ok, _, _, _ = decodeEnvironmentKey("PREFIX__", "", "PREFIX__SEC__KEY")
assert.True(t, ok)
}
func TestEnvironmentToConfig(t *testing.T) {

View File

@@ -15,7 +15,7 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/util"
"gopkg.in/ini.v1" //nolint:depguard
"gopkg.in/ini.v1" //nolint:depguard // wrapper for this package
)
type ConfigKey interface {

View File

@@ -111,7 +111,7 @@ func loadSecurityFrom(rootCfg ConfigProvider) {
if SecretKey == "" {
// FIXME: https://github.com/go-gitea/gitea/issues/16832
// Until it supports rotating an existing secret key, we shouldn't move users off of the widely used default value
SecretKey = "!#@FDEWREWR&*(" //nolint:gosec
SecretKey = "!#@FDEWREWR&*("
}
CookieRememberName = sec.Key("COOKIE_REMEMBER_NAME").MustString("gitea_incredible")

View File

@@ -158,7 +158,7 @@ const (
targetSecIsSec // target section is from the name seciont [name]
)
func getStorageSectionByType(rootCfg ConfigProvider, typ string) (ConfigSection, targetSecType, error) { //nolint:unparam
func getStorageSectionByType(rootCfg ConfigProvider, typ string) (ConfigSection, targetSecType, error) { //nolint:unparam // FIXME: targetSecType is always 0, wrong design?
targetSec, err := rootCfg.GetSection(storageSectionName + "." + typ)
if err != nil {
if !IsValidStorageType(StorageType(typ)) {
@@ -283,7 +283,7 @@ func getStorageForLocal(targetSec, overrideSec ConfigSection, tp targetSecType,
return &storage, nil
}
func getStorageForMinio(targetSec, overrideSec ConfigSection, tp targetSecType, name string) (*Storage, error) { //nolint:dupl
func getStorageForMinio(targetSec, overrideSec ConfigSection, tp targetSecType, name string) (*Storage, error) { //nolint:dupl // duplicates azure setup
var storage Storage
storage.Type = StorageType(targetSec.Key("STORAGE_TYPE").String())
if err := targetSec.MapTo(&storage.MinioConfig); err != nil {
@@ -312,7 +312,7 @@ func getStorageForMinio(targetSec, overrideSec ConfigSection, tp targetSecType,
return &storage, nil
}
func getStorageForAzureBlob(targetSec, overrideSec ConfigSection, tp targetSecType, name string) (*Storage, error) { //nolint:dupl
func getStorageForAzureBlob(targetSec, overrideSec ConfigSection, tp targetSecType, name string) (*Storage, error) { //nolint:dupl // duplicates minio setup
var storage Storage
storage.Type = StorageType(targetSec.Key("STORAGE_TYPE").String())
if err := targetSec.MapTo(&storage.AzureBlobConfig); err != nil {

View File

@@ -42,7 +42,7 @@ var (
var ErrTemplateNotInitialized = errors.New("template system is not initialized, check your log for errors")
func (h *HTMLRender) HTML(w io.Writer, status int, tplName TplName, data any, ctx context.Context) error { //nolint:revive
func (h *HTMLRender) HTML(w io.Writer, status int, tplName TplName, data any, ctx context.Context) error { //nolint:revive // we don't use ctx, only pass it to the template executor
name := string(tplName)
if respWriter, ok := w.(http.ResponseWriter); ok {
if respWriter.Header().Get("Content-Type") == "" {
@@ -57,7 +57,7 @@ func (h *HTMLRender) HTML(w io.Writer, status int, tplName TplName, data any, ct
return t.Execute(w, data)
}
func (h *HTMLRender) TemplateLookup(name string, ctx context.Context) (TemplateExecutor, error) { //nolint:revive
func (h *HTMLRender) TemplateLookup(name string, ctx context.Context) (TemplateExecutor, error) { //nolint:revive // we don't use ctx, only pass it to the template executor
tmpls := h.templates.Load()
if tmpls == nil {
return nil, ErrTemplateNotInitialized

View File

@@ -102,31 +102,28 @@ func escapeTemplate(t *template.Template) error {
return nil
}
//nolint:unused
type htmlTemplate struct {
escapeErr error
text *texttemplate.Template
_/*escapeErr*/ error
text *texttemplate.Template
}
//nolint:unused
type textTemplateCommon struct {
tmpl map[string]*template.Template // Map from name to defined templates.
muTmpl sync.RWMutex // protects tmpl
option struct {
_/*tmpl*/ map[string]*template.Template
_/*muTmpl*/ sync.RWMutex
_/*option*/ struct {
missingKey int
}
muFuncs sync.RWMutex // protects parseFuncs and execFuncs
parseFuncs texttemplate.FuncMap
execFuncs map[string]reflect.Value
muFuncs sync.RWMutex
_/*parseFuncs*/ texttemplate.FuncMap
execFuncs map[string]reflect.Value
}
//nolint:unused
type textTemplate struct {
name string
_/*name*/ string
*parse.Tree
*textTemplateCommon
leftDelim string
rightDelim string
_/*leftDelim*/ string
_/*rightDelim*/ string
}
func ptr[T, P any](ptr *P) *T {

View File

@@ -122,8 +122,23 @@ func (ut *RenderUtils) RenderIssueSimpleTitle(text string) template.HTML {
return ret
}
// RenderLabel renders a label
func (ut *RenderUtils) RenderLabelWithLink(label *issues_model.Label, link any) template.HTML {
var attrHref template.HTML
switch link.(type) {
case template.URL, string:
attrHref = htmlutil.HTMLFormat(`href="%s"`, link)
default:
panic(fmt.Sprintf("unexpected type %T for link", link))
}
return ut.renderLabelWithTag(label, "a", attrHref)
}
func (ut *RenderUtils) RenderLabel(label *issues_model.Label) template.HTML {
return ut.renderLabelWithTag(label, "span", "")
}
// RenderLabel renders a label
func (ut *RenderUtils) renderLabelWithTag(label *issues_model.Label, tagName, tagAttrs template.HTML) template.HTML {
locale := ut.ctx.Value(translation.ContextKey).(translation.Locale)
var extraCSSClasses string
textColor := util.ContrastColor(label.Color)
@@ -137,8 +152,8 @@ func (ut *RenderUtils) RenderLabel(label *issues_model.Label) template.HTML {
if labelScope == "" {
// Regular label
return htmlutil.HTMLFormat(`<div class="ui label %s" style="color: %s !important; background-color: %s !important;" data-tooltip-content title="%s">%s</div>`,
extraCSSClasses, textColor, label.Color, descriptionText, ut.RenderEmoji(label.Name))
return htmlutil.HTMLFormat(`<%s %s class="ui label %s" style="color: %s !important; background-color: %s !important;" data-tooltip-content title="%s"><span class="gt-ellipsis">%s</span></%s>`,
tagName, tagAttrs, extraCSSClasses, textColor, label.Color, descriptionText, ut.RenderEmoji(label.Name), tagName)
}
// Scoped label
@@ -152,7 +167,7 @@ func (ut *RenderUtils) RenderLabel(label *issues_model.Label) template.HTML {
// Ensure we add the same amount of contrast also near 0 and 1.
darken := contrast + math.Max(luminance+contrast-1.0, 0.0)
lighten := contrast + math.Max(contrast-luminance, 0.0)
// Compute factor to keep RGB values proportional.
// Compute the factor to keep RGB values proportional.
darkenFactor := math.Max(luminance-darken, 0.0) / math.Max(luminance, 1.0/255.0)
lightenFactor := math.Min(luminance+lighten, 1.0) / math.Max(luminance, 1.0/255.0)
@@ -173,26 +188,29 @@ func (ut *RenderUtils) RenderLabel(label *issues_model.Label) template.HTML {
if label.ExclusiveOrder > 0 {
// <scope> | <label> | <order>
return htmlutil.HTMLFormat(`<span class="ui label %s scope-parent" data-tooltip-content title="%s">`+
return htmlutil.HTMLFormat(`<%s %s class="ui label %s scope-parent" data-tooltip-content title="%s">`+
`<div class="ui label scope-left" style="color: %s !important; background-color: %s !important">%s</div>`+
`<div class="ui label scope-middle" style="color: %s !important; background-color: %s !important">%s</div>`+
`<div class="ui label scope-right">%d</div>`+
`</span>`,
`</%s>`,
tagName, tagAttrs,
extraCSSClasses, descriptionText,
textColor, scopeColor, scopeHTML,
textColor, itemColor, itemHTML,
label.ExclusiveOrder)
label.ExclusiveOrder,
tagName)
}
// <scope> | <label>
return htmlutil.HTMLFormat(`<span class="ui label %s scope-parent" data-tooltip-content title="%s">`+
return htmlutil.HTMLFormat(`<%s %s class="ui label %s scope-parent" data-tooltip-content title="%s">`+
`<div class="ui label scope-left" style="color: %s !important; background-color: %s !important">%s</div>`+
`<div class="ui label scope-right" style="color: %s !important; background-color: %s !important">%s</div>`+
`</span>`,
`</%s>`,
tagName, tagAttrs,
extraCSSClasses, descriptionText,
textColor, scopeColor, scopeHTML,
textColor, itemColor, itemHTML,
)
tagName)
}
// RenderEmoji renders html text with emoji post processors
@@ -235,7 +253,8 @@ func (ut *RenderUtils) RenderLabels(labels []*issues_model.Label, repoLink strin
if label == nil {
continue
}
htmlCode += fmt.Sprintf(`<a href="%s?labels=%d">%s</a>`, baseLink, label.ID, ut.RenderLabel(label))
link := fmt.Sprintf("%s?labels=%d", baseLink, label.ID)
htmlCode += string(ut.RenderLabelWithLink(label, template.URL(link)))
}
htmlCode += "</span>"
return template.HTML(htmlCode)

View File

@@ -205,6 +205,17 @@ func TestRenderLabels(t *testing.T) {
issue = &issues.Issue{IsPull: true}
expected = `/owner/repo/pulls?labels=123`
assert.Contains(t, ut.RenderLabels([]*issues.Label{label}, "/owner/repo", issue), expected)
expectedLabel := `<a href="&lt;&gt;" class="ui label " style="color: #fff !important; background-color: label-color !important;" data-tooltip-content title=""><span class="gt-ellipsis">label-name</span></a>`
assert.Equal(t, expectedLabel, string(ut.RenderLabelWithLink(label, "<>")))
assert.Equal(t, expectedLabel, string(ut.RenderLabelWithLink(label, template.URL("<>"))))
label = &issues.Label{ID: 123, Name: "</>", Exclusive: true}
expectedLabel = `<a href="" class="ui label scope-parent" data-tooltip-content title=""><div class="ui label scope-left" style="color: #fff !important; background-color: #000000 !important">&lt;</div><div class="ui label scope-right" style="color: #fff !important; background-color: #000000 !important">&gt;</div></a>`
assert.Equal(t, expectedLabel, string(ut.RenderLabelWithLink(label, "")))
label = &issues.Label{ID: 123, Name: "</>", Exclusive: true, ExclusiveOrder: 1}
expectedLabel = `<a href="" class="ui label scope-parent" data-tooltip-content title=""><div class="ui label scope-left" style="color: #fff !important; background-color: #000000 !important">&lt;</div><div class="ui label scope-middle" style="color: #fff !important; background-color: #000000 !important">&gt;</div><div class="ui label scope-right">1</div></a>`
assert.Equal(t, expectedLabel, string(ut.RenderLabelWithLink(label, "")))
}
func TestUserMention(t *testing.T) {

8
package-lock.json generated
View File

@@ -30,7 +30,7 @@
"esbuild-loader": "4.3.0",
"escape-goat": "4.0.0",
"fast-glob": "3.3.3",
"htmx.org": "2.0.5",
"htmx.org": "2.0.6",
"idiomorph": "0.7.3",
"jquery": "3.7.1",
"katex": "0.16.22",
@@ -8233,9 +8233,9 @@
}
},
"node_modules/htmx.org": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/htmx.org/-/htmx.org-2.0.5.tgz",
"integrity": "sha512-ocgvtHCShWFW0DvSV1NbJC7Y5EzUMy2eo5zeWvGj2Ac4LOr7sv9YKg4jzCZJdXN21fXACmCViwKSy+cm6i2dWQ==",
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/htmx.org/-/htmx.org-2.0.6.tgz",
"integrity": "sha512-7ythjYneGSk3yCHgtCnQeaoF+D+o7U2LF37WU3O0JYv3gTZSicdEFiI/Ai/NJyC5ZpYJWMpUb11OC5Lr6AfAqA==",
"license": "0BSD"
},
"node_modules/iconv-lite": {

View File

@@ -29,7 +29,7 @@
"esbuild-loader": "4.3.0",
"escape-goat": "4.0.0",
"fast-glob": "3.3.3",
"htmx.org": "2.0.5",
"htmx.org": "2.0.6",
"idiomorph": "0.7.3",
"jquery": "3.7.1",
"katex": "0.16.22",

View File

@@ -43,7 +43,7 @@ func validateRunID(ctx *ArtifactContext) (*actions.ActionTask, int64, bool) {
return task, runID, true
}
func validateRunIDV4(ctx *ArtifactContext, rawRunID string) (*actions.ActionTask, int64, bool) { //nolint:unparam
func validateRunIDV4(ctx *ArtifactContext, rawRunID string) (*actions.ActionTask, int64, bool) { //nolint:unparam // ActionTask is never used
task := ctx.ActionTask
runID, err := strconv.ParseInt(rawRunID, 10, 64)
if err != nil || task.Job.RunID != runID {

View File

@@ -26,7 +26,7 @@ import (
// saveAsPackageBlob creates a package blob from an upload
// The uploaded blob gets stored in a special upload version to link them to the package/image
func saveAsPackageBlob(ctx context.Context, hsr packages_module.HashedSizeReader, pci *packages_service.PackageCreationInfo) (*packages_model.PackageBlob, error) { //nolint:unparam
func saveAsPackageBlob(ctx context.Context, hsr packages_module.HashedSizeReader, pci *packages_service.PackageCreationInfo) (*packages_model.PackageBlob, error) { //nolint:unparam // PackageBlob is never used
pb := packages_service.NewPackageBlob(hsr)
exists := false

View File

@@ -36,7 +36,7 @@ func apiError(ctx *context.Context, status int, obj any) {
})
}
func xmlResponse(ctx *context.Context, status int, obj any) { //nolint:unparam
func xmlResponse(ctx *context.Context, status int, obj any) { //nolint:unparam // status is always StatusOK
ctx.Resp.Header().Set("Content-Type", "application/atom+xml; charset=utf-8")
ctx.Resp.WriteHeader(status)
if _, err := ctx.Resp.Write([]byte(xml.Header)); err != nil {

View File

@@ -42,7 +42,7 @@ func Markup(ctx *context.APIContext) {
return
}
mode := util.Iif(form.Wiki, "wiki", form.Mode) //nolint:staticcheck
mode := util.Iif(form.Wiki, "wiki", form.Mode) //nolint:staticcheck // form.Wiki is deprecated
common.RenderMarkup(ctx.Base, ctx.Repo, mode, form.Text, form.Context, form.FilePath)
}
@@ -73,7 +73,7 @@ func Markdown(ctx *context.APIContext) {
return
}
mode := util.Iif(form.Wiki, "wiki", form.Mode) //nolint:staticcheck
mode := util.Iif(form.Wiki, "wiki", form.Mode) //nolint:staticcheck // form.Wiki is deprecated
common.RenderMarkup(ctx.Base, ctx.Repo, mode, form.Text, form.Context, "")
}

View File

@@ -200,7 +200,7 @@ func ChangeConfig(ctx *context.Context) {
value := ctx.FormString("value")
cfg := setting.Config()
marshalBool := func(v string) (string, error) { //nolint:unparam
marshalBool := func(v string) (string, error) { //nolint:unparam // error is always nil
if b, _ := strconv.ParseBool(v); b {
return "true", nil
}

View File

@@ -15,6 +15,6 @@ import (
// Markup render markup document to HTML
func Markup(ctx *context.Context) {
form := web.GetForm(ctx).(*api.MarkupOption)
mode := util.Iif(form.Wiki, "wiki", form.Mode) //nolint:staticcheck
mode := util.Iif(form.Wiki, "wiki", form.Mode) //nolint:staticcheck // form.Wiki is deprecated
common.RenderMarkup(ctx.Base, ctx.Repo, mode, form.Text, form.Context, form.FilePath)
}

View File

@@ -1031,7 +1031,7 @@ func registerWebRoutes(m *web.Router) {
m.Get("", org.Projects)
m.Get("/{id}", org.ViewProject)
}, reqUnitAccess(unit.TypeProjects, perm.AccessModeRead, true))
m.Group("", func() { //nolint:dupl
m.Group("", func() { //nolint:dupl // duplicates lines 1421-1441
m.Get("/new", org.RenderNewProject)
m.Post("/new", web.Bind(forms.CreateProjectForm{}), org.NewProjectPost)
m.Group("/{id}", func() {
@@ -1418,7 +1418,7 @@ func registerWebRoutes(m *web.Router) {
m.Group("/{username}/{reponame}/projects", func() {
m.Get("", repo.Projects)
m.Get("/{id}", repo.ViewProject)
m.Group("", func() { //nolint:dupl
m.Group("", func() { //nolint:dupl // duplicates lines 1034-1054
m.Get("/new", repo.RenderNewProject)
m.Post("/new", web.Bind(forms.CreateProjectForm{}), repo.NewProjectPost)
m.Group("/{id}", func() {

View File

@@ -33,7 +33,9 @@ import (
"github.com/nektos/act/pkg/model"
)
var methodCtxKey struct{}
type methodCtxKeyType struct{}
var methodCtxKey methodCtxKeyType
// withMethod sets the notification method that this context currently executes.
// Used for debugging/ troubleshooting purposes.
@@ -44,8 +46,7 @@ func withMethod(ctx context.Context, method string) context.Context {
return ctx
}
}
// FIXME: review the use of this nolint directive
return context.WithValue(ctx, methodCtxKey, method) //nolint:staticcheck
return context.WithValue(ctx, methodCtxKey, method)
}
// getMethod gets the notification method that this context currently executes.

View File

@@ -117,10 +117,10 @@ func dial(source *Source) (*ldap.Conn, error) {
}
if source.SecurityProtocol == SecurityProtocolLDAPS {
return ldap.DialTLS("tcp", net.JoinHostPort(source.Host, strconv.Itoa(source.Port)), tlsConfig) //nolint:staticcheck
return ldap.DialTLS("tcp", net.JoinHostPort(source.Host, strconv.Itoa(source.Port)), tlsConfig) //nolint:staticcheck // DialTLS is deprecated
}
conn, err := ldap.Dial("tcp", net.JoinHostPort(source.Host, strconv.Itoa(source.Port))) //nolint:staticcheck
conn, err := ldap.Dial("tcp", net.JoinHostPort(source.Host, strconv.Itoa(source.Port))) //nolint:staticcheck // Dial is deprecated
if err != nil {
return nil, fmt.Errorf("error during Dial: %w", err)
}

View File

@@ -99,15 +99,14 @@ func checkConfigurationFiles(ctx context.Context, logger log.Logger, autofix boo
func isWritableDir(path string) error {
// There's no platform-independent way of checking if a directory is writable
// https://stackoverflow.com/questions/20026320/how-to-tell-if-folder-exists-and-is-writable
tmpFile, err := os.CreateTemp(path, "doctors-order")
if err != nil {
return err
}
if err := os.Remove(tmpFile.Name()); err != nil {
fmt.Printf("Warning: can't remove temporary file: '%s'\n", tmpFile.Name()) //nolint:forbidigo
log.Warn("can't remove temporary file: %q", tmpFile.Name())
}
tmpFile.Close()
_ = tmpFile.Close()
return nil
}

View File

@@ -214,51 +214,6 @@ func (diffSection *DiffSection) GetLine(idx int) *DiffLine {
return diffSection.Lines[idx]
}
// GetLine gets a specific line by type (add or del) and file line number
// This algorithm is not quite right.
// Actually now we have "Match" field, it is always right, so use it instead in new GetLine
func (diffSection *DiffSection) getLineLegacy(lineType DiffLineType, idx int) *DiffLine { //nolint:unused
var (
difference = 0
addCount = 0
delCount = 0
matchDiffLine *DiffLine
)
LOOP:
for _, diffLine := range diffSection.Lines {
switch diffLine.Type {
case DiffLineAdd:
addCount++
case DiffLineDel:
delCount++
default:
if matchDiffLine != nil {
break LOOP
}
difference = diffLine.RightIdx - diffLine.LeftIdx
addCount = 0
delCount = 0
}
switch lineType {
case DiffLineDel:
if diffLine.RightIdx == 0 && diffLine.LeftIdx == idx-difference {
matchDiffLine = diffLine
}
case DiffLineAdd:
if diffLine.LeftIdx == 0 && diffLine.RightIdx == idx+difference {
matchDiffLine = diffLine
}
}
}
if addCount == delCount {
return matchDiffLine
}
return nil
}
func defaultDiffMatchPatch() *diffmatchpatch.DiffMatchPatch {
dmp := diffmatchpatch.New()
dmp.DiffEditCost = 100
@@ -1348,15 +1303,14 @@ func SyncUserSpecificDiff(ctx context.Context, userID int64, pull *issues_model.
latestCommit = pull.HeadBranch // opts.AfterCommitID is preferred because it handles PRs from forks correctly and the branch name doesn't
}
changedFiles, err := gitRepo.GetFilesChangedBetween(review.CommitSHA, latestCommit)
changedFiles, errIgnored := gitRepo.GetFilesChangedBetween(review.CommitSHA, latestCommit)
// There are way too many possible errors.
// Examples are various git errors such as the commit the review was based on was gc'ed and hence doesn't exist anymore as well as unrecoverable errors where we should serve a 500 response
// Due to the current architecture and physical limitation of needing to compare explicit error messages, we can only choose one approach without the code getting ugly
// For SOME of the errors such as the gc'ed commit, it would be best to mark all files as changed
// But as that does not work for all potential errors, we simply mark all files as unchanged and drop the error which always works, even if not as good as possible
if err != nil {
if errIgnored != nil {
log.Error("Could not get changed files between %s and %s for pull request %d in repo with path %s. Assuming no changes. Error: %w", review.CommitSHA, latestCommit, pull.Index, gitRepo.Path, err)
err = nil //nolint:ineffassign,wastedassign
}
filesChangedSinceLastDiff := make(map[string]pull_model.ViewedState)

View File

@@ -75,11 +75,9 @@ func IsMigrateURLAllowed(remoteURL string, doer *user_model.User) error {
return &git.ErrInvalidCloneAddr{Host: u.Host, IsProtocolInvalid: true, IsPermissionDenied: true, IsURLError: true}
}
hostName, _, err := net.SplitHostPort(u.Host)
if err != nil {
// u.Host can be "host" or "host:port"
err = nil //nolint:ineffassign,wastedassign
hostName = u.Host
hostName, _, errIgnored := net.SplitHostPort(u.Host)
if errIgnored != nil {
hostName = u.Host // u.Host can be "host" or "host:port"
}
// some users only use proxy, there is no DNS resolver. it's safe to ignore the LookupIP error

View File

@@ -470,7 +470,7 @@ func buildPrimary(ctx context.Context, pv *packages_model.PackageVersion, pfs []
}
// https://docs.pulpproject.org/en/2.19/plugins/pulp_rpm/tech-reference/rpm.html#filelists-xml
func buildFilelists(ctx context.Context, pv *packages_model.PackageVersion, pfs []*packages_model.PackageFile, c packageCache, group string) (*repoData, error) { //nolint:dupl
func buildFilelists(ctx context.Context, pv *packages_model.PackageVersion, pfs []*packages_model.PackageFile, c packageCache, group string) (*repoData, error) { //nolint:dupl // duplicates with buildOther
type Version struct {
Epoch string `xml:"epoch,attr"`
Version string `xml:"ver,attr"`
@@ -517,7 +517,7 @@ func buildFilelists(ctx context.Context, pv *packages_model.PackageVersion, pfs
}
// https://docs.pulpproject.org/en/2.19/plugins/pulp_rpm/tech-reference/rpm.html#other-xml
func buildOther(ctx context.Context, pv *packages_model.PackageVersion, pfs []*packages_model.PackageFile, c packageCache, group string) (*repoData, error) { //nolint:dupl
func buildOther(ctx context.Context, pv *packages_model.PackageVersion, pfs []*packages_model.PackageFile, c packageCache, group string) (*repoData, error) { //nolint:dupl // duplicates with buildFilelists
type Version struct {
Epoch string `xml:"epoch,attr"`
Version string `xml:"ver,attr"`

View File

@@ -325,7 +325,7 @@ func handleCloseCrossReferences(ctx context.Context, pr *issues_model.PullReques
}
// doMergeAndPush performs the merge operation without changing any pull information in database and pushes it up to the base repository
func doMergeAndPush(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.User, mergeStyle repo_model.MergeStyle, expectedHeadCommitID, message string, pushTrigger repo_module.PushTrigger) (string, error) { //nolint:unparam
func doMergeAndPush(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.User, mergeStyle repo_model.MergeStyle, expectedHeadCommitID, message string, pushTrigger repo_module.PushTrigger) (string, error) { //nolint:unparam // non-error result is never used
// Clone base repo.
mergeCtx, cancel, err := createTemporaryRepoForMerge(ctx, pr, doer, expectedHeadCommitID)
if err != nil {

View File

@@ -10,8 +10,8 @@
</a>
</div>
<div class="flex-item">
<div class="flex-item-icon">
{{svg "octicon-tag" 16}}
<div class="flex-item-leading">
<div class="tw-mt-1">{{svg "octicon-tag" 16}}</div>
</div>
<div class="flex-item-main">
<div class="flex-item-header">

View File

@@ -63,16 +63,21 @@
{{if or .Labels .Assignees}}
<div class="issue-card-bottom">
<div class="labels-list">
{{range .Labels}}
<a target="_blank" href="{{$.Issue.Repo.Link}}/issues?labels={{.ID}}">{{ctx.RenderUtils.RenderLabel .}}</a>
{{/* the labels container must always be present, to help the assignees list right-aligned */}}
<div class="issue-card-bottom-part labels-list">
{{range $label := .Labels}}
{{$link := print $.Issue.Repo.Link "/issues"}}
{{$link = QueryBuild $link "labels" $label.ID}}
{{ctx.RenderUtils.RenderLabelWithLink $label $link}}
{{end}}
</div>
<div class="issue-card-assignees">
{{if .Assignees}}
<div class="issue-card-bottom-part tw-justify-end">
{{range .Assignees}}
<a target="_blank" href="{{.HomeLink}}" data-tooltip-content="{{ctx.Locale.Tr "repo.projects.column.assigned_to"}} {{.Name}}">{{ctx.AvatarUtils.Avatar . 28}}</a>
<a target="_blank" href="{{.HomeLink}}" data-tooltip-content="{{ctx.Locale.Tr "repo.projects.column.assigned_to"}} {{.Name}}">{{ctx.AvatarUtils.Avatar . 24}}</a>
{{end}}
</div>
{{end}}
</div>
{{end}}
{{end}}

View File

@@ -26,7 +26,7 @@
<div class="divider"></div>
{{end}}
<ul class="issue-label-list">
<ul class="issue-label-list muted-links">
{{$canEditLabel := and (not $.PageIsOrgSettingsLabels) (not $.Repository.IsArchived) (or $.CanWriteIssues $.CanWritePulls)}}
{{$canEditLabel = or $canEditLabel $.PageIsOrgSettingsLabels}}
{{range .Labels}}
@@ -42,9 +42,8 @@
<a class="open-issues" href="{{$.RepoLink}}/issues?labels={{.ID}}">{{svg "octicon-issue-opened"}} {{ctx.Locale.Tr "repo.issues.label_open_issues" .NumOpenIssues}}</a>
{{end}}
</div>
<div class="label-operation tw-flex">
<div class="label-operation">
{{template "repo/issue/labels/label_archived" .}}
<div class="tw-flex tw-ml-auto">
{{if $canEditLabel}}
<a class="edit-label-button" href="#"
data-label-id="{{.ID}}" data-label-name="{{.Name}}" data-label-color="{{.Color}}"
@@ -57,7 +56,6 @@
data-modal-confirm-content="{{ctx.Locale.Tr "repo.issues.label_deletion_desc"}}"
>{{svg "octicon-trash"}} {{ctx.Locale.Tr "repo.issues.label_delete"}}</a>
{{end}}
</div>
</div>
</li>
{{end}}

View File

@@ -27,7 +27,7 @@
</div>
</div>
</div>
<div class="ui list muted-links flex-items-block tw-flex tw-flex-col tw-gap-2">
<div class="ui relaxed list muted-links flex-items-block">
<span class="item empty-list {{if $issueAssignees}}tw-hidden{{end}}">{{ctx.Locale.Tr "repo.issues.new.no_assignees"}}</span>
{{range $issueAssignees}}
<a class="item" href="{{$pageMeta.RepoLink}}/{{if $pageMeta.IsPullRequest}}pulls{{else}}issues{{end}}?assignee={{.ID}}">

View File

@@ -43,7 +43,7 @@
</div>
</div>
<div class="ui list labels-list tw-my-2 tw-flex tw-gap-2">
<div class="ui list labels-list">
<span class="item empty-list {{if $data.SelectedLabelIDs}}tw-hidden{{end}}">{{ctx.Locale.Tr "repo.issues.new.no_label"}}</span>
{{range $data.AllLabels}}
{{if .IsChecked}}

View File

@@ -43,7 +43,7 @@
</div>
</div>
<div class="ui relaxed list flex-items-block tw-my-4">
<div class="ui relaxed list flex-items-block">
<span class="item empty-list {{if or $data.OriginalReviews $data.CurrentPullReviewers}}tw-hidden{{end}}">
{{ctx.Locale.Tr "repo.issues.new.no_reviewers"}}
</span>

View File

@@ -169,7 +169,7 @@
</div>
{{else if eq .Type 7}}
{{if or .AddedLabels .RemovedLabels}}
<div class="timeline-item event" id="{{.HashTag}}">
<div class="timeline-item event with-labels-list-inline" id="{{.HashTag}}">
<span class="badge">{{svg "octicon-tag"}}</span>
{{template "shared/user/avatarlink" dict "user" .Poster}}
<span class="text grey muted-links">

View File

@@ -92,7 +92,7 @@
{{end}}
{{range $att := $release.Attachments}}
<li class="item">
<a target="_blank" class="tw-flex-grow-[2] gt-ellipsis" rel="nofollow" download href="{{$att.DownloadURL}}">
<a target="_blank" class="tw-flex-1 gt-ellipsis" rel="nofollow" download href="{{$att.DownloadURL}}">
<strong class="flex-text-inline">{{svg "octicon-package" 16 "download-icon"}}<span class="gt-ellipsis">{{$att.Name}}</span></strong>
</a>
<div class="attachment-right-info flex-text-inline">

View File

@@ -3,11 +3,14 @@
{{range .Issues}}
<div class="flex-item">
<div class="flex-item-icon">
{{if $.CanWriteIssuesOrPulls}}
<input type="checkbox" autocomplete="off" class="issue-checkbox tw-mr-4" data-issue-id={{.ID}} aria-label="{{ctx.Locale.Tr "repo.issues.action_check"}} &quot;{{.Title}}&quot;">
{{end}}
{{template "shared/issueicon" .}}
<div class="flex-item-leading">
{{/* using some tw helpers is the only way to align the checkbox */}}
<div class="flex-text-inline tw-mt-[2px]">
{{if $.CanWriteIssuesOrPulls}}
<input type="checkbox" autocomplete="off" class="issue-checkbox tw-mr-[14px]" data-issue-id={{.ID}} aria-label="{{ctx.Locale.Tr "repo.issues.action_check"}} &quot;{{.Title}}&quot;">
{{end}}
{{template "shared/issueicon" .}}
</div>
</div>
<div class="flex-item-main">
@@ -19,7 +22,7 @@
{{template "repo/commit_statuses" dict "Status" (index $.CommitLastStatus .PullRequest.ID) "Statuses" (index $.CommitStatuses .PullRequest.ID)}}
{{end}}
{{end}}
<span class="labels-list tw-ml-1">
<span class="labels-list">
{{range .Labels}}
<a href="?q={{$.Keyword}}&type={{$.ViewType}}&state={{$.State}}&labels={{.ID}}{{if ne $.listType "milestone"}}&milestone={{$.MilestoneID}}{{end}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.RenderUtils.RenderLabel .}}</a>
{{end}}
@@ -32,7 +35,7 @@
</div>
{{end}}
</div>
<div class="flex-item-body">
<div class="flex-item-body tw-mt-1">
<a class="index" href="{{if .Link}}{{.Link}}{{else}}{{$.Link}}/{{.Index}}{{end}}">
{{if eq $.listType "dashboard"}}
{{.Repo.FullName}}#{{.Index}}

View File

@@ -4,7 +4,7 @@
// This is primarily coped from /tests/integration/integration_test.go
// TODO: Move common functions to shared file
//nolint:forbidigo
//nolint:forbidigo // use of print functions is allowed in tests
package e2e
import (

View File

@@ -1,7 +1,7 @@
// Copyright 2017 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
//nolint:forbidigo
//nolint:forbidigo // use of print functions is allowed in tests
package integration
import (

View File

@@ -1,7 +1,6 @@
// Copyright 2017 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
//nolint:forbidigo
package tests
import (
@@ -55,7 +54,7 @@ func InitTest(requireGitea bool) {
// Notice: when doing "ssh push", Gitea executes sub processes, debugger won't work for the sub processes.
giteaConf = "tests/sqlite.ini"
_ = os.Setenv("GITEA_CONF", giteaConf)
fmt.Printf("Environment variable $GITEA_CONF not set, use default: %s\n", giteaConf)
_, _ = fmt.Fprintf(os.Stderr, "Environment variable $GITEA_CONF not set - defaulting to %s\n", giteaConf)
if !setting.EnableSQLite3 {
testlogger.Fatalf(`sqlite3 requires: -tags sqlite,sqlite_unlock_notify` + "\n")
}

View File

@@ -34,6 +34,11 @@
/* z-index */
--z-index-modal: 1001; /* modal dialog, hard-coded from Fomantic modal.css */
--z-index-toast: 1002; /* should be larger than modal */
--font-size-label: 12px; /* font size of individual labels */
--gap-inline: 0.25rem; /* gap for inline texts and elements, for example: the spaces for sentence with labels, button text, etc */
--gap-block: 0.25rem; /* gap for element blocks, for example: spaces between buttons, menu image & title, header icon & title etc */
}
@media (min-width: 768px) and (max-width: 1200px) {
@@ -1093,7 +1098,7 @@ table th[data-sortt-desc] .svg {
.flex-text-inline {
display: inline-flex;
align-items: center;
gap: .25rem;
gap: var(--gap-inline);
vertical-align: middle;
min-width: 0; /* make ellipsis work */
}
@@ -1121,7 +1126,7 @@ table th[data-sortt-desc] .svg {
.flex-text-block {
display: flex;
align-items: center;
gap: .5rem;
gap: var(--gap-block);
min-width: 0;
}
@@ -1136,7 +1141,7 @@ the "!important" is necessary to override Fomantic UI menu item styles, meanwhil
.ui.dropdown .menu.flex-items-menu > .item:not(.hidden, .filtered, .tw-hidden) {
display: flex !important;
align-items: center;
gap: .5rem;
gap: var(--gap-block);
min-width: 0;
}
.ui.dropdown .menu.flex-items-menu > .item img,

View File

@@ -4,25 +4,19 @@
.ui.label {
display: inline-flex;
align-items: center;
gap: .25rem;
gap: var(--gap-inline);
min-width: 0;
vertical-align: middle;
line-height: 1;
max-width: 100%;
background: var(--color-label-bg);
color: var(--color-label-text);
padding: 0.3em 0.5em;
font-size: 0.85714286rem;
padding: 2px 6px;
font-size: var(--font-size-label);
font-weight: var(--font-weight-medium);
border: 0 solid transparent;
border-radius: 0.28571429rem;
border-radius: var(--border-radius);
white-space: nowrap;
}
.ui.label:first-child {
margin-left: 0;
}
.ui.label:last-child {
margin-right: 0;
overflow: hidden;
text-overflow: ellipsis;
}
a.ui.label {
@@ -292,3 +286,58 @@ a.ui.ui.ui.basic.grey.label:hover {
.ui.large.label {
font-size: 1rem;
}
/* To let labels break up and wrap across multiple lines (issue title, comment event), use "display: contents here" to apply parent layout.
If the labels-list itself needs some layouts, use extra classes or "tw" helpers. */
.labels-list {
display: contents;
font-size: var(--font-size-label); /* it must match the label font size, otherwise the height mismatches */
}
.labels-list a {
max-width: 100%; /* for ellipsis */
}
.labels-list .ui.label {
min-height: 20px;
padding-top: 0;
padding-bottom: 0;
}
.with-labels-list-inline .labels-list .ui.label + .ui.label {
margin-left: var(--gap-inline);
}
.with-labels-list-inline .labels-list .ui.label {
line-height: var(--line-height-default);
}
/* Scoped labels with different colors on left and right */
.ui.label.scope-parent {
background: none !important;
padding: 0 !important;
gap: 0 !important;
}
.ui.label.scope-parent > .ui.label {
margin: 0 !important; /* scoped label's margin is handled by the parent */
}
.ui.label.scope-left {
border-bottom-right-radius: 0;
border-top-right-radius: 0;
}
.ui.label.scope-middle {
border-radius: 0;
}
.ui.label.scope-right {
border-bottom-left-radius: 0;
border-top-left-radius: 0;
}
.ui.label.archived-label {
filter: grayscale(0.5);
opacity: 0.5;
}

View File

@@ -5,7 +5,6 @@
list-style-type: none;
margin: 1em 0;
padding: 0;
font-size: 1em;
}
.ui.list:first-child {

View File

@@ -73,10 +73,21 @@
overflow: hidden;
}
.issue-content-right .ui.list {
margin: 0.5em 0;
max-width: 100%;
}
.issue-sidebar-combo > .ui.dropdown .item:not(.checked) .item-check-mark {
visibility: hidden;
}
.issue-content-right .ui.list.labels-list {
display: flex;
gap: var(--gap-inline);
flex-wrap: wrap;
}
@media (max-width: 767.98px) {
.issue-content-left,
.issue-content-right {
@@ -1544,49 +1555,6 @@ td .commit-summary {
border-bottom-right-radius: 4px;
}
.labels-list {
display: inline-flex;
flex-wrap: wrap;
gap: 2.5px;
align-items: center;
}
.labels-list .label, .scope-parent > .label {
padding: 0 6px;
min-height: 20px;
line-height: 1.3; /* there is a `font-size: 1.25em` for inside emoji, so here the line-height needs to be larger slightly */
}
/* Scoped labels with different colors on left and right */
.ui.label.scope-parent {
background: none !important;
padding: 0 !important;
gap: 0 !important;
}
.archived-label {
filter: grayscale(0.5);
opacity: 0.5;
}
.ui.label.scope-left {
border-bottom-right-radius: 0;
border-top-right-radius: 0;
margin-right: 0;
}
.ui.label.scope-middle {
border-radius: 0;
margin-left: 0;
margin-right: 0;
}
.ui.label.scope-right {
border-bottom-left-radius: 0;
border-top-left-radius: 0;
margin-left: 0;
}
.repo-button-row {
margin: 8px 0;
display: flex;

View File

@@ -29,13 +29,16 @@
display: flex;
width: 100%;
justify-content: space-between;
gap: 0.25em;
gap: 1em;
}
.issue-card-assignees {
.issue-card-bottom-part {
display: flex;
flex: 1;
align-items: center;
gap: 0.25em;
justify-content: end;
flex-wrap: wrap;
overflow: hidden;
max-width: fit-content;
max-height: fit-content;
}

View File

@@ -4,41 +4,46 @@
margin: 0;
}
.issue-label-list .item {
.issue-label-list > .item {
border-bottom: 1px solid var(--color-secondary);
display: flex;
padding: 1em 0;
margin: 0;
}
.issue-label-list .item:first-child {
.issue-label-list > .item:first-child {
padding-top: 0;
}
.issue-label-list .item:last-child {
.issue-label-list > .item:last-child {
border-bottom: none;
padding-bottom: 0;
}
.issue-label-list .item .label-title {
.issue-label-list > .item .label-title {
width: 33%;
padding-right: 1em;
}
.issue-label-list .item .label-issues {
.issue-label-list > .item .label-issues {
width: 33%;
padding-right: 1em;
}
.issue-label-list .item .label-operation {
.issue-label-list > .item .label-operation {
width: 33%;
display: flex;
flex-wrap: wrap;
gap: 0.5em;
justify-content: end;
align-items: center;
}
.issue-label-list .item a {
.issue-label-list > .item .label-operation a {
font-size: 12px;
padding-right: 10px;
color: var(--color-text-light);
}
.issue-label-list .item.org-label {
.issue-label-list > .item.org-label {
opacity: 0.7;
}

View File

@@ -70,8 +70,12 @@
flex-wrap: wrap;
}
#release-list .release-entry .attachment-list > .item a {
min-width: 300px;
}
#release-list .release-entry .attachment-list .attachment-right-info {
flex-grow: 1;
flex-shrink: 0;
min-width: 300px;
}

View File

@@ -33,14 +33,6 @@
color: var(--color-primary) !important;
}
.flex-item .flex-item-icon {
align-self: baseline; /* mainly used by the issue list, to align the leading icon with the title */
}
.flex-item .flex-item-icon + .flex-item-main {
align-self: baseline;
}
.flex-item .flex-item-trailing {
display: flex;
gap: 0.5rem;
@@ -54,7 +46,9 @@
display: inline-flex;
flex-wrap: wrap;
align-items: center;
gap: .25rem;
/* labels are under effect of this gap here because they are display:contents. Ideally we should make wrapping
of labels work without display: contents and set this to a static value again. */
gap: var(--gap-inline);
max-width: 100%;
color: var(--color-text);
font-size: 16px;