0
0
mirror of https://github.com/go-gitea/gitea.git synced 2026-05-13 21:56:10 +02:00

Merge branch 'main' into sync_status_handling

This commit is contained in:
pomidorry 2026-05-08 15:47:59 +03:00 committed by GitHub
commit f4a03de9b5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
45 changed files with 462 additions and 269 deletions

View File

@ -71,15 +71,15 @@ jobs:
- "assets/emoji.json" - "assets/emoji.json"
- "package.json" - "package.json"
- "pnpm-lock.yaml" - "pnpm-lock.yaml"
- "pnpm-workspace.yaml"
- "Makefile" - "Makefile"
- ".eslintrc.cjs"
- ".npmrc"
docs: docs:
- "**/*.md" - "**/*.md"
- ".markdownlint.yaml" - ".markdownlint.yaml"
- "package.json" - "package.json"
- "pnpm-lock.yaml" - "pnpm-lock.yaml"
- "pnpm-workspace.yaml"
actions: actions:
- ".github/workflows/*" - ".github/workflows/*"
@ -108,6 +108,7 @@ jobs:
- "Makefile" - "Makefile"
- "package.json" - "package.json"
- "pnpm-lock.yaml" - "pnpm-lock.yaml"
- "pnpm-workspace.yaml"
- ".spectral.yaml" - ".spectral.yaml"
yaml: yaml:

View File

@ -44,7 +44,7 @@ jobs:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
cache: false cache: false
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 - uses: pnpm/action-setup@8912a9102ac27614460f54aedde9e1e7f9aec20d # v6.0.5
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with: with:
node-version: 24 node-version: 24
@ -130,7 +130,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 - uses: pnpm/action-setup@8912a9102ac27614460f54aedde9e1e7f9aec20d # v6.0.5
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with: with:
node-version: 24 node-version: 24

View File

@ -29,7 +29,7 @@ jobs:
with: with:
cache-name: e2e cache-name: e2e
build-cache: "false" build-cache: "false"
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 - uses: pnpm/action-setup@8912a9102ac27614460f54aedde9e1e7f9aec20d # v6.0.5
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with: with:
node-version: 24 node-version: 24

View File

@ -22,7 +22,7 @@ jobs:
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 - uses: pnpm/action-setup@8912a9102ac27614460f54aedde9e1e7f9aec20d # v6.0.5
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with: with:
node-version: 24 node-version: 24

View File

@ -23,7 +23,7 @@ jobs:
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 - uses: pnpm/action-setup@8912a9102ac27614460f54aedde9e1e7f9aec20d # v6.0.5
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with: with:
node-version: 24 node-version: 24

View File

@ -26,7 +26,7 @@ jobs:
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 - uses: pnpm/action-setup@8912a9102ac27614460f54aedde9e1e7f9aec20d # v6.0.5
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with: with:
node-version: 24 node-version: 24

7
.npmrc
View File

@ -1,7 +0,0 @@
audit=false
fund=false
update-notifier=false
save-exact=true
auto-install-peers=true
dedupe-peer-dependents=false
enable-pre-post-scripts=true

View File

@ -195,7 +195,7 @@ PR titles must follow the [Conventional Commits](https://www.conventionalcommits
type(scope)!: subject type(scope)!: subject
``` ```
The allowed types are `build`, `ci`, `docs`, `feat`, `fix`, `perf`, `refactor`, `revert`, `style`, and `test`. The generic `chore` type is intentionally not accepted; pick a more descriptive type instead. The allowed types are `build`, `chore`, `ci`, `docs`, `feat`, `fix`, `perf`, `refactor`, `revert`, `style`, and `test`. The generic `chore` type is intentionally not accepted; pick a more descriptive type instead.
Examples: Examples:

View File

@ -3,7 +3,7 @@
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.26-alpine3.23 AS frontend-build FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.26-alpine3.23 AS frontend-build
RUN apk --no-cache add build-base git nodejs pnpm RUN apk --no-cache add build-base git nodejs pnpm
WORKDIR /src WORKDIR /src
COPY package.json pnpm-lock.yaml .npmrc ./ COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
RUN --mount=type=cache,target=/root/.local/share/pnpm/store pnpm install --frozen-lockfile RUN --mount=type=cache,target=/root/.local/share/pnpm/store pnpm install --frozen-lockfile
COPY --exclude=.git/ . . COPY --exclude=.git/ . .
RUN make frontend RUN make frontend

View File

@ -3,7 +3,7 @@
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.26-alpine3.23 AS frontend-build FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.26-alpine3.23 AS frontend-build
RUN apk --no-cache add build-base git nodejs pnpm RUN apk --no-cache add build-base git nodejs pnpm
WORKDIR /src WORKDIR /src
COPY package.json pnpm-lock.yaml .npmrc ./ COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
RUN --mount=type=cache,target=/root/.local/share/pnpm/store pnpm install --frozen-lockfile RUN --mount=type=cache,target=/root/.local/share/pnpm/store pnpm install --frozen-lockfile
COPY --exclude=.git/ . . COPY --exclude=.git/ . .
RUN make frontend RUN make frontend

View File

@ -11,15 +11,15 @@ COMMA := ,
XGO_VERSION := go-1.26.x XGO_VERSION := go-1.26.x
AIR_PACKAGE ?= github.com/air-verse/air@v1 # renovate: datasource=go AIR_PACKAGE ?= github.com/air-verse/air@v1.65.1 # renovate: datasource=go
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v3/cmd/editorconfig-checker@v3 # renovate: datasource=go EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v3/cmd/editorconfig-checker@v3.6.1 # renovate: datasource=go
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.11.4 # renovate: datasource=go GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.12.2 # renovate: datasource=go
GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.15 # renovate: datasource=go GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.15 # renovate: datasource=go
MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.8.0 # renovate: datasource=go MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.8.0 # renovate: datasource=go
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.33.1 # renovate: datasource=go SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.33.2 # renovate: datasource=go
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest XGO_PACKAGE ?= src.techknowlogick.com/xgo@v1.9.0 # renovate: datasource=go
GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1 # renovate: datasource=go GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1.3.0 # renovate: datasource=go
ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1.7.11 # renovate: datasource=go ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1.7.12 # renovate: datasource=go
HAS_GO := $(shell hash $(GO) > /dev/null 2>&1 && echo yes) HAS_GO := $(shell hash $(GO) > /dev/null 2>&1 && echo yes)
ifeq ($(HAS_GO), yes) ifeq ($(HAS_GO), yes)
@ -613,6 +613,7 @@ update-js: node_modules ## update js dependencies
.PHONY: nolyfill .PHONY: nolyfill
nolyfill: node_modules ## apply nolyfill overrides to package.json and relock nolyfill: node_modules ## apply nolyfill overrides to package.json and relock
pnpm exec nolyfill install pnpm exec nolyfill install
node tools/migrate-nolyfills.ts
pnpm install pnpm install
@touch node_modules @touch node_modules

2
go.mod
View File

@ -1,6 +1,6 @@
module code.gitea.io/gitea module code.gitea.io/gitea
go 1.26.2 go 1.26.3
// rfc5280 said: "The serial number is an integer assigned by the CA to each certificate." // rfc5280 said: "The serial number is an integer assigned by the CA to each certificate."
// But some CAs use negative serial number, just relax the check. related: // But some CAs use negative serial number, just relax the check. related:

View File

@ -100,7 +100,7 @@ var registeredConfigs = map[Type]func() Config{}
// RegisterTypeConfig register a config for a provided type // RegisterTypeConfig register a config for a provided type
func RegisterTypeConfig(typ Type, exemplar Config) { func RegisterTypeConfig(typ Type, exemplar Config) {
if reflect.TypeOf(exemplar).Kind() == reflect.Ptr { if reflect.TypeOf(exemplar).Kind() == reflect.Pointer {
// Pointer: // Pointer:
registeredConfigs[typ] = func() Config { registeredConfigs[typ] = func() Config {
return reflect.New(reflect.ValueOf(exemplar).Elem().Type()).Interface().(Config) return reflect.New(reflect.ValueOf(exemplar).Elem().Type()).Interface().(Config)

View File

@ -17,12 +17,15 @@ import (
"xorm.io/xorm" "xorm.io/xorm"
) )
type engineContextKeyType struct{} type contextKey struct{ key string }
var engineContextKey = engineContextKeyType{} var (
contextKeyEngine = contextKey{"engine"}
ContextKeyTestFixtures = contextKey{"test-fixtures"}
)
func withContextEngine(ctx context.Context, e Engine) context.Context { func withContextEngine(ctx context.Context, e Engine) context.Context {
return context.WithValue(ctx, engineContextKey, e) return context.WithValue(ctx, contextKeyEngine, e)
} }
var ( var (
@ -68,7 +71,7 @@ func contextSafetyCheck(e Engine) {
// GetEngine gets an existing db Engine/Statement or creates a new Session // GetEngine gets an existing db Engine/Statement or creates a new Session
func GetEngine(ctx context.Context) Engine { func GetEngine(ctx context.Context) Engine {
if engine, ok := ctx.Value(engineContextKey).(Engine); ok { if engine, ok := ctx.Value(contextKeyEngine).(Engine); ok {
// if reusing the existing session, need to do "contextSafetyCheck" because the Iterate creates a "autoResetStatement=false" session // if reusing the existing session, need to do "contextSafetyCheck" because the Iterate creates a "autoResetStatement=false" session
contextSafetyCheck(engine) contextSafetyCheck(engine)
return engine return engine
@ -309,7 +312,7 @@ func InTransaction(ctx context.Context) bool {
} }
func getTransactionSession(ctx context.Context) *xorm.Session { func getTransactionSession(ctx context.Context) *xorm.Session {
e, _ := ctx.Value(engineContextKey).(Engine) e, _ := ctx.Value(contextKeyEngine).(Engine)
if sess, ok := e.(*xorm.Session); ok && sess.IsInTx() { if sess, ok := e.(*xorm.Session); ok && sess.IsInTx() {
return sess return sess
} }

View File

@ -22,11 +22,17 @@ type EngineHook struct {
var _ contexts.Hook = (*EngineHook)(nil) var _ contexts.Hook = (*EngineHook)(nil)
func (*EngineHook) BeforeProcess(c *contexts.ContextHook) (context.Context, error) { func (*EngineHook) BeforeProcess(c *contexts.ContextHook) (context.Context, error) {
if c.Ctx.Value(ContextKeyTestFixtures) != nil {
return c.Ctx, nil
}
ctx, _ := gtprof.GetTracer().Start(c.Ctx, gtprof.TraceSpanDatabase) ctx, _ := gtprof.GetTracer().Start(c.Ctx, gtprof.TraceSpanDatabase)
return ctx, nil return ctx, nil
} }
func (h *EngineHook) AfterProcess(c *contexts.ContextHook) error { func (h *EngineHook) AfterProcess(c *contexts.ContextHook) error {
if c.Ctx.Value(ContextKeyTestFixtures) != nil {
return nil
}
span := gtprof.GetContextSpan(c.Ctx) span := gtprof.GetContextSpan(c.Ctx)
if span != nil { if span != nil {
// Do not record SQL parameters here: // Do not record SQL parameters here:

View File

@ -72,7 +72,7 @@ func PrepareTestEnv(t *testing.T, skip int, syncModels ...any) (*xorm.Engine, fu
if err := unittest.InitFixtures( if err := unittest.InitFixtures(
unittest.FixturesOptions{ unittest.FixturesOptions{
Dir: fixturesDir, Dir: fixturesDir,
}, x); err != nil { }); err != nil {
t.Errorf("error whilst initializing fixtures from %s: %v", fixturesDir, err) t.Errorf("error whilst initializing fixtures from %s: %v", fixturesDir, err)
return x, deferFn return x, deferFn
} }
@ -110,6 +110,7 @@ func mainTest(m *testing.M) int {
if err = git.InitFull(); err != nil { if err = git.InitFull(); err != nil {
return testlogger.MainErrorf("Unable to InitFull: %v", err) return testlogger.MainErrorf("Unable to InitFull: %v", err)
} }
setting.Database.SlowQueryThreshold = 0
setting.LoadDBSetting() setting.LoadDBSetting()
setting.InitLoggersForTest() setting.InitLoggersForTest()
return m.Run() return m.Run()

View File

@ -4,7 +4,10 @@
package unittest package unittest
import ( import (
"context"
"fmt" "fmt"
"strings"
"unicode"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/auth/password/hash" "code.gitea.io/gitea/modules/auth/password/hash"
@ -12,11 +15,13 @@ import (
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
"xorm.io/xorm" "xorm.io/xorm"
"xorm.io/xorm/contexts"
"xorm.io/xorm/schemas" "xorm.io/xorm/schemas"
) )
type FixturesLoader interface { type FixturesLoader interface {
Load() error Load() error
MarkTableChanged(tableName string)
} }
var fixturesLoader FixturesLoader var fixturesLoader FixturesLoader
@ -57,15 +62,101 @@ func loadFixtureResetSeqPgsql(e *xorm.Engine) error {
return nil return nil
} }
type fixturesHookStruct struct{}
func cutSpaceForSQL(s string) (string, string, bool) {
s = strings.TrimSpace(s)
pos := strings.IndexFunc(s, unicode.IsSpace)
if pos == -1 {
return s, "", false
}
return s[:pos], strings.TrimSpace(s[pos+1:]), true
}
func trimTableNameQuotes(s string) string {
pos := strings.IndexByte(s, '.')
if pos != -1 {
s = s[pos+1:]
}
return strings.Trim(s, "\"`[]")
}
func (f fixturesHookStruct) BeforeProcess(c *contexts.ContextHook) (context.Context, error) {
if c.Ctx.Value(db.ContextKeyTestFixtures) != nil {
return c.Ctx, nil
}
ctx, sql := c.Ctx, c.SQL
cmdPart, cmdRemaining, ok := cutSpaceForSQL(sql)
if !ok {
return ctx, nil
}
// ignore the SQLs which don't change data
if util.AsciiEqualFold(cmdPart, "SELECT") ||
util.AsciiEqualFold(cmdPart, "SHOW") ||
util.AsciiEqualFold(cmdPart, "PRAGMA") ||
util.AsciiEqualFold(cmdPart, "ALTER") ||
util.AsciiEqualFold(cmdPart, "CREATE") ||
util.AsciiEqualFold(cmdPart, "DROP") ||
util.AsciiEqualFold(cmdPart, "IF") ||
util.AsciiEqualFold(cmdPart, "SET") ||
util.AsciiEqualFold(cmdPart, "sp_rename") ||
util.AsciiEqualFold(cmdPart, "BEGIN") ||
util.AsciiEqualFold(cmdPart, "ROLLBACK") ||
util.AsciiEqualFold(cmdPart, "COMMIT") {
return ctx, nil
}
switch {
case util.AsciiEqualFold(cmdPart, "INSERT"):
cmdPart, cmdRemaining, _ = cutSpaceForSQL(cmdRemaining)
if util.AsciiEqualFold(cmdPart, "INTO") {
cmdPart, cmdRemaining, _ = cutSpaceForSQL(cmdRemaining)
}
fixturesLoader.MarkTableChanged(trimTableNameQuotes(cmdPart))
case util.AsciiEqualFold(cmdPart, "MERGE"):
cmdPart, cmdRemaining, _ = cutSpaceForSQL(cmdRemaining)
if util.AsciiEqualFold(cmdPart, "INTO") {
cmdPart, cmdRemaining, _ = cutSpaceForSQL(cmdRemaining)
}
fixturesLoader.MarkTableChanged(trimTableNameQuotes(cmdPart))
case util.AsciiEqualFold(cmdPart, "UPDATE"):
cmdPart, cmdRemaining, _ = cutSpaceForSQL(cmdRemaining)
fixturesLoader.MarkTableChanged(trimTableNameQuotes(cmdPart))
case util.AsciiEqualFold(cmdPart, "DELETE"):
cmdPart, cmdRemaining, _ = cutSpaceForSQL(cmdRemaining)
if util.AsciiEqualFold(cmdPart, "FROM") {
cmdPart, cmdRemaining, _ = cutSpaceForSQL(cmdRemaining)
}
fixturesLoader.MarkTableChanged(trimTableNameQuotes(cmdPart))
case util.AsciiEqualFold(cmdPart, "TRUNCATE"):
cmdPart, cmdRemaining, _ = cutSpaceForSQL(cmdRemaining)
if util.AsciiEqualFold(cmdPart, "TABLE") {
cmdPart, cmdRemaining, _ = cutSpaceForSQL(cmdRemaining)
}
fixturesLoader.MarkTableChanged(trimTableNameQuotes(cmdPart))
default:
// should either parse the table name if it changes data, or ignore it
panic("unrecognized sql: " + sql)
}
_ = cmdRemaining
return ctx, nil
}
func (f fixturesHookStruct) AfterProcess(c *contexts.ContextHook) error {
return nil
}
// InitFixtures initialize test fixtures for a test database // InitFixtures initialize test fixtures for a test database
func InitFixtures(opts FixturesOptions, engine ...*xorm.Engine) (err error) { func InitFixtures(opts FixturesOptions) (err error) {
xormEngine := util.IfZero(util.OptionalArg(engine), GetXORMEngine()) xormEngine := GetXORMEngine()
fixturesLoader, err = NewFixturesLoader(xormEngine, opts) fixturesLoader, err = NewFixturesLoader(xormEngine, opts)
// fixturesLoader = NewFixturesLoaderVendor(xormEngine, opts) // fixturesLoader = NewFixturesLoaderVendor(xormEngine, opts)
// register the dummy hash algorithm function used in the test fixtures // register the dummy hash algorithm function used in the test fixtures
_ = hash.Register("dummy", hash.NewDummyHasher) _ = hash.Register("dummy", hash.NewDummyHasher)
setting.PasswordHashAlgo, _ = hash.SetDefaultPasswordHashAlgorithm("dummy") setting.PasswordHashAlgo, _ = hash.SetDefaultPasswordHashAlgorithm("dummy")
xormEngine.AddHook(&fixturesHookStruct{})
return err return err
} }

View File

@ -4,6 +4,7 @@
package unittest package unittest
import ( import (
"context"
"database/sql" "database/sql"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
@ -11,6 +12,7 @@ import (
"path/filepath" "path/filepath"
"slices" "slices"
"strings" "strings"
"sync"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
@ -32,7 +34,7 @@ type FixtureItem struct {
type fixturesLoaderInternal struct { type fixturesLoaderInternal struct {
xormEngine *xorm.Engine xormEngine *xorm.Engine
xormTableNames map[string]bool tableSyncMap sync.Map
db *sql.DB db *sql.DB
dbType schemas.DBType dbType schemas.DBType
fixtures map[string]*FixtureItem fixtures map[string]*FixtureItem
@ -148,25 +150,36 @@ func (f *fixturesLoaderInternal) Load() error {
} }
defer func() { _ = tx.Rollback() }() defer func() { _ = tx.Rollback() }()
ctx := context.WithValue(context.Background(), db.ContextKeyTestFixtures, true)
for _, fixture := range f.fixtures { for _, fixture := range f.fixtures {
if !f.xormTableNames[fixture.tableName] { synced, existing := f.tableSyncMap.Load(fixture.tableName)
if synced == true || !existing {
continue continue
} }
if err := f.loadFixtures(tx, fixture); err != nil { if err := f.loadFixtures(tx, fixture); err != nil {
return fmt.Errorf("failed to load fixtures from %s: %w", fixture.fileFullPath, err) return fmt.Errorf("failed to load fixtures from %s: %w", fixture.fileFullPath, err)
} }
f.tableSyncMap.Store(fixture.tableName, true)
} }
if err = tx.Commit(); err != nil { if err = tx.Commit(); err != nil {
return err return err
} }
for xormTableName := range f.xormTableNames { f.tableSyncMap.Range(func(k, v any) bool {
if f.fixtures[xormTableName] == nil { tableName, synced := k.(string), v.(bool)
_, _ = f.xormEngine.Exec("DELETE FROM `" + xormTableName + "`") if !synced && f.fixtures[tableName] == nil {
_, _ = f.xormEngine.Context(ctx).Exec("DELETE FROM `" + tableName + "`")
} }
} f.tableSyncMap.Store(tableName, true)
return true
})
return nil return nil
} }
func (f *fixturesLoaderInternal) MarkTableChanged(tableName string) {
f.tableSyncMap.Store(tableName, false)
}
func FixturesFileFullPaths(dir string, files []string) (map[string]*FixtureItem, error) { func FixturesFileFullPaths(dir string, files []string) (map[string]*FixtureItem, error) {
if files != nil && len(files) == 0 { if files != nil && len(files) == 0 {
return nil, nil //nolint:nilnil // load nothing return nil, nil //nolint:nilnil // load nothing
@ -215,11 +228,12 @@ func NewFixturesLoader(x *xorm.Engine, opts FixturesOptions) (FixturesLoader, er
f.paramPlaceholder = func(idx int) string { return "?" } f.paramPlaceholder = func(idx int) string { return "?" }
} }
// If a model is not imported in a package (no bean is registered), the table won't exist in database.
// So only use tables of registered models (beans).
xormBeans, _ := db.NamesToBean() xormBeans, _ := db.NamesToBean()
f.xormTableNames = map[string]bool{}
for _, bean := range xormBeans { for _, bean := range xormBeans {
f.xormTableNames[x.TableName(bean)] = true beanTableName := x.TableName(bean)
f.tableSyncMap.Store(trimTableNameQuotes(beanTableName), false)
} }
return f, nil return f, nil
} }

View File

@ -9,7 +9,7 @@ import (
) )
func fieldByName(v reflect.Value, field string) reflect.Value { func fieldByName(v reflect.Value, field string) reflect.Value {
if v.Kind() == reflect.Ptr { if v.Kind() == reflect.Pointer {
v = v.Elem() v = v.Elem()
} }
f := v.FieldByName(field) f := v.FieldByName(field)

View File

@ -91,7 +91,7 @@ func (e *MarshalEncoder) marshal(v any) error {
val := reflect.ValueOf(v) val := reflect.ValueOf(v)
typ := reflect.TypeOf(v) typ := reflect.TypeOf(v)
if typ.Kind() == reflect.Ptr { if typ.Kind() == reflect.Pointer {
val = val.Elem() val = val.Elem()
typ = typ.Elem() typ = typ.Elem()
} }

View File

@ -41,7 +41,8 @@ var (
AutoMigration bool AutoMigration bool
SlowQueryThreshold time.Duration SlowQueryThreshold time.Duration
}{ }{
IterateBufferSize: 50, IterateBufferSize: 50,
SlowQueryThreshold: 5 * time.Second,
} }
) )
@ -86,7 +87,7 @@ func loadDBSetting(rootCfg ConfigProvider) {
Database.DBConnectRetries = sec.Key("DB_RETRIES").MustInt(10) Database.DBConnectRetries = sec.Key("DB_RETRIES").MustInt(10)
Database.DBConnectBackoff = sec.Key("DB_RETRY_BACKOFF").MustDuration(3 * time.Second) Database.DBConnectBackoff = sec.Key("DB_RETRY_BACKOFF").MustDuration(3 * time.Second)
Database.AutoMigration = sec.Key("AUTO_MIGRATION").MustBool(true) Database.AutoMigration = sec.Key("AUTO_MIGRATION").MustBool(true)
Database.SlowQueryThreshold = sec.Key("SLOW_QUERY_THRESHOLD").MustDuration(5 * time.Second) Database.SlowQueryThreshold = sec.Key("SLOW_QUERY_THRESHOLD").MustDuration(Database.SlowQueryThreshold)
} }
// DatabaseType FIXME: it is also used directly with "schemas.DBType", so the names must be consistent // DatabaseType FIXME: it is also used directly with "schemas.DBType", so the names must be consistent

View File

@ -9,6 +9,7 @@ import (
"net" "net"
"net/http" "net/http"
"reflect" "reflect"
"slices"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/web/routing" "code.gitea.io/gitea/modules/web/routing"
@ -131,8 +132,8 @@ type middlewareProvider = func(next http.Handler) http.Handler
func executeMiddlewaresHandler(w http.ResponseWriter, r *http.Request, middlewares []middlewareProvider, endpoint http.HandlerFunc) { func executeMiddlewaresHandler(w http.ResponseWriter, r *http.Request, middlewares []middlewareProvider, endpoint http.HandlerFunc) {
handler := endpoint handler := endpoint
for i := len(middlewares) - 1; i >= 0; i-- { for _, middleware := range slices.Backward(middlewares) {
handler = middlewares[i](handler).ServeHTTP handler = middleware(handler).ServeHTTP
} }
handler(w, r) handler(w, r)
} }

View File

@ -29,7 +29,7 @@ func AssignForm(form any, data map[string]any) {
typ := reflect.TypeOf(form) typ := reflect.TypeOf(form)
val := reflect.ValueOf(form) val := reflect.ValueOf(form)
for typ.Kind() == reflect.Ptr { for typ.Kind() == reflect.Pointer {
typ = typ.Elem() typ = typ.Elem()
val = val.Elem() val = val.Elem()
} }
@ -104,7 +104,7 @@ func Validate(errs binding.Errors, data map[string]any, f Form, l translation.Lo
data["ErrorMsg"] = l.TrString("form.unknown_error") data["ErrorMsg"] = l.TrString("form.unknown_error")
typ := reflect.TypeOf(f) typ := reflect.TypeOf(f)
if typ.Kind() == reflect.Ptr { if typ.Kind() == reflect.Pointer {
typ = typ.Elem() typ = typ.Elem()
} }

View File

@ -1,9 +1,9 @@
{ {
"type": "module", "type": "module",
"packageManager": "pnpm@10.33.2", "packageManager": "pnpm@11.0.8",
"engines": { "engines": {
"node": ">= 22.18.0", "node": ">= 22.18.0",
"pnpm": ">= 10.0.0" "pnpm": ">= 11.0.0"
}, },
"dependencies": { "dependencies": {
"@citation-js/core": "0.7.21", "@citation-js/core": "0.7.21",
@ -124,34 +124,5 @@
"updates": "17.16.8", "updates": "17.16.8",
"vitest": "4.1.5", "vitest": "4.1.5",
"vue-tsc": "3.2.8" "vue-tsc": "3.2.8"
},
"pnpm": {
"peerDependencyRules": {
"allowedVersions": {
"eslint-plugin-github>eslint": ">=9"
}
},
"overrides": {
"array-includes": "npm:@nolyfill/array-includes@^1",
"array.prototype.findlastindex": "npm:@nolyfill/array.prototype.findlastindex@^1",
"array.prototype.flat": "npm:@nolyfill/array.prototype.flat@^1",
"array.prototype.flatmap": "npm:@nolyfill/array.prototype.flatmap@^1",
"es-aggregate-error": "npm:@nolyfill/es-aggregate-error@^1",
"hasown": "npm:@nolyfill/hasown@^1",
"is-core-module": "npm:@nolyfill/is-core-module@^1",
"object.assign": "npm:@nolyfill/object.assign@^1",
"object.fromentries": "npm:@nolyfill/object.fromentries@^1",
"object.groupby": "npm:@nolyfill/object.groupby@^1",
"object.values": "npm:@nolyfill/object.values@^1",
"safe-buffer": "npm:@nolyfill/safe-buffer@^1",
"safe-regex-test": "npm:@nolyfill/safe-regex-test@^1",
"safer-buffer": "npm:@nolyfill/safer-buffer@^1",
"string.prototype.includes": "npm:@nolyfill/string.prototype.includes@^1",
"string.prototype.trimend": "npm:@nolyfill/string.prototype.trimend@^1",
"object-keys": "npm:@nolyfill/object-keys@^1",
"object.entries": "npm:@nolyfill/object.entries@^1",
"abab": "npm:@nolyfill/abab@^1",
"es-set-tostringtag": "npm:@nolyfill/es-set-tostringtag@^1"
}
} }
} }

32
pnpm-workspace.yaml Normal file
View File

@ -0,0 +1,32 @@
packages: [.] # workaround for https://github.com/SukkaW/nolyfill/issues/119
savePrefix: ''
dedupePeerDependents: false
updateNotifier: false
strictDepBuilds: false
minimumReleaseAge: 0
peerDependencyRules:
allowedVersions:
eslint-plugin-github>eslint: '>=9'
overrides:
array-includes: npm:@nolyfill/array-includes@^1
array.prototype.findlastindex: npm:@nolyfill/array.prototype.findlastindex@^1
array.prototype.flat: npm:@nolyfill/array.prototype.flat@^1
array.prototype.flatmap: npm:@nolyfill/array.prototype.flatmap@^1
es-aggregate-error: npm:@nolyfill/es-aggregate-error@^1
hasown: npm:@nolyfill/hasown@^1
is-core-module: npm:@nolyfill/is-core-module@^1
object.assign: npm:@nolyfill/object.assign@^1
object.fromentries: npm:@nolyfill/object.fromentries@^1
object.groupby: npm:@nolyfill/object.groupby@^1
object.values: npm:@nolyfill/object.values@^1
safe-buffer: npm:@nolyfill/safe-buffer@^1
safe-regex-test: npm:@nolyfill/safe-regex-test@^1
safer-buffer: npm:@nolyfill/safer-buffer@^1
string.prototype.includes: npm:@nolyfill/string.prototype.includes@^1
string.prototype.trimend: npm:@nolyfill/string.prototype.trimend@^1
object-keys: npm:@nolyfill/object-keys@^1
object.entries: npm:@nolyfill/object.entries@^1
abab: npm:@nolyfill/abab@^1
es-set-tostringtag: npm:@nolyfill/es-set-tostringtag@^1

View File

@ -2,7 +2,7 @@
"$schema": "https://docs.renovatebot.com/renovate-schema.json", "$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["config:recommended", "helpers:pinGitHubActionDigests", "customManagers:githubActionsVersions"], "extends": ["config:recommended", "helpers:pinGitHubActionDigests", "customManagers:githubActionsVersions"],
"configMigration": true, "configMigration": true,
"enabledManagers": ["github-actions", "gomod", "npm", "pep621", "nix"], "enabledManagers": ["github-actions", "gomod", "npm", "pep621", "nix", "custom.regex"],
"labels": ["dependencies"], "labels": ["dependencies"],
"branchPrefix": "renovate/", "branchPrefix": "renovate/",
"schedule": ["* * * * 1"], // dependency update PRs weekly, vulnerabilityAlerts bypasses this "schedule": ["* * * * 1"], // dependency update PRs weekly, vulnerabilityAlerts bypasses this
@ -60,19 +60,32 @@
}, },
{ {
"groupName": "go dependencies", "groupName": "go dependencies",
"matchDatasources": ["go"], // covers gomod manager + Makefile go-tool customManager "matchManagers": ["gomod"],
"postUpgradeTasks": { "postUpgradeTasks": {
"commands": ["make tidy"], "commands": ["make tidy"],
"fileFilters": ["go.mod", "go.sum", "assets/go-licenses.json"], "fileFilters": ["go.mod", "go.sum", "assets/go-licenses.json"],
"executionMode": "branch", "executionMode": "branch",
}, },
}, },
{
"groupName": "tool dependencies",
"matchManagers": ["custom.regex"],
"matchFileNames": ["**/Makefile"],
},
{
"matchManagers": ["gomod"],
"matchDepNames": ["go"],
"matchDepTypes": ["golang"],
"rangeStrategy": "bump",
"schedule": ["at any time"],
"minimumReleaseAge": "0",
},
{ {
"groupName": "npm dependencies", "groupName": "npm dependencies",
"matchManagers": ["npm"], "matchManagers": ["npm"],
"postUpgradeTasks": { "postUpgradeTasks": {
"commands": ["make svg nolyfill"], "commands": ["make svg nolyfill"],
"fileFilters": ["package.json", "pnpm-lock.yaml", "public/assets/img/svg/**"], "fileFilters": ["package.json", "pnpm-lock.yaml", "pnpm-workspace.yaml", "public/assets/img/svg/**"],
"executionMode": "branch", "executionMode": "branch",
}, },
}, },

View File

@ -57,14 +57,14 @@ func RequireUnitReader(unitTypes ...unit.Type) func(ctx *Context) {
} }
} }
// CheckRepoScopedToken check whether personal access token has repo scope // CheckRepoScopedToken checks whether the authenticated API token has repo scope.
func CheckRepoScopedToken(ctx *Context, repo *repo_model.Repository, level auth_model.AccessTokenScopeLevel) { func CheckRepoScopedToken(ctx *Context, repo *repo_model.Repository, level auth_model.AccessTokenScopeLevel) {
if !ctx.IsBasicAuth || ctx.Data["IsApiToken"] != true { if ctx.Data["IsApiToken"] != true {
return return
} }
scope, ok := ctx.Data["ApiTokenScope"].(auth_model.AccessTokenScope) scope, ok := ctx.Data["ApiTokenScope"].(auth_model.AccessTokenScope)
if ok { // it's a personal access token but not oauth2 token if ok {
var scopeMatched bool var scopeMatched bool
requiredScopes := auth_model.GetRequiredScopes(level, auth_model.AccessTokenScopeCategoryRepository) requiredScopes := auth_model.GetRequiredScopes(level, auth_model.AccessTokenScopeCategoryRepository)
@ -76,7 +76,7 @@ func CheckRepoScopedToken(ctx *Context, repo *repo_model.Repository, level auth_
return return
} }
if publicOnly && repo.IsPrivate { if publicOnly && repo != nil && repo.IsPrivate {
ctx.HTTPError(http.StatusForbidden) ctx.HTTPError(http.StatusForbidden)
return return
} }

View File

@ -9,6 +9,7 @@ import (
"testing" "testing"
actions_model "code.gitea.io/gitea/models/actions" actions_model "code.gitea.io/gitea/models/actions"
db "code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
@ -124,3 +125,55 @@ func TestToActionWorkflowRun_UsesTriggerEvent(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, "schedule", apiRun.Event) assert.Equal(t, "schedule", apiRun.Event)
} }
func TestToActionWorkflowJob_StepStatusIsIndependentOfJobStatus(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
ctx := t.Context()
run := &actions_model.ActionRun{
ID: 9001,
RepoID: 2,
TriggerUserID: 1,
WorkflowID: "test.yaml",
Index: 12345,
Ref: "refs/heads/main",
Status: actions_model.StatusFailure,
}
require.NoError(t, db.Insert(ctx, run))
task := &actions_model.ActionTask{
ID: 900102,
JobID: 9001,
RepoID: 2,
Status: actions_model.StatusFailure,
}
require.NoError(t, db.Insert(ctx, task))
job := &actions_model.ActionRunJob{
ID: 90010203,
RunID: 9001,
TaskID: 900102,
RepoID: 2,
Name: "test-job-name",
Attempt: 1,
JobID: "test-job-id",
Status: actions_model.StatusFailure,
}
require.NoError(t, db.Insert(ctx, job))
require.NoError(t, db.Insert(ctx,
&actions_model.ActionTaskStep{TaskID: task.ID, RepoID: 2, Index: 0, Name: "step-success", Status: actions_model.StatusSuccess},
&actions_model.ActionTaskStep{TaskID: task.ID, RepoID: 2, Index: 1, Name: "step-failure", Status: actions_model.StatusFailure},
))
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
apiJob, err := ToActionWorkflowJob(ctx, repo, task, job)
require.NoError(t, err)
require.Len(t, apiJob.Steps, 2)
assert.Equal(t, "completed", apiJob.Steps[0].Status, "step 0 status")
assert.Equal(t, "success", apiJob.Steps[0].Conclusion, "step 0 conclusion (succeeded before the failure)")
assert.Equal(t, "completed", apiJob.Steps[1].Status, "step 1 status")
assert.Equal(t, "failure", apiJob.Steps[1].Conclusion, "step 1 conclusion")
}

View File

@ -314,33 +314,31 @@ func ToActionWorkflowRun(ctx context.Context, run *actions_model.ActionRun, atte
}, nil }, nil
} }
func ToWorkflowRunAction(status actions_model.Status) string { func ToWorkflowRunAction(status actions_model.Status) (action string) {
var action string
switch status { switch status {
case actions_model.StatusWaiting, actions_model.StatusBlocked: case actions_model.StatusWaiting, actions_model.StatusBlocked:
action = "requested" action = "requested"
case actions_model.StatusRunning: case actions_model.StatusRunning:
action = "in_progress" action = "in_progress"
} default:
if status.IsDone() { if status.IsDone() {
action = "completed" action = "completed"
} else {
setting.PanicInDevOrTesting("unknown action status: %v", status)
}
} }
return action return action
} }
func ToActionsStatus(status actions_model.Status) (string, string) { func ToActionsStatus(status actions_model.Status) (action, conclusion string) {
var action string
var conclusion string
switch status { switch status {
// This is a naming conflict of the webhook between Gitea and GitHub Actions
case actions_model.StatusWaiting: case actions_model.StatusWaiting:
action = "queued" action = "queued" // "waiting" is a naming conflict of the webhook between Gitea and GitHub Actions
case actions_model.StatusBlocked: case actions_model.StatusBlocked:
action = "waiting" action = "waiting" // naming conflict (as above)
case actions_model.StatusRunning: case actions_model.StatusRunning:
action = "in_progress" action = "in_progress"
} default:
if status.IsDone() {
action = "completed" action = "completed"
switch status { switch status {
case actions_model.StatusSuccess: case actions_model.StatusSuccess:
@ -351,6 +349,8 @@ func ToActionsStatus(status actions_model.Status) (string, string) {
conclusion = "failure" conclusion = "failure"
case actions_model.StatusSkipped: case actions_model.StatusSkipped:
conclusion = "skipped" conclusion = "skipped"
default:
setting.PanicInDevOrTesting("unknown action status: %v", status)
} }
} }
return action, conclusion return action, conclusion
@ -390,7 +390,7 @@ func ToActionWorkflowJob(ctx context.Context, repo *repo_model.Repository, task
runnerName = runner.Name runnerName = runner.Name
} }
for i, step := range task.Steps { for i, step := range task.Steps {
stepStatus, stepConclusion := ToActionsStatus(job.Status) stepStatus, stepConclusion := ToActionsStatus(step.Status)
steps = append(steps, &api.ActionWorkflowStep{ steps = append(steps, &api.ActionWorkflowStep{
Name: step.Name, Name: step.Name,
Number: int64(i), Number: int64(i),

View File

@ -57,7 +57,7 @@ func (t *Task) IsEnabled() bool {
// GetConfig will return a copy of the task's config // GetConfig will return a copy of the task's config
func (t *Task) GetConfig() Config { func (t *Task) GetConfig() Config {
if reflect.TypeOf(t.config).Kind() == reflect.Ptr { if reflect.TypeOf(t.config).Kind() == reflect.Pointer {
// Pointer: // Pointer:
return reflect.New(reflect.ValueOf(t.config).Elem().Type()).Interface().(Config) return reflect.New(reflect.ValueOf(t.config).Elem().Type()).Interface().(Config)
} }

View File

@ -6,6 +6,7 @@ package gitdiff
import ( import (
"bytes" "bytes"
"html/template" "html/template"
"slices"
"strings" "strings"
"unicode/utf8" "unicode/utf8"
@ -385,8 +386,7 @@ func (hcd *highlightCodeDiff) recoverOneDiff(str string) template.HTML {
} }
// close all opening tags // close all opening tags
for i := len(tagStack) - 1; i >= 0; i-- { for _, tagToClose := range slices.Backward(tagStack) {
tagToClose := tagStack[i]
// get the closing tag "</span>" from "<span class=...>" or "<span>" // get the closing tag "</span>" from "<span class=...>" or "<span>"
pos := strings.IndexAny(tagToClose, " >") pos := strings.IndexAny(tagToClose, " >")
// pos must be positive, because the tags were pushed by us // pos must be positive, because the tags were pushed by us

View File

@ -10,6 +10,7 @@ import (
"html" "html"
"net/url" "net/url"
"regexp" "regexp"
"slices"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@ -123,9 +124,7 @@ func getIssueFromRef(ctx context.Context, repo *repo_model.Repository, index int
// UpdateIssuesCommit checks if issues are manipulated by commit message. // UpdateIssuesCommit checks if issues are manipulated by commit message.
func UpdateIssuesCommit(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, commits []*repository.PushCommit, branchName string) error { func UpdateIssuesCommit(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, commits []*repository.PushCommit, branchName string) error {
// Commits are appended in the reverse order. // Commits are appended in the reverse order.
for i := len(commits) - 1; i >= 0; i-- { for _, c := range slices.Backward(commits) {
c := commits[i]
type markKey struct { type markKey struct {
ID int64 ID int64
Action references.XRefAction Action references.XRefAction

View File

@ -9,6 +9,7 @@ import (
"fmt" "fmt"
"io" "io"
"regexp" "regexp"
"slices"
"strings" "strings"
"time" "time"
"unicode/utf8" "unicode/utf8"
@ -845,8 +846,7 @@ func GetSquashMergeCommitMessages(ctx context.Context, pr *issues_model.PullRequ
// use PR's commit messages as squash commit message // use PR's commit messages as squash commit message
// commits list is in reverse chronological order // commits list is in reverse chronological order
maxMsgSize := setting.Repository.PullRequest.DefaultMergeMessageSize maxMsgSize := setting.Repository.PullRequest.DefaultMergeMessageSize
for i := len(commits) - 1; i >= 0; i-- { for _, commit := range slices.Backward(commits) {
commit := commits[i]
msg := strings.TrimSpace(commit.MessageUTF8()) msg := strings.TrimSpace(commit.MessageUTF8())
if msg == "" { if msg == "" {
continue continue

View File

@ -6,6 +6,7 @@ package gitgraph
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"slices"
) )
// Parser represents a git graph parser. It is stateful containing the previous // Parser represents a git graph parser. It is stateful containing the previous
@ -163,8 +164,7 @@ func (parser *Parser) ParseGlyphs(glyphs []byte) {
// release unused colors // release unused colors
parser.releaseUnusedColors() parser.releaseUnusedColors()
for i := len(glyphs) - 1; i >= 0; i-- { for i, glyph := range slices.Backward(glyphs) {
glyph := glyphs[i]
switch glyph { switch glyph {
case '|': case '|':
fallthrough fallthrough

View File

@ -1,6 +1,5 @@
// @ts-check
// TODO: Move to .ts after https://github.com/stylelint/stylelint/issues/8893 is fixed
import {fileURLToPath} from 'node:url'; import {fileURLToPath} from 'node:url';
import type {Config} from 'stylelint';
const cssVarFiles = [ const cssVarFiles = [
fileURLToPath(new URL('web_src/css/base.css', import.meta.url)), fileURLToPath(new URL('web_src/css/base.css', import.meta.url)),
@ -8,7 +7,6 @@ const cssVarFiles = [
fileURLToPath(new URL('web_src/css/themes/theme-gitea-dark.css', import.meta.url)), fileURLToPath(new URL('web_src/css/themes/theme-gitea-dark.css', import.meta.url)),
]; ];
/** @type {import('stylelint').Config} */
export default { export default {
extends: 'stylelint-config-recommended', extends: 'stylelint-config-recommended',
reportUnscopedDisables: true, reportUnscopedDisables: true,
@ -25,18 +23,6 @@ export default {
'/web_src/fomantic', '/web_src/fomantic',
], ],
overrides: [ overrides: [
{
files: ['**/chroma/*', '**/codemirror/*', '**/console.css', 'font_i18n.css'],
rules: {
'scale-unlimited/declaration-strict-value': null,
},
},
{
files: ['**/chroma/*', '**/codemirror/*'],
rules: {
'block-no-empty': null,
},
},
{ {
files: ['**/*.vue'], files: ['**/*.vue'],
customSyntax: 'postcss-html', customSyntax: 'postcss-html',
@ -139,7 +125,7 @@ export default {
'no-unknown-custom-media': null, // disabled until stylelint supports multi-file linting 'no-unknown-custom-media': null, // disabled until stylelint supports multi-file linting
'no-unknown-custom-properties': null, // disabled until stylelint supports multi-file linting 'no-unknown-custom-properties': null, // disabled until stylelint supports multi-file linting
'plugin/declaration-block-no-ignored-properties': true, 'plugin/declaration-block-no-ignored-properties': true,
'scale-unlimited/declaration-strict-value': [['/color$/', 'font-weight'], {ignoreValues: '/^(inherit|transparent|unset|initial|currentcolor|none)$/', ignoreFunctions: true, disableFix: true, expandShorthand: true}], 'scale-unlimited/declaration-strict-value': [['/color$/', 'fill', 'stroke', 'font-weight'], {ignoreValues: '/^(inherit|transparent|unset|initial|currentcolor|none)$/', ignoreFunctions: true, disableFix: true, expandShorthand: true}],
'selector-attribute-quotes': 'always', 'selector-attribute-quotes': 'always',
'selector-no-vendor-prefix': true, 'selector-no-vendor-prefix': true,
'selector-pseudo-element-colon-notation': 'double', 'selector-pseudo-element-colon-notation': 'double',
@ -148,4 +134,4 @@ export default {
'shorthand-property-no-redundant-values': true, 'shorthand-property-no-redundant-values': true,
'value-no-vendor-prefix': [true, {ignoreValues: ['box', 'inline-box']}], 'value-no-vendor-prefix': [true, {ignoreValues: ['box', 'inline-box']}],
}, },
}; } satisfies Config;

View File

@ -9,6 +9,9 @@ import (
"net/url" "net/url"
"testing" "testing"
auth_model "code.gitea.io/gitea/models/auth"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
@ -20,6 +23,7 @@ import (
func TestGitSmartHTTP(t *testing.T) { func TestGitSmartHTTP(t *testing.T) {
onGiteaRun(t, func(t *testing.T, u *url.URL) { onGiteaRun(t, func(t *testing.T, u *url.URL) {
testGitSmartHTTP(t, u) testGitSmartHTTP(t, u)
testGitSmartHTTPTokenScopes(t)
testRenamedRepoRedirect(t) testRenamedRepoRedirect(t)
testGitArchiveRemote(t, u) testGitArchiveRemote(t, u)
}) })
@ -80,6 +84,42 @@ func testGitSmartHTTP(t *testing.T, u *url.URL) {
} }
} }
func testGitSmartHTTPTokenScopes(t *testing.T) {
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2, OwnerName: "user2", Name: "repo2"})
require.True(t, repo.IsPrivate)
session := loginUser(t, "user2")
badToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadNotification)
readToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadRepository)
writeToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
publicOnlyToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopePublicOnly, auth_model.AccessTokenScopeReadRepository)
t.Run("upload-pack requires read repository scope", func(t *testing.T) {
path := "/user2/repo2/info/refs?service=git-upload-pack"
MakeRequest(t, NewRequest(t, "GET", path).AddBasicAuth(badToken, "x-oauth-basic"), http.StatusForbidden)
MakeRequest(t, NewRequest(t, "GET", path).AddTokenAuth(badToken), http.StatusForbidden)
resp := MakeRequest(t, NewRequest(t, "GET", path).AddTokenAuth(readToken), http.StatusOK)
assert.Contains(t, resp.Body.String(), "refs/heads/master")
})
t.Run("receive-pack requires write repository scope", func(t *testing.T) {
path := "/user2/repo2/info/refs?service=git-receive-pack"
MakeRequest(t, NewRequest(t, "GET", path).AddBasicAuth(readToken, "x-oauth-basic"), http.StatusForbidden)
MakeRequest(t, NewRequest(t, "GET", path).AddTokenAuth(readToken), http.StatusForbidden)
resp := MakeRequest(t, NewRequest(t, "GET", path).AddTokenAuth(writeToken), http.StatusOK)
assert.Contains(t, resp.Body.String(), "refs/heads/master")
})
t.Run("public-only scope rejects private repo", func(t *testing.T) {
path := "/user2/repo2/info/refs?service=git-upload-pack"
MakeRequest(t, NewRequest(t, "GET", path).AddTokenAuth(publicOnlyToken), http.StatusForbidden)
})
}
func testRenamedRepoRedirect(t *testing.T) { func testRenamedRepoRedirect(t *testing.T) {
defer test.MockVariableValue(&setting.Service.RequireSignInViewStrict, true)() defer test.MockVariableValue(&setting.Service.RequireSignInViewStrict, true)()

View File

@ -36,6 +36,7 @@ func InitIntegrationTest() error {
return err return err
} }
setting.Database.SlowQueryThreshold = 0
setting.LoadDBSetting() setting.LoadDBSetting()
cleanupDb, err := unittest.ResetTestDatabase() cleanupDb, err := unittest.ResetTestDatabase()
if err != nil { if err != nil {

View File

@ -1,7 +1,7 @@
#!/usr/bin/env node #!/usr/bin/env node
import {env, exit} from 'node:process'; import {env, exit} from 'node:process';
const allowedTypes = 'build, ci, docs, feat, fix, perf, refactor, revert, style, test'; const allowedTypes = 'build, chore, ci, docs, feat, fix, perf, refactor, revert, style, test';
const title = env.PR_TITLE; const title = env.PR_TITLE;
if (!title) { if (!title) {

View File

@ -0,0 +1,33 @@
#!/usr/bin/env node
// nolyfill writes overrides to package.json#pnpm.overrides which pnpm v11 ignores.
// This moves them to pnpm-workspace.yaml until SukkaW/nolyfill#119 is fixed.
import {readFileSync, writeFileSync} from 'node:fs';
import {exit} from 'node:process';
import {fileURLToPath} from 'node:url';
import {dump} from 'js-yaml';
const packagePath = fileURLToPath(new URL('../package.json', import.meta.url));
const workspacePath = fileURLToPath(new URL('../pnpm-workspace.yaml', import.meta.url));
const packageJson: {pnpm?: {overrides?: Record<string, string>}} = JSON.parse(readFileSync(packagePath, 'utf8'));
const overrides = packageJson.pnpm?.overrides;
if (!overrides || !Object.keys(overrides).length) {
exit(0);
}
const block = dump({overrides}, {lineWidth: -1, quotingType: "'"});
const workspace = readFileSync(workspacePath, 'utf8');
const overridesRegex = /^overrides:[^\n]*(?:\n(?:[ \t][^\n]*|[ \t]*(?=\n[ \t])))*\n?/m;
if (!overridesRegex.test(workspace)) {
console.error(`No 'overrides:' block found in pnpm-workspace.yaml`);
exit(1);
}
writeFileSync(workspacePath, workspace.replace(overridesRegex, block));
const pnpm = packageJson.pnpm!;
delete pnpm.overrides;
if (!Object.keys(pnpm).length) delete packageJson.pnpm;
writeFileSync(packagePath, `${JSON.stringify(packageJson, null, 2)}\n`);

View File

@ -1,4 +1,5 @@
/* Based on https://github.com/buildkite/terminal-to-html/blob/697ff23bd8dc48b9d23f11f259f5256dae2455f0/assets/terminal.css */ /* Based on https://github.com/buildkite/terminal-to-html/blob/697ff23bd8dc48b9d23f11f259f5256dae2455f0/assets/terminal.css */
/* stylelint-disable scale-unlimited/declaration-strict-value -- terminal ANSI palette uses literal hex values */
.console { .console {
background: var(--color-console-bg); background: var(--color-console-bg);

View File

@ -84,162 +84,82 @@
fill: var(--color-secondary-dark-5); fill: var(--color-secondary-dark-5);
} }
#git-graph-container:not(.monochrome) #rel-container .flow-group.flow-color-16-0 {
stroke: var(--color-series-16-0);
fill: var(--color-series-16-0);
}
#git-graph-container:not(.monochrome) #rel-container .flow-group.flow-color-16-1 { #git-graph-container:not(.monochrome) #rel-container .flow-group.flow-color-16-1 {
stroke: #499a37; stroke: var(--color-series-16-1);
fill: #499a37; fill: var(--color-series-16-1);
} }
#git-graph-container:not(.monochrome) #rel-container .flow-group.flow-color-16-2 { #git-graph-container:not(.monochrome) #rel-container .flow-group.flow-color-16-2 {
stroke: #ce4751; stroke: var(--color-series-16-2);
fill: #ce4751; fill: var(--color-series-16-2);
} }
#git-graph-container:not(.monochrome) #rel-container .flow-group.flow-color-16-3 { #git-graph-container:not(.monochrome) #rel-container .flow-group.flow-color-16-3 {
stroke: #8f9121; stroke: var(--color-series-16-3);
fill: #8f9121; fill: var(--color-series-16-3);
} }
#git-graph-container:not(.monochrome) #rel-container .flow-group.flow-color-16-4 { #git-graph-container:not(.monochrome) #rel-container .flow-group.flow-color-16-4 {
stroke: #ac32a6; stroke: var(--color-series-16-4);
fill: #ac32a6; fill: var(--color-series-16-4);
} }
#git-graph-container:not(.monochrome) #rel-container .flow-group.flow-color-16-5 { #git-graph-container:not(.monochrome) #rel-container .flow-group.flow-color-16-5 {
stroke: #7445e9; stroke: var(--color-series-16-5);
fill: #7445e9; fill: var(--color-series-16-5);
} }
#git-graph-container:not(.monochrome) #rel-container .flow-group.flow-color-16-6 { #git-graph-container:not(.monochrome) #rel-container .flow-group.flow-color-16-6 {
stroke: #c67d28; stroke: var(--color-series-16-6);
fill: #c67d28; fill: var(--color-series-16-6);
} }
#git-graph-container:not(.monochrome) #rel-container .flow-group.flow-color-16-7 { #git-graph-container:not(.monochrome) #rel-container .flow-group.flow-color-16-7 {
stroke: #4db392; stroke: var(--color-series-16-7);
fill: #4db392; fill: var(--color-series-16-7);
} }
#git-graph-container:not(.monochrome) #rel-container .flow-group.flow-color-16-8 { #git-graph-container:not(.monochrome) #rel-container .flow-group.flow-color-16-8 {
stroke: #aa4d30; stroke: var(--color-series-16-8);
fill: #aa4d30; fill: var(--color-series-16-8);
} }
#git-graph-container:not(.monochrome) #rel-container .flow-group.flow-color-16-9 { #git-graph-container:not(.monochrome) #rel-container .flow-group.flow-color-16-9 {
stroke: #2a6f84; stroke: var(--color-series-16-9);
fill: #2a6f84; fill: var(--color-series-16-9);
} }
#git-graph-container:not(.monochrome) #rel-container .flow-group.flow-color-16-10 { #git-graph-container:not(.monochrome) #rel-container .flow-group.flow-color-16-10 {
stroke: #c45327; stroke: var(--color-series-16-10);
fill: #c45327; fill: var(--color-series-16-10);
} }
#git-graph-container:not(.monochrome) #rel-container .flow-group.flow-color-16-11 { #git-graph-container:not(.monochrome) #rel-container .flow-group.flow-color-16-11 {
stroke: #3d965c; stroke: var(--color-series-16-11);
fill: #3d965c; fill: var(--color-series-16-11);
} }
#git-graph-container:not(.monochrome) #rel-container .flow-group.flow-color-16-12 { #git-graph-container:not(.monochrome) #rel-container .flow-group.flow-color-16-12 {
stroke: #792a93; stroke: var(--color-series-16-12);
fill: #792a93; fill: var(--color-series-16-12);
} }
#git-graph-container:not(.monochrome) #rel-container .flow-group.flow-color-16-13 { #git-graph-container:not(.monochrome) #rel-container .flow-group.flow-color-16-13 {
stroke: #439d73; stroke: var(--color-series-16-13);
fill: #439d73; fill: var(--color-series-16-13);
} }
#git-graph-container:not(.monochrome) #rel-container .flow-group.flow-color-16-14 { #git-graph-container:not(.monochrome) #rel-container .flow-group.flow-color-16-14 {
stroke: #103aad; stroke: var(--color-series-16-14);
fill: #103aad; fill: var(--color-series-16-14);
} }
#git-graph-container:not(.monochrome) #rel-container .flow-group.flow-color-16-15 { #git-graph-container:not(.monochrome) #rel-container .flow-group.flow-color-16-15 {
stroke: #982e85; stroke: var(--color-series-16-15);
fill: #982e85; fill: var(--color-series-16-15);
}
#git-graph-container:not(.monochrome) #rel-container .flow-group.flow-color-16-0 {
stroke: #7db233;
fill: #7db233;
}
#git-graph-container:not(.monochrome) #rel-container .flow-group.highlight.flow-color-16-1 {
stroke: #5ac144;
fill: #5ac144;
}
#git-graph-container:not(.monochrome) #rel-container .flow-group.highlight.flow-color-16-2 {
stroke: #ed5a8b;
fill: #ed5a8b;
}
#git-graph-container:not(.monochrome) #rel-container .flow-group.highlight.flow-color-16-3 {
stroke: #ced049;
fill: #ced048;
}
#git-graph-container:not(.monochrome) #rel-container .flow-group.highlight.flow-color-16-4 {
stroke: #db61d7;
fill: #db62d6;
}
#git-graph-container:not(.monochrome) #rel-container .flow-group.highlight.flow-color-16-5 {
stroke: #8455f9;
fill: #8455f9;
}
#git-graph-container:not(.monochrome) #rel-container .flow-group.highlight.flow-color-16-6 {
stroke: #e6a151;
fill: #e6a151;
}
#git-graph-container:not(.monochrome) #rel-container .flow-group.highlight.flow-color-16-7 {
stroke: #44daaa;
fill: #44daaa;
}
#git-graph-container:not(.monochrome) #rel-container .flow-group.highlight.flow-color-16-8 {
stroke: #dd7a5c;
fill: #dd7a5c;
}
#git-graph-container:not(.monochrome) #rel-container .flow-group.highlight.flow-color-16-9 {
stroke: #38859c;
fill: #38859c;
}
#git-graph-container:not(.monochrome) #rel-container .flow-group.highlight.flow-color-16-10 {
stroke: #d95520;
fill: #d95520;
}
#git-graph-container:not(.monochrome) #rel-container .flow-group.highlight.flow-color-16-11 {
stroke: #42ae68;
fill: #42ae68;
}
#git-graph-container:not(.monochrome) #rel-container .flow-group.highlight.flow-color-16-12 {
stroke: #9126b5;
fill: #9126b5;
}
#git-graph-container:not(.monochrome) #rel-container .flow-group.highlight.flow-color-16-13 {
stroke: #4ab080;
fill: #4ab080;
}
#git-graph-container:not(.monochrome) #rel-container .flow-group.highlight.flow-color-16-14 {
stroke: #284fb8;
fill: #284fb8;
}
#git-graph-container:not(.monochrome) #rel-container .flow-group.highlight.flow-color-16-15 {
stroke: #971c80;
fill: #971c80;
}
#git-graph-container:not(.monochrome) #rel-container .flow-group.highlight.flow-color-16-0 {
stroke: #87ca28;
fill: #87ca28;
} }

View File

@ -51,7 +51,7 @@
local("SourceHanSans-Light"), local("Yu Gothic Regular"), local("SourceHanSans-Light"), local("Yu Gothic Regular"),
local("YuGothic Regular"), local("Droid Sans Japanese"), local("Meiryo"), local("YuGothic Regular"), local("Droid Sans Japanese"), local("Meiryo"),
local("MS PGothic"); local("MS PGothic");
font-weight: 300; font-weight: 300; /* stylelint-disable-line scale-unlimited/declaration-strict-value */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@ -66,7 +66,7 @@
local("SourceHanSans-Regular"), local("Yu Gothic Medium"), local("SourceHanSans-Regular"), local("Yu Gothic Medium"),
local("YuGothic Medium"), local("Droid Sans Japanese"), local("Meiryo"), local("YuGothic Medium"), local("Droid Sans Japanese"), local("Meiryo"),
local("MS PGothic"); local("MS PGothic");
font-weight: 400; font-weight: 400; /* stylelint-disable-line scale-unlimited/declaration-strict-value */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@ -81,7 +81,7 @@
local("SourceHanSans-Medium"), local("Yu Gothic Medium"), local("SourceHanSans-Medium"), local("Yu Gothic Medium"),
local("YuGothic Medium"), local("Droid Sans Japanese"), local("Meiryo"), local("YuGothic Medium"), local("Droid Sans Japanese"), local("Meiryo"),
local("MS PGothic"); local("MS PGothic");
font-weight: 500; font-weight: 500; /* stylelint-disable-line scale-unlimited/declaration-strict-value */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@ -95,7 +95,7 @@
local("NotoSansCJKJP-Bold"), local("Source Han Sans Bold"), local("NotoSansCJKJP-Bold"), local("Source Han Sans Bold"),
local("SourceHanSans-Bold"), local("Yu Gothic Bold"), local("YuGothic Bold"), local("SourceHanSans-Bold"), local("Yu Gothic Bold"), local("YuGothic Bold"),
local("Droid Sans Japanese"), local("Meiryo Bold"), local("MS PGothic"); local("Droid Sans Japanese"), local("Meiryo Bold"), local("MS PGothic");
font-weight: 600; font-weight: 600; /* stylelint-disable-line scale-unlimited/declaration-strict-value */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@ -124,7 +124,7 @@
local("NotoSansCJKSC-Light"), local("HiraginoSansGB-W3"), local("NotoSansCJKSC-Light"), local("HiraginoSansGB-W3"),
local("Hiragino Sans GB W3"), local("Microsoft YaHei Light"), local("Hiragino Sans GB W3"), local("Microsoft YaHei Light"),
local("Heiti SC Light"), local("SimHei"); local("Heiti SC Light"), local("SimHei");
font-weight: 300; font-weight: 300; /* stylelint-disable-line scale-unlimited/declaration-strict-value */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@ -137,7 +137,7 @@
local("NotoSansCJKSC-Regular"), local("HiraginoSansGB-W3"), local("NotoSansCJKSC-Regular"), local("HiraginoSansGB-W3"),
local("Hiragino Sans GB W3"), local("Microsoft YaHei"), local("Hiragino Sans GB W3"), local("Microsoft YaHei"),
local("Heiti SC Light"), local("SimHei"); local("Heiti SC Light"), local("SimHei");
font-weight: 400; font-weight: 400; /* stylelint-disable-line scale-unlimited/declaration-strict-value */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@ -150,7 +150,7 @@
local("NotoSansCJKSC-Medium"), local("HiraginoSansGB-W3"), local("NotoSansCJKSC-Medium"), local("HiraginoSansGB-W3"),
local("Hiragino Sans GB W3"), local("Microsoft YaHei"), local("Hiragino Sans GB W3"), local("Microsoft YaHei"),
local("Heiti SC Light"), local("SimHei"); local("Heiti SC Light"), local("SimHei");
font-weight: 500; font-weight: 500; /* stylelint-disable-line scale-unlimited/declaration-strict-value */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@ -163,7 +163,7 @@
local("NotoSansCJKSC-Bold"), local("HiraginoSansGB-W6"), local("NotoSansCJKSC-Bold"), local("HiraginoSansGB-W6"),
local("Hiragino Sans GB W6"), local("Microsoft YaHei Bold"), local("Hiragino Sans GB W6"), local("Microsoft YaHei Bold"),
local("Heiti SC Medium"), local("SimHei"); local("Heiti SC Medium"), local("SimHei");
font-weight: 600; font-weight: 600; /* stylelint-disable-line scale-unlimited/declaration-strict-value */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@ -192,7 +192,7 @@
local("NotoSansCJKTC-Light"), local("HiraginoSansTC-W3"), local("NotoSansCJKTC-Light"), local("HiraginoSansTC-W3"),
local("Hiragino Sans TC W3"), local("Microsoft JhengHei Light"), local("Hiragino Sans TC W3"), local("Microsoft JhengHei Light"),
local("Heiti TC Light"), local("PMingLiU"); local("Heiti TC Light"), local("PMingLiU");
font-weight: 300; font-weight: 300; /* stylelint-disable-line scale-unlimited/declaration-strict-value */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@ -205,7 +205,7 @@
local("NotoSansCJKTC-Regular"), local("HiraginoSansTC-W3"), local("NotoSansCJKTC-Regular"), local("HiraginoSansTC-W3"),
local("Hiragino Sans TC W3"), local("Microsoft JhengHei"), local("Hiragino Sans TC W3"), local("Microsoft JhengHei"),
local("Heiti TC Light"), local("PMingLiU"); local("Heiti TC Light"), local("PMingLiU");
font-weight: 400; font-weight: 400; /* stylelint-disable-line scale-unlimited/declaration-strict-value */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@ -218,7 +218,7 @@
local("NotoSansCJKTC-Medium"), local("HiraginoSansTC-W3"), local("NotoSansCJKTC-Medium"), local("HiraginoSansTC-W3"),
local("Hiragino Sans TC W3"), local("Microsoft JhengHei"), local("Hiragino Sans TC W3"), local("Microsoft JhengHei"),
local("Heiti TC Light"), local("PMingLiU"); local("Heiti TC Light"), local("PMingLiU");
font-weight: 500; font-weight: 500; /* stylelint-disable-line scale-unlimited/declaration-strict-value */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@ -231,7 +231,7 @@
local("NotoSansCJKTC-Bold"), local("HiraginoSansTC-W6"), local("NotoSansCJKTC-Bold"), local("HiraginoSansTC-W6"),
local("Hiragino Sans TC W6"), local("Microsoft JhengHei Bold"), local("Hiragino Sans TC W6"), local("Microsoft JhengHei Bold"),
local("Heiti TC Medium"), local("PMingLiU"); local("Heiti TC Medium"), local("PMingLiU");
font-weight: 600; font-weight: 600; /* stylelint-disable-line scale-unlimited/declaration-strict-value */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@ -262,7 +262,7 @@
local("NotoSansCJKTC-Light"), local("HiraginoSansTC-W3"), local("NotoSansCJKTC-Light"), local("HiraginoSansTC-W3"),
local("Hiragino Sans TC W3"), local("Microsoft JhengHei Light"), local("Hiragino Sans TC W3"), local("Microsoft JhengHei Light"),
local("Heiti TC Light"), local("PMingLiU_HKSCS"), local("PMingLiU"); local("Heiti TC Light"), local("PMingLiU_HKSCS"), local("PMingLiU");
font-weight: 300; font-weight: 300; /* stylelint-disable-line scale-unlimited/declaration-strict-value */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@ -277,7 +277,7 @@
local("NotoSansCJKTC-Regular"), local("HiraginoSansTC-W3"), local("NotoSansCJKTC-Regular"), local("HiraginoSansTC-W3"),
local("Hiragino Sans TC W3"), local("Microsoft JhengHei"), local("Hiragino Sans TC W3"), local("Microsoft JhengHei"),
local("Heiti TC Light"), local("PMingLiU_HKSCS"), local("PMingLiU"); local("Heiti TC Light"), local("PMingLiU_HKSCS"), local("PMingLiU");
font-weight: 400; font-weight: 400; /* stylelint-disable-line scale-unlimited/declaration-strict-value */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@ -292,7 +292,7 @@
local("NotoSansCJKTC-Medium"), local("HiraginoSansTC-W3"), local("NotoSansCJKTC-Medium"), local("HiraginoSansTC-W3"),
local("Hiragino Sans TC W3"), local("Microsoft JhengHei"), local("Hiragino Sans TC W3"), local("Microsoft JhengHei"),
local("Heiti TC Light"), local("PMingLiU_HKSCS"), local("PMingLiU"); local("Heiti TC Light"), local("PMingLiU_HKSCS"), local("PMingLiU");
font-weight: 500; font-weight: 500; /* stylelint-disable-line scale-unlimited/declaration-strict-value */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@ -307,7 +307,7 @@
local("NotoSansCJKTC-Bold"), local("HiraginoSansTC-W6"), local("NotoSansCJKTC-Bold"), local("HiraginoSansTC-W6"),
local("Hiragino Sans TC W6"), local("Microsoft JhengHei Bold"), local("Hiragino Sans TC W6"), local("Microsoft JhengHei Bold"),
local("Heiti TC Medium"), local("PMingLiU_HKSCS"), local("PMingLiU"); local("Heiti TC Medium"), local("PMingLiU_HKSCS"), local("PMingLiU");
font-weight: 600; font-weight: 600; /* stylelint-disable-line scale-unlimited/declaration-strict-value */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@ -335,7 +335,7 @@
local("SourceHanSansK-Light"), local("Noto Sans CJK KR Light"), local("SourceHanSansK-Light"), local("Noto Sans CJK KR Light"),
local("NotoSansCJKKR-Light"), local("NanumBarunGothic Light"), local("NotoSansCJKKR-Light"), local("NanumBarunGothic Light"),
local("Malgun Gothic Semilight"), local("Nanum Gothic"), local("Dotum"); local("Malgun Gothic Semilight"), local("Nanum Gothic"), local("Dotum");
font-weight: 300; font-weight: 300; /* stylelint-disable-line scale-unlimited/declaration-strict-value */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@ -347,7 +347,7 @@
local("SourceHanSansK-Regular"), local("Noto Sans CJK KR Regular"), local("SourceHanSansK-Regular"), local("Noto Sans CJK KR Regular"),
local("NotoSansCJKKR-Regular"), local("NanumBarunGothic"), local("NotoSansCJKKR-Regular"), local("NanumBarunGothic"),
local("Malgun Gothic"), local("Nanum Gothic"), local("Dotum"); local("Malgun Gothic"), local("Nanum Gothic"), local("Dotum");
font-weight: 400; font-weight: 400; /* stylelint-disable-line scale-unlimited/declaration-strict-value */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@ -359,7 +359,7 @@
local("SourceHanSansK-Medium"), local("Noto Sans CJK KR Medium"), local("SourceHanSansK-Medium"), local("Noto Sans CJK KR Medium"),
local("NotoSansCJKKR-Medium"), local("NanumBarunGothic"), local("NotoSansCJKKR-Medium"), local("NanumBarunGothic"),
local("Malgun Gothic"), local("Nanum Gothic"), local("Dotum"); local("Malgun Gothic"), local("Nanum Gothic"), local("Dotum");
font-weight: 500; font-weight: 500; /* stylelint-disable-line scale-unlimited/declaration-strict-value */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }
@ -371,7 +371,7 @@
local("SourceHanSansK-Bold"), local("Noto Sans CJK KR Bold"), local("SourceHanSansK-Bold"), local("Noto Sans CJK KR Bold"),
local("NotoSansCJKKR-Bold"), local("NanumBarunGothic Bold"), local("NotoSansCJKKR-Bold"), local("NanumBarunGothic Bold"),
local("Malgun Gothic Bold"), local("Nanum Gothic Bold"), local("Dotum"); local("Malgun Gothic Bold"), local("Nanum Gothic Bold"), local("Dotum");
font-weight: 600; font-weight: 600; /* stylelint-disable-line scale-unlimited/declaration-strict-value */
unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, unicode-range: U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF,
U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????; U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????;
} }

View File

@ -141,6 +141,23 @@ gitea-theme-meta-info {
--color-ansi-bright-magenta: #d74397; --color-ansi-bright-magenta: #d74397;
--color-ansi-bright-cyan: #00b6ad; --color-ansi-bright-cyan: #00b6ad;
--color-ansi-bright-white: var(--color-console-fg); --color-ansi-bright-white: var(--color-console-fg);
/* 16-color series */
--color-series-16-0: #7db233;
--color-series-16-1: #499a37;
--color-series-16-2: #ce4751;
--color-series-16-3: #8f9121;
--color-series-16-4: #ac32a6;
--color-series-16-5: #7445e9;
--color-series-16-6: #c67d28;
--color-series-16-7: #4db392;
--color-series-16-8: #aa4d30;
--color-series-16-9: #2a6f84;
--color-series-16-10: #c45327;
--color-series-16-11: #3d965c;
--color-series-16-12: #792a93;
--color-series-16-13: #439d73;
--color-series-16-14: #103aad;
--color-series-16-15: #982e85;
/* other colors */ /* other colors */
--color-grey: #3d3f44; --color-grey: #3d3f44;
--color-grey-light: #898d96; --color-grey-light: #898d96;

View File

@ -141,6 +141,23 @@ gitea-theme-meta-info {
--color-ansi-bright-magenta: #d74397; --color-ansi-bright-magenta: #d74397;
--color-ansi-bright-cyan: #00b6ad; --color-ansi-bright-cyan: #00b6ad;
--color-ansi-bright-white: var(--color-console-fg); --color-ansi-bright-white: var(--color-console-fg);
/* 16-color series */
--color-series-16-0: #7db233;
--color-series-16-1: #499a37;
--color-series-16-2: #ce4751;
--color-series-16-3: #8f9121;
--color-series-16-4: #ac32a6;
--color-series-16-5: #7445e9;
--color-series-16-6: #c67d28;
--color-series-16-7: #4db392;
--color-series-16-8: #aa4d30;
--color-series-16-9: #2a6f84;
--color-series-16-10: #c45327;
--color-series-16-11: #3d965c;
--color-series-16-12: #792a93;
--color-series-16-13: #439d73;
--color-series-16-14: #103aad;
--color-series-16-15: #982e85;
/* other colors */ /* other colors */
--color-grey: #697077; --color-grey: #697077;
--color-grey-light: #7c838a; --color-grey-light: #7c838a;

View File

@ -16,5 +16,3 @@ window.config = {
}; };
window.testModules = {}; window.testModules = {};
export {}; // mark as module for top-level await